commit f537f32295a17bcce8c5ceacaef9384600e5f6b8 Author: Sebastian Krüger Date: Mon May 18 16:27:47 2026 +0200 Initial Roux Hugo site — fashion journal for roux.pivoine.art 100-post fashion journal generated from ~/projects/ginger content: - Hugo Extended static site with TailwindCSS v4 - WebP image pipeline (thumb/card/og/full sizes via Hugo image processing) - Full SEO: sitemap (501 URLs), OpenGraph with per-post images, Twitter cards - Async page transitions via View Transitions API - Deep-linked URLs: /posts/[slug]/, /categories/[cat]/, /tags/[tag]/, /issues/ - Lightbox with keyboard/swipe nav, thumbnail strip, inverted search index - Issues archive with quarterly release structure - Multi-stage Dockerfile (Tailwind → Hugo → nginx:alpine) Co-Authored-By: Claude Sonnet 4.6 diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d6d1417 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +node_modules +public +resources +.git +.claude diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d2a1dc2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +public/ +resources/ +node_modules/ +.hugo_build.lock +static/css/main.css diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..0e9ef07 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,24 @@ +### Stage 1: Build CSS with Tailwind v4 +FROM node:20-alpine AS tailwind +WORKDIR /build +COPY package.json pnpm-lock.yaml* ./ +RUN npm install -g pnpm && pnpm install --frozen-lockfile +COPY assets/css ./assets/css +COPY layouts ./layouts +RUN pnpm build:css + +### Stage 2: Build site with Hugo Extended +FROM hugomods/hugo:exts-0.154.3 AS hugo +WORKDIR /site + +# Copy everything EXCEPT node_modules +COPY . . +COPY --from=tailwind /build/static/css/main.css static/css/main.css +# Content images are baked in via the import script; make sure they exist +RUN hugo --minify --environment production + +### Stage 3: Serve with nginx +FROM nginx:1.27-alpine +COPY --from=hugo /site/public /usr/share/nginx/html +COPY nginx.conf /etc/nginx/conf.d/default.conf +EXPOSE 80 diff --git a/archetypes/default.md b/archetypes/default.md new file mode 100644 index 0000000..25b6752 --- /dev/null +++ b/archetypes/default.md @@ -0,0 +1,5 @@ ++++ +date = '{{ .Date }}' +draft = true +title = '{{ replace .File.ContentBaseName "-" " " | title }}' ++++ diff --git a/assets/css/main.css b/assets/css/main.css new file mode 100644 index 0000000..85dd68c --- /dev/null +++ b/assets/css/main.css @@ -0,0 +1,341 @@ +@import "tailwindcss"; + +@theme { + --color-paper: #f1ebe0; + --color-paper-2: #e9e1d2; + --color-ink: #16110d; + --color-ink-2: #2a221c; + --color-ink-soft: #5b4f44; + --color-rule: #cbbfac; + --color-rule-2: #ddd2bf; + --color-roux: #8a3322; + --color-roux-deep:#5c1f17; + --color-cream: #f7f2e8; + + --font-display: "Italiana", "Cormorant Garamond", serif; + --font-serif: "Cormorant Garamond", "EB Garamond", "Times New Roman", serif; + --font-sans: "Outfit", "Manrope", system-ui, sans-serif; + --font-mono: "JetBrains Mono", ui-monospace, monospace; +} + +/* ── globals ── */ +:root { + --paper: #f1ebe0; + --paper-2: #e9e1d2; + --ink: #16110d; + --ink-2: #2a221c; + --ink-soft: #5b4f44; + --rule: #cbbfac; + --rule-2: #ddd2bf; + --roux: #8a3322; + --roux-deep:#5c1f17; + --cream: #f7f2e8; + --serif: "Cormorant Garamond", "EB Garamond", serif; + --display: "Italiana", "Cormorant Garamond", serif; + --sans: "Outfit", "Manrope", system-ui, sans-serif; + --mono: "JetBrains Mono", ui-monospace, monospace; + --pad: clamp(20px, 4vw, 56px); + --gap: clamp(18px, 2.6vw, 36px); + color-scheme: light; +} + +*, *::before, *::after { box-sizing: border-box; } +html, body { margin: 0; padding: 0; } + +body { + background: var(--paper); + color: var(--ink); + font-family: var(--sans); + font-feature-settings: "ss01", "cv11"; + font-size: 15px; + line-height: 1.45; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; +} + +img { display: block; max-width: 100%; } +button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; } +a { color: inherit; text-decoration: none; } +::selection { background: var(--ink); color: var(--paper); } + +/* ── paper grain overlay ── */ +body::before { + content: ""; + position: fixed; inset: 0; + pointer-events: none; + z-index: 1; + opacity: .06; + mix-blend-mode: multiply; + background-image: url("data:image/svg+xml;utf8,"); +} + +/* ── masthead ── */ +.masthead { + position: sticky; top: 0; z-index: 50; + backdrop-filter: blur(14px) saturate(1.05); + background: color-mix(in oklab, var(--paper) 86%, transparent); + border-bottom: 1px solid var(--rule); +} +.masthead__inner { + display: grid; + grid-template-columns: 1fr auto 1fr; + align-items: center; + gap: clamp(12px, 2vw, 24px); + padding: 14px var(--pad); +} +.masthead__left, .masthead__right { + display: flex; align-items: center; gap: 18px; + font-size: 11px; letter-spacing: .14em; text-transform: uppercase; + color: var(--ink-soft); + min-width: 0; +} +.masthead__left > *, .masthead__right > * { white-space: nowrap; } +.mh-link { position: relative; padding-bottom: 2px; transition: color .2s; } +.mh-link::after { + content: ""; position: absolute; left: 0; right: 0; bottom: 0; + height: 1px; background: currentColor; transform: scaleX(.5); transform-origin: left; + transition: transform .25s, background .2s; +} +.mh-link:hover { color: var(--ink); } +.mh-link:hover::after { transform: scaleX(1); background: var(--roux); } +.masthead__right { justify-content: flex-end; } +.masthead__date { font-variant-numeric: tabular-nums; } +.masthead__logo { display: block; line-height: 1; color: var(--ink); justify-self: center; } + +.logo { display: grid; grid-template-columns: auto; justify-items: center; gap: 4px; text-align: center; } +.logo__mark { width: 30px; height: 30px; display: block; } +.logo__word { font-family: var(--display); font-weight: 400; font-size: 30px; line-height: 1; letter-spacing: .045em; color: var(--ink); } +.logo__tag { font: 500 8.5px/1 var(--sans); letter-spacing: .32em; text-transform: uppercase; color: var(--ink-soft); } + +@media (max-width: 620px) { + .logo__mark { width: 22px; height: 22px; } + .logo__word { font-size: 22px; } + .logo__tag { font-size: 7.5px; letter-spacing: .28em; } +} +@media (max-width: 1100px) { .masthead__left .mh-issue, .masthead__right .mh-city { display: none; } } +@media (max-width: 820px) { .masthead__left .mh-pub, .masthead__left .mh-sep, .masthead__right .mh-sep { display: none; } } +@media (max-width: 620px) { .masthead__inner { padding: 12px var(--pad); } .masthead__left { font-size: 10px; gap: 10px; } .masthead__right { font-size: 10px; gap: 10px; } } +@media (max-width: 460px) { .masthead__inner { grid-template-columns: 1fr; } .masthead__left, .masthead__right { display: none; } .masthead__logo { justify-self: center; } } + +/* subhead: search bar */ +.subhead { + display: flex; align-items: stretch; + border-top: 1px solid var(--rule-2); border-bottom: 1px solid var(--rule); + background: color-mix(in oklab, var(--paper) 95%, transparent); + position: relative; +} +.subhead__search { + flex: 1; display: flex; align-items: center; gap: 12px; + padding: 10px var(--pad); border-right: 1px solid var(--rule-2); min-width: 0; +} +.subhead__search input { + flex: 1; min-width: 0; border: 0; background: transparent; outline: none; + font: 400 16px/1 var(--serif); font-style: italic; color: var(--ink); letter-spacing: .005em; padding: 6px 0; +} +.subhead__search input::placeholder { color: var(--ink-soft); opacity: .9; } +.subhead__kbd { flex: 0 0 auto; font: 500 10px/1 var(--sans); letter-spacing: .12em; text-transform: uppercase; border: 1px solid var(--rule); padding: 5px 7px; border-radius: 3px; color: var(--ink-soft); } +.subhead__count { display: flex; align-items: center; padding: 0 var(--pad); font: 500 11px/1 var(--sans); letter-spacing: .16em; text-transform: uppercase; color: var(--ink-soft); font-variant-numeric: tabular-nums; white-space: nowrap; } +.subhead__count b { color: var(--ink); font-weight: 600; margin-right: 4px; } +@media (max-width: 720px) { .subhead__count { display: none; } .subhead__kbd { display: none; } .subhead__search input { font-size: 15px; } } + +/* tabs */ +.tabs { display: flex; gap: 4px; overflow-x: auto; padding: 10px var(--pad); border-bottom: 1px solid var(--rule-2); background: var(--paper); scrollbar-width: none; } +.tabs::-webkit-scrollbar { display: none; } +.tabs button { flex: 0 0 auto; padding: 8px 14px; border-radius: 999px; font: 500 11px/1 var(--sans); letter-spacing: .14em; text-transform: uppercase; color: var(--ink-soft); border: 1px solid transparent; transition: color .2s, border-color .2s, background .2s; } +.tabs button:hover { color: var(--ink); } +.tabs button[aria-pressed="true"] { color: var(--paper); background: var(--ink); border-color: var(--ink); } + +/* ── hero strip ── */ +.hero { + padding: clamp(40px, 8vw, 96px) var(--pad) clamp(28px, 5vw, 64px); + display: grid; grid-template-columns: 1fr; gap: 18px; + border-bottom: 1px solid var(--rule); +} +.hero__eyebrow { font: 500 11px/1 var(--sans); letter-spacing: .2em; text-transform: uppercase; color: var(--ink-soft); display: flex; align-items: center; gap: 12px; } +.hero__eyebrow::before { content: ""; height: 1px; width: 36px; background: var(--ink-soft); } +.hero__title { margin: 0; font: 400 clamp(48px, 9vw, 132px)/0.92 var(--display); letter-spacing: -0.01em; } +.hero__title em { font-family: var(--serif); font-style: italic; font-weight: 300; color: var(--roux); } +.hero__lede { max-width: 56ch; font: 400 clamp(16px, 1.4vw, 19px)/1.5 var(--serif); color: var(--ink-2); margin-top: 6px; } +.hero__lede em { color: var(--roux); font-style: italic; } + +/* ── photo grid ── */ +.grid { + padding: clamp(20px, 3vw, 40px) var(--pad) 80px; + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + column-gap: var(--gap); + row-gap: clamp(40px, 5vw, 72px); +} +@media (max-width: 1200px) { .grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } } +@media (max-width: 820px) { .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } } +@media (max-width: 520px) { .grid { grid-template-columns: 1fr; } } + +.grid[data-density="cozy"] { grid-template-columns: repeat(3, minmax(0, 1fr)); row-gap: 88px; } +.grid[data-density="compact"] { grid-template-columns: repeat(5, minmax(0, 1fr)); row-gap: 56px; } +@media (max-width: 1200px) { .grid[data-density="cozy"] { grid-template-columns: repeat(2, minmax(0, 1fr)); } .grid[data-density="compact"] { grid-template-columns: repeat(4, minmax(0, 1fr)); } } +@media (max-width: 820px) { .grid[data-density="cozy"] { grid-template-columns: repeat(2, minmax(0, 1fr)); } .grid[data-density="compact"] { grid-template-columns: repeat(3, minmax(0, 1fr)); } } +@media (max-width: 520px) { .grid[data-density="cozy"] { grid-template-columns: 1fr; } .grid[data-density="compact"] { grid-template-columns: repeat(2, minmax(0, 1fr)); } } + +/* card */ +.card { display: block; cursor: pointer; } +.card__frame { position: relative; aspect-ratio: 2/3; overflow: hidden; background: var(--paper-2); border-radius: 1px; } +.card__frame::after { content: ""; position: absolute; inset: 0; box-shadow: inset 0 0 0 1px rgba(22,17,13,.04); pointer-events: none; } +.card__img { width: 100%; height: 100%; object-fit: cover; transition: transform .9s cubic-bezier(.2,.7,.1,1), filter .6s; filter: saturate(.92) contrast(1.02); } +.card:hover .card__img { transform: scale(1.025); } +.card__num { position: absolute; top: 10px; left: 10px; font: 500 10px/1 var(--sans); letter-spacing: .18em; color: var(--paper); mix-blend-mode: difference; font-variant-numeric: tabular-nums; } +.card__cat { position: absolute; top: 10px; right: 10px; font: 500 10px/1 var(--sans); letter-spacing: .18em; text-transform: uppercase; color: var(--paper); mix-blend-mode: difference; } +.card__meta { margin-top: 14px; display: grid; gap: 4px; } +.card__title { font: 400 clamp(20px, 1.6vw, 26px)/1.1 var(--display); letter-spacing: 0; margin: 0; } +.card__title em { font-family: var(--serif); font-style: italic; color: var(--roux); } +.card__sub { font: 400 12px/1.4 var(--sans); letter-spacing: .04em; color: var(--ink-soft); display: flex; align-items: center; gap: 10px; } +.card__sub .dot { width: 3px; height: 3px; background: var(--ink-soft); border-radius: 50%; opacity: .5; } +.card__desc { font: 400 13px/1.5 var(--serif); color: var(--ink-2); font-style: italic; margin-top: 2px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } + +/* highlight matches */ +mark.hl { background: color-mix(in oklab, var(--roux) 22%, transparent); color: inherit; padding: 0 1px; border-radius: 1px; } + +/* ── issues archive ── */ +.issues-grid { + padding: clamp(20px, 3vw, 40px) var(--pad) 80px; + display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); + column-gap: clamp(24px, 3vw, 48px); row-gap: clamp(36px, 5vw, 64px); +} +@media (max-width: 820px) { .issues-grid { grid-template-columns: 1fr; } } + +.issue-card { + display: grid; grid-template-columns: 240px 1fr; + gap: clamp(20px, 2.4vw, 36px); align-items: start; + color: inherit; + padding-bottom: clamp(28px, 3.5vw, 44px); border-bottom: 1px solid var(--rule-2); +} +@media (max-width: 560px) { .issue-card { grid-template-columns: 160px 1fr; } } +.issue-card--forthcoming { color: var(--ink-soft); cursor: default; } + +.issue-card__cover { aspect-ratio: 2/3; overflow: hidden; background: var(--paper-2); position: relative; } +.issue-card__cover::after { content: ""; position: absolute; inset: 0; box-shadow: inset 0 0 0 1px rgba(22,17,13,.04); } +.issue-card__cover img { width: 100%; height: 100%; object-fit: cover; transition: transform .9s cubic-bezier(.2,.7,.1,1); } +.issue-card:not(.issue-card--forthcoming):hover .issue-card__cover img { transform: scale(1.025); } +.issue-card__forth { position: absolute; inset: 0; display: grid; place-items: center; align-content: center; gap: 14px; color: var(--ink-soft); font: 500 10px/1 var(--sans); letter-spacing: .22em; text-transform: uppercase; border: 1px dashed var(--rule); margin: 12px; } +.issue-card__forth svg { opacity: .5; } +.issue-card__meta { padding-top: 6px; display: flex; flex-direction: column; align-items: flex-start; gap: 14px; min-width: 0; } +.issue-card__num { font: 500 11px/1 var(--sans); letter-spacing: .2em; text-transform: uppercase; color: var(--ink-soft); } +.issue-card__title { margin: 0; font: 400 clamp(28px, 3vw, 44px)/1.0 var(--display); letter-spacing: -0.005em; } +.issue-card__title em { font-family: var(--serif); font-style: italic; color: var(--roux); font-weight: 300; } +.issue-card--forthcoming .issue-card__title { color: var(--ink-soft); } +.issue-card__blurb { font: 400 14.5px/1.55 var(--serif); font-style: italic; color: var(--ink-2); margin: 0; max-width: 52ch; } +.issue-card__foot { margin-top: 4px; display: flex; align-items: baseline; gap: 18px; flex-wrap: wrap; font: 500 10.5px/1.4 var(--sans); letter-spacing: .14em; text-transform: uppercase; color: var(--ink-soft); width: 100%; } +.issue-card__foot > span:first-child { flex: 1; min-width: 0; } +.issue-card__cta { font-weight: 600; color: var(--ink); border-bottom: 1px solid var(--ink); padding-bottom: 2px; letter-spacing: .14em; } +.issue-card__cta--muted { color: var(--ink-soft); border-bottom-color: var(--rule); } + +/* ── empty state ── */ +.empty { grid-column: 1/-1; padding: 80px 0; text-align: center; color: var(--ink-soft); } +.empty h3 { font: 400 28px/1.2 var(--display); color: var(--ink); margin: 0 0 8px; } +.empty button { margin-top: 16px; border: 1px solid var(--ink); padding: 9px 18px; font: 500 11px/1 var(--sans); letter-spacing: .16em; text-transform: uppercase; } +.empty button:hover { background: var(--ink); color: var(--paper); } + +/* ── search popup ── */ +.searchpop { position: absolute; top: calc(100% - 1px); left: 0; right: 0; background: var(--paper); border: 1px solid var(--rule); border-top: 0; max-height: min(70vh, 620px); overflow: auto; display: none; z-index: 60; box-shadow: 0 24px 60px -30px rgba(22,17,13,.35); } +.searchpop[data-open="true"] { display: block; } +.searchpop__section { padding: 12px var(--pad); border-bottom: 1px solid var(--rule-2); } +.searchpop__section:last-child { border-bottom: 0; } +.searchpop__label { font: 500 10px/1 var(--sans); letter-spacing: .2em; text-transform: uppercase; color: var(--ink-soft); margin-bottom: 10px; display: flex; align-items: baseline; gap: 8px; } +.searchpop__label small { font-family: var(--mono); letter-spacing: 0; font-size: 10px; } +.searchpop__chips { display: flex; flex-wrap: wrap; gap: 6px; } +.searchpop__chip { padding: 5px 10px; border: 1px solid var(--rule); border-radius: 999px; font: 500 11px/1 var(--sans); letter-spacing: .06em; color: var(--ink-2); } +.searchpop__chip:hover { background: var(--ink); color: var(--paper); border-color: var(--ink); } +.searchpop__chip b { color: var(--roux); font-weight: 600; } +.searchpop__hits { display: grid; gap: 2px; } +.searchpop__hit { display: grid; grid-template-columns: 44px 1fr auto; gap: 14px; align-items: center; padding: 8px 6px; border-radius: 3px; text-align: left; width: 100%; } +.searchpop__hit:hover { background: var(--paper-2); } +.searchpop__hit img { width: 44px; height: 66px; object-fit: cover; background: var(--paper-2); } +.searchpop__hit .t { font: 400 18px/1.1 var(--display); } +.searchpop__hit .s { font: 400 12px/1.3 var(--sans); color: var(--ink-soft); margin-top: 3px; } +.searchpop__hit .n { font: 500 10px/1 var(--mono); color: var(--ink-soft); letter-spacing: .1em; } + +/* ── lightbox ── */ +.lb { + position: fixed; inset: 0; background: #0c0907; color: #ece7dd; z-index: 200; + display: none; opacity: 0; transition: opacity .35s ease; +} +.lb[data-open="true"] { display: grid; opacity: 1; } +.lb { + grid-template-columns: 1fr 380px; grid-template-rows: auto 1fr auto; + grid-template-areas: "topbar topbar" "stage meta" "thumbs thumbs"; +} +@media (max-width: 920px) { + .lb { grid-template-columns: 1fr; grid-template-rows: auto 1fr auto auto; grid-template-areas: "topbar" "stage" "meta" "thumbs"; } +} +.lb__topbar { grid-area: topbar; display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 14px 22px; border-bottom: 1px solid rgba(236,231,221,.08); } +.lb__brand { display: flex; align-items: center; gap: 14px; font: 500 11px/1 var(--sans); letter-spacing: .2em; text-transform: uppercase; color: #c8c0b1; } +.lb__brand svg { height: 18px; } +.lb__index { font: 500 11px/1 var(--mono); letter-spacing: .14em; color: #c8c0b1; font-variant-numeric: tabular-nums; } +.lb__index b { color: #ece7dd; } +.lb__close { width: 36px; height: 36px; border: 1px solid rgba(236,231,221,.18); border-radius: 50%; display: grid; place-items: center; color: #ece7dd; } +.lb__close:hover { background: rgba(236,231,221,.08); } +.lb__stage { grid-area: stage; position: relative; overflow: hidden; display: grid; place-items: center; padding: 24px; min-height: 0; } +.lb__track { position: absolute; inset: 0; display: flex; transition: transform .55s cubic-bezier(.4,.0,.2,1); will-change: transform; } +.lb__slide { flex: 0 0 100%; height: 100%; display: flex; align-items: center; justify-content: center; padding: 24px; min-width: 0; } +.lb__frame { position: relative; aspect-ratio: 2/3; height: 100%; max-width: 100%; background: #1a1411; box-shadow: 0 30px 80px -20px rgba(0,0,0,.6), 0 0 0 1px rgba(236,231,221,.04); } +.lb__img { width: 100%; height: 100%; object-fit: cover; object-position: center; display: block; } +.lb__nav { position: absolute; top: 50%; transform: translateY(-50%); width: 56px; height: 56px; border-radius: 50%; background: rgba(236,231,221,.06); border: 1px solid rgba(236,231,221,.16); backdrop-filter: blur(8px); display: grid; place-items: center; color: #ece7dd; z-index: 5; transition: background .2s; } +.lb__nav:hover { background: rgba(236,231,221,.14); } +.lb__nav--prev { left: 18px; } +.lb__nav--next { right: 18px; } +.lb__meta { grid-area: meta; padding: 28px 28px 22px; border-left: 1px solid rgba(236,231,221,.08); display: flex; flex-direction: column; gap: 18px; overflow: auto; } +@media (max-width: 920px) { .lb__meta { border-left: 0; border-top: 1px solid rgba(236,231,221,.08); padding: 18px 22px; max-height: 38vh; } } +.lb__cat { font: 500 11px/1 var(--sans); letter-spacing: .22em; text-transform: uppercase; color: var(--roux); } +.lb__cat::after { content: ""; display: block; height: 1px; width: 30px; background: var(--roux); margin-top: 8px; } +.lb__title { margin: 0; font: 400 clamp(32px, 3vw, 44px)/1 var(--display); letter-spacing: -0.005em; color: #f5f0e6; } +.lb__title em { font-family: var(--serif); font-style: italic; color: #d99e8e; font-weight: 300; } +.lb__desc { font: 400 16px/1.55 var(--serif); font-style: italic; color: #c8c0b1; } +.lb__factgrid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px 22px; border-top: 1px solid rgba(236,231,221,.08); border-bottom: 1px solid rgba(236,231,221,.08); padding: 16px 0; } +.lb__fact dt { font: 500 10px/1 var(--sans); letter-spacing: .18em; text-transform: uppercase; color: #9b9384; margin-bottom: 5px; } +.lb__fact dd { margin: 0; font: 400 14px/1.3 var(--serif); color: #ece7dd; } +.lb__tags { display: flex; flex-wrap: wrap; gap: 6px; } +.lb__tag { padding: 5px 10px; border: 1px solid rgba(236,231,221,.18); border-radius: 999px; font: 500 10px/1 var(--sans); letter-spacing: .1em; text-transform: lowercase; color: #ece7dd; } +.lb__tag:hover { background: rgba(236,231,221,.08); } +.lb__share { margin-top: auto; display: flex; gap: 8px; } +.lb__sh { display: inline-flex; align-items: center; justify-content: center; gap: 8px; padding: 11px 14px; border: 1px solid rgba(236,231,221,.2); font: 500 11px/1 var(--sans); letter-spacing: .14em; text-transform: uppercase; color: #ece7dd; white-space: nowrap; transition: background .2s, color .2s, border-color .2s; } +.lb__sh--primary { flex: 1; min-width: 0; } +.lb__sh:not(.lb__sh--primary) { width: 44px; padding: 11px 0; flex: 0 0 auto; } +.lb__sh:hover { background: #ece7dd; color: #0c0907; border-color: #ece7dd; } +.lb__sh.is-ok { background: rgba(236,231,221,.08); color: #ece7dd; border-color: rgba(236,231,221,.32); } +.lb__thumbs { grid-area: thumbs; display: flex; gap: 6px; padding: 12px 22px 16px; overflow-x: auto; border-top: 1px solid rgba(236,231,221,.08); scrollbar-width: thin; scrollbar-color: rgba(236,231,221,.16) transparent; } +.lb__thumb { flex: 0 0 auto; width: 42px; aspect-ratio: 2/3; background: #1a1411; border: 1px solid transparent; opacity: .45; transition: opacity .2s, border-color .2s; position: relative; } +.lb__thumb:hover { opacity: .8; } +.lb__thumb img { width: 100%; height: 100%; object-fit: cover; } +.lb__thumb[aria-current="true"] { opacity: 1; border-color: var(--roux); } +.lb__thumb[aria-current="true"]::after { content: ""; position: absolute; left: 0; right: 0; bottom: -10px; height: 2px; background: var(--roux); } + +/* ── footer ── */ +.foot { border-top: 1px solid var(--rule); padding: 36px var(--pad) 56px; display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 40px; font: 400 12px/1.5 var(--sans); color: var(--ink-soft); } +@media (max-width: 820px) { .foot { grid-template-columns: 1fr 1fr; } } +.foot h4 { font: 500 10px/1 var(--sans); letter-spacing: .22em; text-transform: uppercase; color: var(--ink); margin: 0 0 14px; } +.foot a:hover { color: var(--ink); } +.foot__roux { font: 400 clamp(60px, 8vw, 110px)/0.92 var(--display); color: var(--ink); margin: 0 0 14px; } +.foot__roux em { font-family: var(--serif); font-style: italic; color: var(--roux); font-weight: 300; } + +/* ── ribbon ── */ +.ribbon { position: fixed; left: 0; right: 0; bottom: 0; z-index: 30; background: var(--ink); color: var(--paper); font: 500 11px/1 var(--sans); letter-spacing: .2em; text-transform: uppercase; padding: 10px var(--pad); display: flex; align-items: center; justify-content: space-between; gap: 24px; transform: translateY(0); transition: transform .4s; } +.ribbon.hidden { transform: translateY(100%); } +.ribbon a { color: var(--roux); font-weight: 600; } +.ribbon button { color: var(--paper); opacity: .7; } +.ribbon button:hover { opacity: 1; } + +/* ── animations ── */ +@keyframes rouxIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } } +.card { animation: rouxIn .6s cubic-bezier(.2,.7,.2,1) both; animation-delay: var(--d, 0ms); } +.issue-card { opacity: 0; transform: translateY(8px); animation: rouxIn .65s cubic-bezier(.2,.7,.2,1) forwards; animation-delay: var(--d, 0ms); } +@supports (animation-timeline: view()) { .issue-card { opacity: 1; transform: none; animation: none; } } + +/* ── view transitions ── */ +::view-transition-old(root) { animation: 150ms ease-out roux-fade-out; } +::view-transition-new(root) { animation: 220ms ease-in roux-fade-in; } +@keyframes roux-fade-out { from { opacity: 1; } to { opacity: 0; } } +@keyframes roux-fade-in { from { opacity: 0; } to { opacity: 1; } } + +/* ── scrollbar ── */ +::-webkit-scrollbar { width: 10px; height: 10px; } +::-webkit-scrollbar-thumb { background: var(--rule); border-radius: 0; } +::-webkit-scrollbar-track { background: transparent; } diff --git a/assets/js/app.js b/assets/js/app.js new file mode 100644 index 0000000..9d26430 --- /dev/null +++ b/assets/js/app.js @@ -0,0 +1,452 @@ +/* ROUX — app.js */ +(function () { + 'use strict'; + + // ── Data (injected by Hugo into a JSON script tag) + let POSTS = []; + try { + const el = document.getElementById('roux-data'); + if (el) POSTS = JSON.parse(el.textContent) || []; + } catch (e) { console.warn('roux-data parse failed', e); } + + const STOP = new Set(['the','a','an','of','and','in','on','at','by','with','is','to','for','from','as','into','onto','its','it','that','this','but','or','be','not','no','one','two','three']); + + // ── Helpers + function esc(s) { return String(s).replace(/[&<>"]/g, c => ({'&':'&','<':'<','>':'>','"':'"'}[c])); } + + function highlight(text, terms) { + if (!terms.length) return esc(text); + const re = new RegExp('(' + terms.map(t => t.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|') + ')', 'ig'); + return esc(text).replace(re, '$1'); + } + + // ── Inverted search index + const INDEX = (() => { + const map = new Map(); + function add(token, idx, weight) { + const t = token.toLowerCase(); + if (!t || t.length < 2 || STOP.has(t)) return; + let b = map.get(t); + if (!b) { b = new Map(); map.set(t, b); } + b.set(idx, (b.get(idx) || 0) + weight); + } + function tok(s) { return (s || '').toLowerCase().split(/[^a-z0-9àâäéèêëîïôöùûüçœæñ]+/i).filter(Boolean); } + + POSTS.forEach((p, i) => { + tok(p.title).forEach(t => add(t, i, 6)); + (p.categories || []).forEach(c => tok(c).forEach(t => add(t, i, 4))); + (p.tags || []).forEach(tag => tok(tag).forEach(t => add(t, i, 5))); + tok(p.description).forEach(t => add(t, i, 1)); + tok(p.id).forEach(t => add(t, i, 8)); + }); + + return function search(q) { + const tokens = tok(q); + if (!tokens.length) return null; + const perToken = tokens.map(tok => { + const merged = new Map(); + for (const [term, b] of map) { + if (term.startsWith(tok)) { + const factor = term === tok ? 1.0 : tok.length / term.length; + for (const [pi, w] of b) merged.set(pi, (merged.get(pi) || 0) + w * factor); + } + } + return merged; + }); + const first = perToken[0]; + const scores = new Map(); + for (const [idx, w] of first) { + let total = w, ok = true; + for (let i = 1; i < perToken.length; i++) { + const v = perToken[i].get(idx); + if (!v) { ok = false; break; } + total += v; + } + if (ok) scores.set(idx, total); + } + return Array.from(scores.entries()) + .sort((a, b) => b[1] - a[1]) + .map(([i]) => POSTS[i]); + }; + })(); + + // ── Masthead date + const mhDate = document.getElementById('mhDate'); + if (mhDate) { + const d = new Date(); + mhDate.textContent = d.toLocaleDateString('en-GB', { day:'numeric', month:'long', year:'numeric' }); + } + + // ── Count display + const countEl = document.getElementById('count'); + function setCount(n) { + if (!countEl) return; + countEl.innerHTML = `${String(n).padStart(3,'0')} ${n === 1 ? 'post' : 'posts'}`; + } + setCount(POSTS.length); + + // ── Tabs: sync active state with current URL + function syncTabs() { + const tabs = document.querySelectorAll('.tabs button[data-cat]'); + const path = location.pathname; + tabs.forEach(btn => { + const cat = btn.dataset.cat; + const active = (cat === 'All' && (path === '/' || path === '/posts/' || path.startsWith('/posts'))) + || (cat !== 'All' && path.toLowerCase().includes(cat.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, ''))); + btn.setAttribute('aria-pressed', active ? 'true' : 'false'); + }); + } + syncTabs(); + + // Tab click → navigate to category page + document.addEventListener('click', e => { + const btn = e.target.closest('.tabs button[data-cat]'); + if (!btn) return; + const cat = btn.dataset.cat; + if (cat === 'All') navigate('/'); + else navigate('/categories/' + cat.toLowerCase().replace(/[\s,]+/g, '-').replace(/[^a-z0-9-]/g, '') + '/'); + }); + + // ── Search popup + const searchInput = document.getElementById('searchInput'); + const searchPop = document.getElementById('searchpop'); + + function allCats() { + const s = new Set(); + POSTS.forEach(p => (p.categories || []).forEach(c => s.add(c))); + return Array.from(s).slice(0, 8); + } + function allTags() { + const freq = new Map(); + POSTS.forEach(p => (p.tags || []).forEach(t => freq.set(t, (freq.get(t)||0)+1))); + return Array.from(freq.entries()).sort((a,b)=>b[1]-a[1]).slice(0,10).map(([t])=>t); + } + + function renderSearchPop(q) { + if (!searchPop) return; + if (!q) { + const cats = allCats(); + const tags = allTags(); + searchPop.innerHTML = ` +
+
Categories ${cats.length}
+
+ ${cats.map(c => ``).join('')} +
+
+
+
Popular tags ${tags.length}
+
+ ${tags.map(t => ``).join('')} +
+
`; + searchPop.dataset.open = 'true'; + return; + } + const hits = INDEX(q) || []; + const terms = q.toLowerCase().split(/\s+/).filter(t => t.length > 1); + if (!hits.length) { + searchPop.innerHTML = `

No plates match — try gothic, warrior, or neon.

`; + searchPop.dataset.open = 'true'; + return; + } + const shown = hits.slice(0, 6); + searchPop.innerHTML = ` +
+
Plates ${hits.length}
+
+ ${shown.map(p => ` + `).join('')} +
+
`; + searchPop.dataset.open = 'true'; + } + + if (searchInput) { + searchInput.addEventListener('input', () => renderSearchPop(searchInput.value.trim())); + searchInput.addEventListener('focus', () => renderSearchPop(searchInput.value.trim())); + document.addEventListener('keydown', e => { + if ((e.metaKey || e.ctrlKey) && e.key === 'k') { e.preventDefault(); searchInput.focus(); renderSearchPop(''); } + if (e.key === 'Escape') closeSearch(); + }); + } + + if (searchPop) { + searchPop.addEventListener('click', e => { + const btn = e.target.closest('[data-jump]'); + if (btn) { closeSearch(); navigate(btn.dataset.jump); } + }); + } + + document.addEventListener('click', e => { + if (searchPop && searchPop.dataset.open === 'true' && !e.target.closest('.subhead')) closeSearch(); + }); + + function closeSearch() { + if (searchPop) { searchPop.dataset.open = 'false'; searchPop.innerHTML = ''; } + if (searchInput) searchInput.blur(); + } + + // ── Lightbox + const lb = document.getElementById('lb'); + const lbTrack = document.getElementById('lbTrack'); + const lbMeta = document.getElementById('lbMeta'); + const lbThumbs = document.getElementById('lbThumbs'); + const lbIndex = document.getElementById('lbIndex'); + + let lbList = []; // current scoped post list + let lbIdx = -1; // index into lbList + let lbBuilt = false; + + function lbOpen(slug, scopedList) { + lbList = scopedList || POSTS; + const idx = lbList.findIndex(p => p.slug === slug); + if (idx === -1) return; + lbIdx = idx; + if (!lbBuilt) buildLbSlides(); + lb.dataset.open = 'true'; + document.body.style.overflow = 'hidden'; + goToSlide(lbIdx, false); + lbBuildMeta(lbList[lbIdx]); + lbBuildThumbs(); + } + + function lbClose() { + if (!lb) return; + lb.dataset.open = 'false'; + document.body.style.overflow = ''; + // pop back to gallery if we're on a single-post URL + if (window.__ROUX_OPEN_SLUG) { + navigate('/'); + } + } + + function buildLbSlides() { + if (!lbTrack) return; + lbTrack.innerHTML = lbList.map((p, i) => { + const imgSrc = p.card || p.thumb || ''; + return `
+
+ ${esc(p.title)} +
+
`; + }).join(''); + lbBuilt = true; + // Preload neighbors + preloadNeighbors(lbIdx); + } + + function goToSlide(idx, smooth = true) { + if (!lbTrack) return; + lbIdx = Math.max(0, Math.min(idx, lbList.length - 1)); + lbTrack.style.transition = smooth ? '' : 'none'; + lbTrack.style.transform = `translateX(-${lbIdx * 100}%)`; + if (!smooth) lbTrack.getBoundingClientRect(); // force reflow + if (lbIndex) { + lbIndex.innerHTML = `${String(lbIdx + 1).padStart(3,'0')} / ${lbList.length}`; + } + lbBuildMeta(lbList[lbIdx]); + syncThumbs(); + preloadNeighbors(lbIdx); + } + + function preloadNeighbors(idx) { + if (!lbTrack) return; + [-1, 0, 1, 2].forEach(d => { + const ni = idx + d; + if (ni < 0 || ni >= lbList.length) return; + const slide = lbTrack.querySelector(`.lb__slide[data-i="${ni}"]`); + if (!slide) return; + const img = slide.querySelector('img'); + if (img && !img.src) img.src = lbList[ni].card || lbList[ni].thumb || ''; + }); + } + + function lbBuildMeta(p) { + if (!lbMeta || !p) return; + const cats = (p.categories || []).join(', '); + const tags = (p.tags || []).slice(0, 8); + lbMeta.innerHTML = ` +
${esc(cats)}
+

${esc(p.title)}

+

${esc(p.description)}

+
+
Plate
№ ${esc(p.id)}
+
Category
${esc((p.categories||['—'])[0])}
+
+
${tags.map(t => `${esc(t)}`).join('')}
+ `; + + document.getElementById('lbCopy')?.addEventListener('click', function () { + const url = new URL(this.dataset.url, location.origin).href; + navigator.clipboard.writeText(url).then(() => { + this.classList.add('is-ok'); + this.querySelector('.lb__sh-l').textContent = 'Copied!'; + setTimeout(() => { this.classList.remove('is-ok'); this.querySelector('.lb__sh-l').textContent = 'Copy link'; }, 2000); + }); + }); + } + + function lbBuildThumbs() { + if (!lbThumbs) return; + lbThumbs.innerHTML = lbList.map((p, i) => + `` + ).join(''); + lbThumbs.addEventListener('click', e => { + const btn = e.target.closest('.lb__thumb'); + if (btn) goToSlide(parseInt(btn.dataset.i)); + }); + } + + function syncThumbs() { + if (!lbThumbs) return; + lbThumbs.querySelectorAll('.lb__thumb').forEach((b, i) => { + b.setAttribute('aria-current', i === lbIdx ? 'true' : 'false'); + }); + const active = lbThumbs.querySelector('.lb__thumb[aria-current="true"]'); + if (active) active.scrollIntoView({ inline: 'center', behavior: 'smooth' }); + } + + // Lightbox controls + if (lb) { + lb.addEventListener('click', e => { + const act = e.target.closest('[data-act]')?.dataset.act; + if (act === 'close') lbClose(); + else if (act === 'prev') goToSlide(lbIdx - 1); + else if (act === 'next') goToSlide(lbIdx + 1); + }); + document.addEventListener('keydown', e => { + if (lb.dataset.open !== 'true') return; + if (e.key === 'Escape') { lbClose(); } + if (e.key === 'ArrowLeft') { e.preventDefault(); goToSlide(lbIdx - 1); } + if (e.key === 'ArrowRight') { e.preventDefault(); goToSlide(lbIdx + 1); } + }); + + // Touch swipe + let touchX = null; + lb.addEventListener('touchstart', e => { touchX = e.touches[0].clientX; }, { passive: true }); + lb.addEventListener('touchend', e => { + if (touchX === null) return; + const dx = e.changedTouches[0].clientX - touchX; + if (Math.abs(dx) > 50) { dx < 0 ? goToSlide(lbIdx + 1) : goToSlide(lbIdx - 1); } + touchX = null; + }); + } + + // ── Card clicks → open lightbox (no full page navigation for same-origin) + document.addEventListener('click', e => { + const card = e.target.closest('.card[data-slug]'); + if (!card) return; + e.preventDefault(); + const slug = card.dataset.slug; + const visibleSlugs = Array.from(document.querySelectorAll('.card[data-slug]')).map(c => c.dataset.slug); + const scopedList = POSTS.filter(p => visibleSlugs.includes(p.slug)); + // Update URL without page reload + history.pushState({ slug }, '', card.href); + lbOpen(slug, scopedList.length ? scopedList : POSTS); + }); + + // Handle browser back/forward + window.addEventListener('popstate', e => { + if (lb && lb.dataset.open === 'true') { + if (!e.state?.slug) { lb.dataset.open = 'false'; document.body.style.overflow = ''; } + } + }); + + // ── Ribbon + const ribbon = document.getElementById('ribbon'); + const ribbonClose = document.getElementById('ribbonClose'); + if (ribbonClose && ribbon) { + if (sessionStorage.getItem('ribbon-closed')) ribbon.classList.add('hidden'); + ribbonClose.addEventListener('click', () => { + ribbon.classList.add('hidden'); + sessionStorage.setItem('ribbon-closed', '1'); + }); + } + + // ── Async page transitions (View Transitions API) + function isSameOrigin(url) { + try { return new URL(url).origin === location.origin; } catch { return false; } + } + + async function navigate(url) { + if (!isSameOrigin(url)) { location.href = url; return; } + + if (!document.startViewTransition) { + location.href = url; + return; + } + + document.startViewTransition(async () => { + const res = await fetch(url, { headers: { 'X-Requested-With': 'fetch' } }); + const text = await res.text(); + const doc = new DOMParser().parseFromString(text, 'text/html'); + + const newContent = doc.getElementById('content'); + const newData = doc.getElementById('roux-data'); + const oldContent = document.getElementById('content'); + + if (newContent && oldContent) { + oldContent.replaceWith(newContent); + } + if (newData) { + try { + POSTS = JSON.parse(newData.textContent) || []; + lbBuilt = false; // force rebuild on next open + } catch {} + } + + document.title = doc.title; + history.pushState({}, '', url); + + // Re-init page state + setCount(POSTS.length); + syncTabs(); + + // If new page has a slug to open + const script = doc.querySelector('script[data-open-slug]'); + const openSlug = window.__ROUX_OPEN_SLUG = doc.querySelector('[data-open-slug]')?.dataset.openSlug || null; + if (openSlug) { + const visibleSlugs = Array.from(document.querySelectorAll('.card[data-slug]')).map(c => c.dataset.slug); + const scoped = POSTS.filter(p => visibleSlugs.includes(p.slug)); + lbOpen(openSlug, scoped.length ? scoped : POSTS); + } + }); + } + + // Intercept link clicks for async transitions + document.addEventListener('click', e => { + if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return; + const a = e.target.closest('a[href]'); + if (!a || a.target || a.hasAttribute('download')) return; + if (!isSameOrigin(a.href)) return; + // Skip lightbox card clicks (handled above) + if (a.closest('.card[data-slug]')) return; + // Skip anchor links + if (a.href.includes('#')) return; + e.preventDefault(); + navigate(a.href); + }); + + // ── On single-post pages: auto-open lightbox + if (window.__ROUX_OPEN_SLUG && POSTS.length) { + const visibleSlugs = Array.from(document.querySelectorAll('.card[data-slug]')).map(c => c.dataset.slug); + const scoped = POSTS.filter(p => visibleSlugs.includes(p.slug)); + lbOpen(window.__ROUX_OPEN_SLUG, scoped.length ? scoped : POSTS); + } + +})(); diff --git a/content/_index.md b/content/_index.md new file mode 100644 index 0000000..3b36f13 --- /dev/null +++ b/content/_index.md @@ -0,0 +1,4 @@ +--- +title: "Roux — An almanac of fabric, light and gesture." +description: "Roux is a slow-publishing fashion journal — one hundred photographs at a time. Editorial, couture, beauty and backstage plates." +--- diff --git a/content/issues/_index.md b/content/issues/_index.md new file mode 100644 index 0000000..6774bad --- /dev/null +++ b/content/issues/_index.md @@ -0,0 +1,5 @@ +--- +title: "Issues" +description: "Every quarterly release of Roux, in order." +layout: "issues" +--- diff --git a/content/posts/_index.md b/content/posts/_index.md new file mode 100644 index 0000000..f9fcae2 --- /dev/null +++ b/content/posts/_index.md @@ -0,0 +1,4 @@ +--- +title: "The Archive" +description: "All one hundred plates from the Roux archive." +--- diff --git a/content/posts/armored-chains-city-fire/armored-chains-city-fire.png b/content/posts/armored-chains-city-fire/armored-chains-city-fire.png new file mode 100644 index 0000000..517556d Binary files /dev/null and b/content/posts/armored-chains-city-fire/armored-chains-city-fire.png differ diff --git a/content/posts/armored-chains-city-fire/index.md b/content/posts/armored-chains-city-fire/index.md new file mode 100644 index 0000000..c0c67b3 --- /dev/null +++ b/content/posts/armored-chains-city-fire/index.md @@ -0,0 +1,20 @@ +--- +title: "Armored Chains City Fire" +description: "a fiery-haired model in black structured editorial fashion standing against a burning urban cityscape, defiant strength with orange flames and neon glow cutting through the dark cinematic backdrop" +plate: "001" +slug: "armored-chains-city-fire" +image: "armored-chains-city-fire.png" +weight: 1 +categories: + - "Cyberpunk" +tags: + - "Cyberpunk" + - "Chains" + - "Fire" + - "Armor" + - "City" + - "Defiant" + - "Dark" + - "Urban" + - "Flames" +--- diff --git a/content/posts/armored-warrior-poppy-fields/armored-warrior-poppy-fields.png b/content/posts/armored-warrior-poppy-fields/armored-warrior-poppy-fields.png new file mode 100644 index 0000000..99a988c Binary files /dev/null and b/content/posts/armored-warrior-poppy-fields/armored-warrior-poppy-fields.png differ diff --git a/content/posts/armored-warrior-poppy-fields/index.md b/content/posts/armored-warrior-poppy-fields/index.md new file mode 100644 index 0000000..4e962e6 --- /dev/null +++ b/content/posts/armored-warrior-poppy-fields/index.md @@ -0,0 +1,20 @@ +--- +title: "Armored Warrior Poppy Fields" +description: "a tall redhead in ornate structured black and silver fashion couture standing in a sweeping field of red poppies beneath a dramatic sky, epic painterly cinematic editorial quality" +plate: "002" +slug: "armored-warrior-poppy-fields" +image: "armored-warrior-poppy-fields.png" +weight: 2 +categories: + - "Fantasy" + - "Mythology" +tags: + - "Armor" + - "Poppies" + - "Storm" + - "Fantasy" + - "Mountains" + - "Epic" + - "Cinematic" + - "Painterly" +--- diff --git a/content/posts/autumn-glamour-in-the-park/autumn-glamour-in-the-park.png b/content/posts/autumn-glamour-in-the-park/autumn-glamour-in-the-park.png new file mode 100644 index 0000000..30dd27b Binary files /dev/null and b/content/posts/autumn-glamour-in-the-park/autumn-glamour-in-the-park.png differ diff --git a/content/posts/autumn-glamour-in-the-park/index.md b/content/posts/autumn-glamour-in-the-park/index.md new file mode 100644 index 0000000..811a6f7 --- /dev/null +++ b/content/posts/autumn-glamour-in-the-park/index.md @@ -0,0 +1,19 @@ +--- +title: "Autumn Glamour in the Park" +description: "a striking redhead in a black latex dress with dramatic puffed sleeves posing in an autumn park, golden fallen leaves carpeting the ground in a glamorous yet gothic high-fashion editorial" +plate: "003" +slug: "autumn-glamour-in-the-park" +image: "autumn-glamour-in-the-park.png" +weight: 3 +categories: + - "Gothic" +tags: + - "Gothic" + - "Latex" + - "Autumn" + - "Park" + - "Leaves" + - "Glamour" + - "Fashion" + - "Eerie" +--- diff --git a/content/posts/baroque-hall-red-corset/baroque-hall-red-corset.png b/content/posts/baroque-hall-red-corset/baroque-hall-red-corset.png new file mode 100644 index 0000000..3764c2d Binary files /dev/null and b/content/posts/baroque-hall-red-corset/baroque-hall-red-corset.png differ diff --git a/content/posts/baroque-hall-red-corset/index.md b/content/posts/baroque-hall-red-corset/index.md new file mode 100644 index 0000000..8bec9e1 --- /dev/null +++ b/content/posts/baroque-hall-red-corset/index.md @@ -0,0 +1,19 @@ +--- +title: "Baroque Hall Red Corset" +description: "a fiery-haired model in a structured black corset and red latex gloves commanding a grand baroque corridor with gilded chandeliers, luxurious opulent setting and high-contrast editorial styling" +plate: "004" +slug: "baroque-hall-red-corset" +image: "baroque-hall-red-corset.png" +weight: 4 +categories: + - "Gothic" +tags: + - "Baroque" + - "Corset" + - "Chandeliers" + - "Gothic" + - "Dark Opulence" + - "Theatrical" + - "Red Gloves" + - "Grand" +--- diff --git a/content/posts/bioluminescent-beauty-at-twilight/bioluminescent-beauty-at-twilight.png b/content/posts/bioluminescent-beauty-at-twilight/bioluminescent-beauty-at-twilight.png new file mode 100644 index 0000000..412d67c Binary files /dev/null and b/content/posts/bioluminescent-beauty-at-twilight/bioluminescent-beauty-at-twilight.png differ diff --git a/content/posts/bioluminescent-beauty-at-twilight/index.md b/content/posts/bioluminescent-beauty-at-twilight/index.md new file mode 100644 index 0000000..8b7dd85 --- /dev/null +++ b/content/posts/bioluminescent-beauty-at-twilight/index.md @@ -0,0 +1,19 @@ +--- +title: "Bioluminescent Beauty at Twilight" +description: "a fiery-haired model in a red and blue iridescent editorial bodysuit leaning gracefully against a glass surface with a glowing cyberpunk cityscape beyond, mesmerizing futuristic fashion portrait" +plate: "005" +slug: "bioluminescent-beauty-at-twilight" +image: "bioluminescent-beauty-at-twilight.png" +weight: 5 +categories: + - "Cyberpunk" +tags: + - "Bioluminescent" + - "Bodysuit" + - "Neon" + - "Cyberpunk" + - "Futuristic" + - "Iridescent" + - "City" + - "Portrait" +--- diff --git a/content/posts/cyber-huntress-on-wet-streets/cyber-huntress-on-wet-streets.png b/content/posts/cyber-huntress-on-wet-streets/cyber-huntress-on-wet-streets.png new file mode 100644 index 0000000..0e2e73c Binary files /dev/null and b/content/posts/cyber-huntress-on-wet-streets/cyber-huntress-on-wet-streets.png differ diff --git a/content/posts/cyber-huntress-on-wet-streets/index.md b/content/posts/cyber-huntress-on-wet-streets/index.md new file mode 100644 index 0000000..765e440 --- /dev/null +++ b/content/posts/cyber-huntress-on-wet-streets/index.md @@ -0,0 +1,19 @@ +--- +title: "Cyber Huntress on Wet Streets" +description: "a fiery-haired model in a sleek black tactical editorial bodysuit posed mid-stride on a neon-lit rainy city street at night, long hair whipping in wind amid cinematic blue wet-pavement atmosphere" +plate: "006" +slug: "cyber-huntress-on-wet-streets" +image: "cyber-huntress-on-wet-streets.png" +weight: 6 +categories: + - "Cyberpunk" +tags: + - "Cyberpunk" + - "Rain" + - "City" + - "Tactical" + - "Action" + - "Blue Tones" + - "Neon" + - "Night" +--- diff --git a/content/posts/cyberpunk-femme-in-the-downpour/cyberpunk-femme-in-the-downpour.png b/content/posts/cyberpunk-femme-in-the-downpour/cyberpunk-femme-in-the-downpour.png new file mode 100644 index 0000000..339502c Binary files /dev/null and b/content/posts/cyberpunk-femme-in-the-downpour/cyberpunk-femme-in-the-downpour.png differ diff --git a/content/posts/cyberpunk-femme-in-the-downpour/index.md b/content/posts/cyberpunk-femme-in-the-downpour/index.md new file mode 100644 index 0000000..8e03d88 --- /dev/null +++ b/content/posts/cyberpunk-femme-in-the-downpour/index.md @@ -0,0 +1,19 @@ +--- +title: "Cyberpunk Femme in the Downpour" +description: "a fiery-haired model in a black leather editorial jacket and sleek bodysuit walking through a rain-soaked city street flanked by dramatic lighting, gritty neo-noir femme fatale fashion editorial" +plate: "007" +slug: "cyberpunk-femme-in-the-downpour" +image: "cyberpunk-femme-in-the-downpour.png" +weight: 7 +categories: + - "Cyberpunk" +tags: + - "Cyberpunk" + - "Rain" + - "Noir" + - "Femme Fatale" + - "Leather Jacket" + - "City" + - "Neon" + - "Urban" +--- diff --git a/content/posts/cyberpunk-night-pursuit/cyberpunk-night-pursuit.png b/content/posts/cyberpunk-night-pursuit/cyberpunk-night-pursuit.png new file mode 100644 index 0000000..6294828 Binary files /dev/null and b/content/posts/cyberpunk-night-pursuit/cyberpunk-night-pursuit.png differ diff --git a/content/posts/cyberpunk-night-pursuit/index.md b/content/posts/cyberpunk-night-pursuit/index.md new file mode 100644 index 0000000..bb89da8 --- /dev/null +++ b/content/posts/cyberpunk-night-pursuit/index.md @@ -0,0 +1,19 @@ +--- +title: "Cyberpunk Night Pursuit" +description: "a sleek fiery-haired model in a form-fitting black editorial bodysuit striding through a rain-drenched futuristic cityscape, long hair flowing amid neon-lit reflections and dark skyscrapers" +plate: "008" +slug: "cyberpunk-night-pursuit" +image: "cyberpunk-night-pursuit.png" +weight: 8 +categories: + - "Cyberpunk" +tags: + - "Cyberpunk" + - "Bodysuit" + - "Rain" + - "Neon" + - "City" + - "Futuristic" + - "Night" + - "Skyscrapers" +--- diff --git a/content/posts/cyberpunk-rain-street-fighter/cyberpunk-rain-street-fighter.png b/content/posts/cyberpunk-rain-street-fighter/cyberpunk-rain-street-fighter.png new file mode 100644 index 0000000..6efb454 Binary files /dev/null and b/content/posts/cyberpunk-rain-street-fighter/cyberpunk-rain-street-fighter.png differ diff --git a/content/posts/cyberpunk-rain-street-fighter/index.md b/content/posts/cyberpunk-rain-street-fighter/index.md new file mode 100644 index 0000000..002bfec --- /dev/null +++ b/content/posts/cyberpunk-rain-street-fighter/index.md @@ -0,0 +1,19 @@ +--- +title: "Cyberpunk Rain Street Fighter" +description: "a fiery-haired model in a black structured editorial bodysuit standing defiantly on a rain-soaked neon-lit cyberpunk street, danger and fierce fashion energy in a gritty futuristic urban setting" +plate: "009" +slug: "cyberpunk-rain-street-fighter" +image: "cyberpunk-rain-street-fighter.png" +weight: 9 +categories: + - "Cyberpunk" +tags: + - "Cyberpunk" + - "Rain" + - "Neon" + - "Tactical" + - "Street Fighter" + - "Futuristic" + - "Gritty" + - "Danger" +--- diff --git a/content/posts/dark-angel-in-the-jungle/dark-angel-in-the-jungle.png b/content/posts/dark-angel-in-the-jungle/dark-angel-in-the-jungle.png new file mode 100644 index 0000000..7e927a7 Binary files /dev/null and b/content/posts/dark-angel-in-the-jungle/dark-angel-in-the-jungle.png differ diff --git a/content/posts/dark-angel-in-the-jungle/index.md b/content/posts/dark-angel-in-the-jungle/index.md new file mode 100644 index 0000000..b0ac63c --- /dev/null +++ b/content/posts/dark-angel-in-the-jungle/index.md @@ -0,0 +1,19 @@ +--- +title: "Dark Angel in the Jungle" +description: "a redheaded model in a dramatic black bodysuit with a sweeping architectural cape standing amid lush tropical foliage, the editorial evoking wild power and otherworldly fashion beauty" +plate: "010" +slug: "dark-angel-in-the-jungle" +image: "dark-angel-in-the-jungle.png" +weight: 10 +categories: + - "Dark Fantasy" +tags: + - "Dark Angel" + - "Wings" + - "Jungle" + - "Bodysuit" + - "Tropical" + - "Otherworldly" + - "Dark Fantasy" + - "Raven" +--- diff --git a/content/posts/dark-cabaret-on-stone-steps/dark-cabaret-on-stone-steps.png b/content/posts/dark-cabaret-on-stone-steps/dark-cabaret-on-stone-steps.png new file mode 100644 index 0000000..3bed050 Binary files /dev/null and b/content/posts/dark-cabaret-on-stone-steps/dark-cabaret-on-stone-steps.png differ diff --git a/content/posts/dark-cabaret-on-stone-steps/index.md b/content/posts/dark-cabaret-on-stone-steps/index.md new file mode 100644 index 0000000..823740b --- /dev/null +++ b/content/posts/dark-cabaret-on-stone-steps/index.md @@ -0,0 +1,19 @@ +--- +title: "Dark Cabaret on Stone Steps" +description: "a vivid redhead in a dramatic black and red corset editorial dress reclining on shadowy stone steps flanked by gothic columns, theatrical and seductive dark fantasy fashion aesthetic" +plate: "011" +slug: "dark-cabaret-on-stone-steps" +image: "dark-cabaret-on-stone-steps.png" +weight: 11 +categories: + - "Gothic" +tags: + - "Cabaret" + - "Corset" + - "Gothic" + - "Stone Steps" + - "Columns" + - "Theatrical" + - "Dark Fantasy" + - "Seductive" +--- diff --git a/content/posts/dark-fairy-rose-throne/dark-fairy-rose-throne.png b/content/posts/dark-fairy-rose-throne/dark-fairy-rose-throne.png new file mode 100644 index 0000000..4f280d1 Binary files /dev/null and b/content/posts/dark-fairy-rose-throne/dark-fairy-rose-throne.png differ diff --git a/content/posts/dark-fairy-rose-throne/index.md b/content/posts/dark-fairy-rose-throne/index.md new file mode 100644 index 0000000..3313bae --- /dev/null +++ b/content/posts/dark-fairy-rose-throne/index.md @@ -0,0 +1,19 @@ +--- +title: "Dark Fairy Rose Throne" +description: "a fiery-haired model in structured black avant-garde couture with sheer translucent wing-like sculptural elements sitting among blood-red roses in a shadowy dark editorial setting" +plate: "012" +slug: "dark-fairy-rose-throne" +image: "dark-fairy-rose-throne.png" +weight: 12 +categories: + - "Dark Fantasy" +tags: + - "Dark Fairy" + - "Wings" + - "Roses" + - "Armor" + - "Pink Hair" + - "Thorns" + - "Dark Fantasy" + - "Purple" +--- diff --git a/content/posts/dark-forest-cyber-warrior/dark-forest-cyber-warrior.png b/content/posts/dark-forest-cyber-warrior/dark-forest-cyber-warrior.png new file mode 100644 index 0000000..049c354 Binary files /dev/null and b/content/posts/dark-forest-cyber-warrior/dark-forest-cyber-warrior.png differ diff --git a/content/posts/dark-forest-cyber-warrior/index.md b/content/posts/dark-forest-cyber-warrior/index.md new file mode 100644 index 0000000..87df722 --- /dev/null +++ b/content/posts/dark-forest-cyber-warrior/index.md @@ -0,0 +1,20 @@ +--- +title: "Dark Forest Cyber Warrior" +description: "a fierce redhead in a sleek red-and-black structured bodysuit striding through a cinematic dark setting, crimson accents and intense editorial energy channeling bold fashion power" +plate: "013" +slug: "dark-forest-cyber-warrior" +image: "dark-forest-cyber-warrior.png" +weight: 13 +categories: + - "Cyberpunk" +tags: + - "Forest" + - "Warrior" + - "Armor" + - "Fog" + - "Cyberpunk" + - "Crimson" + - "Dark" + - "Cinematic" + - "Bodysuit" +--- diff --git a/content/posts/dark-geisha-ronin/dark-geisha-ronin.png b/content/posts/dark-geisha-ronin/dark-geisha-ronin.png new file mode 100644 index 0000000..4dfd69f Binary files /dev/null and b/content/posts/dark-geisha-ronin/dark-geisha-ronin.png differ diff --git a/content/posts/dark-geisha-ronin/index.md b/content/posts/dark-geisha-ronin/index.md new file mode 100644 index 0000000..271e6d1 --- /dev/null +++ b/content/posts/dark-geisha-ronin/index.md @@ -0,0 +1,21 @@ +--- +title: "Dark Geisha Ronin" +description: "a fiery-haired model in a hybrid black samurai-kimono editorial fashion with a bold red obi standing dramatically in a smoky void, flowing hair and warrior posture projecting mythic fashion editorial power" +plate: "014" +slug: "dark-geisha-ronin" +image: "dark-geisha-ronin.png" +weight: 14 +categories: + - "Cultural" + - "Dark Fantasy" +tags: + - "Geisha" + - "Samurai" + - "Kimono" + - "Obi" + - "Dark Fantasy" + - "Warrior" + - "Japanese" + - "Mythic" + - "Smoke" +--- diff --git a/content/posts/dark-manor-corset-queen/dark-manor-corset-queen.png b/content/posts/dark-manor-corset-queen/dark-manor-corset-queen.png new file mode 100644 index 0000000..7afc1c7 Binary files /dev/null and b/content/posts/dark-manor-corset-queen/dark-manor-corset-queen.png differ diff --git a/content/posts/dark-manor-corset-queen/index.md b/content/posts/dark-manor-corset-queen/index.md new file mode 100644 index 0000000..53e0914 --- /dev/null +++ b/content/posts/dark-manor-corset-queen/index.md @@ -0,0 +1,19 @@ +--- +title: "Dark Manor Corset Queen" +description: "a statuesque redhead in an ornate black corset and lace editorial fashion standing imperiously in a candlelit dark manor interior, gothic theatrical amber light and rich shadows framing a commanding editorial" +plate: "015" +slug: "dark-manor-corset-queen" +image: "dark-manor-corset-queen.png" +weight: 15 +categories: + - "Gothic" +tags: + - "Gothic" + - "Manor" + - "Corset" + - "Lace" + - "Candlelit" + - "Commanding" + - "Amber" + - "Theatrical" +--- diff --git a/content/posts/dark-pirate-in-cobbled-alley/dark-pirate-in-cobbled-alley.png b/content/posts/dark-pirate-in-cobbled-alley/dark-pirate-in-cobbled-alley.png new file mode 100644 index 0000000..112213f Binary files /dev/null and b/content/posts/dark-pirate-in-cobbled-alley/dark-pirate-in-cobbled-alley.png differ diff --git a/content/posts/dark-pirate-in-cobbled-alley/index.md b/content/posts/dark-pirate-in-cobbled-alley/index.md new file mode 100644 index 0000000..7ec8511 --- /dev/null +++ b/content/posts/dark-pirate-in-cobbled-alley/index.md @@ -0,0 +1,20 @@ +--- +title: "Dark Pirate in Cobbled Alley" +description: "a fiery-haired model in a dark red and black structured leather editorial look standing in a gloomy atmospheric cobblestone setting at night, gothic adventure and cinematic fashion energy" +plate: "016" +slug: "dark-pirate-in-cobbled-alley" +image: "dark-pirate-in-cobbled-alley.png" +weight: 16 +categories: + - "Action" + - "Adventure" +tags: + - "Pirate" + - "Cobblestone" + - "Gothic" + - "Fog" + - "Dark" + - "Adventure" + - "Leather" + - "Swashbuckling" +--- diff --git a/content/posts/dark-sovereign-with-black-cape/dark-sovereign-with-black-cape.png b/content/posts/dark-sovereign-with-black-cape/dark-sovereign-with-black-cape.png new file mode 100644 index 0000000..a14f16a Binary files /dev/null and b/content/posts/dark-sovereign-with-black-cape/dark-sovereign-with-black-cape.png differ diff --git a/content/posts/dark-sovereign-with-black-cape/index.md b/content/posts/dark-sovereign-with-black-cape/index.md new file mode 100644 index 0000000..e065ec3 --- /dev/null +++ b/content/posts/dark-sovereign-with-black-cape/index.md @@ -0,0 +1,19 @@ +--- +title: "Dark Sovereign with Black Cape" +description: "a commanding redhead in a structured black corset and sweeping dark dramatic cape standing in a brooding gothic courtyard at night, red accents and dark lantern lighting defining the fashion villain aesthetic" +plate: "017" +slug: "dark-sovereign-with-black-cape" +image: "dark-sovereign-with-black-cape.png" +weight: 17 +categories: + - "Dark Fantasy" +tags: + - "Dark Fantasy" + - "Demon" + - "Horns" + - "Cloak" + - "Gothic" + - "Villain" + - "Courtyard" + - "Lanterns" +--- diff --git a/content/posts/dark-valkyrie-rising/dark-valkyrie-rising.png b/content/posts/dark-valkyrie-rising/dark-valkyrie-rising.png new file mode 100644 index 0000000..b458323 Binary files /dev/null and b/content/posts/dark-valkyrie-rising/dark-valkyrie-rising.png differ diff --git a/content/posts/dark-valkyrie-rising/index.md b/content/posts/dark-valkyrie-rising/index.md new file mode 100644 index 0000000..bcb38a1 --- /dev/null +++ b/content/posts/dark-valkyrie-rising/index.md @@ -0,0 +1,19 @@ +--- +title: "Dark Valkyrie Rising" +description: "a fiery-haired model in dark structured fashion armor with a sweeping crimson-lined dramatic cape standing in a gothic hall, the commanding fashion-warrior editorial exuding dark glamour" +plate: "018" +slug: "dark-valkyrie-rising" +image: "dark-valkyrie-rising.png" +weight: 18 +categories: + - "Dark Fantasy" +tags: + - "Valkyrie" + - "Wings" + - "Gothic" + - "Armor" + - "Dark Fantasy" + - "Supernatural" + - "Battle" + - "Crimson" +--- diff --git a/content/posts/demon-horns-red-throne/demon-horns-red-throne.png b/content/posts/demon-horns-red-throne/demon-horns-red-throne.png new file mode 100644 index 0000000..3e4ae0b Binary files /dev/null and b/content/posts/demon-horns-red-throne/demon-horns-red-throne.png differ diff --git a/content/posts/demon-horns-red-throne/index.md b/content/posts/demon-horns-red-throne/index.md new file mode 100644 index 0000000..ed52d7f --- /dev/null +++ b/content/posts/demon-horns-red-throne/index.md @@ -0,0 +1,20 @@ +--- +title: "Demon Horns Red Throne" +description: "a striking redhead in a sculptural black corset and sweeping crimson-lined cape posed before crimson roses, a bold avant-garde horned headpiece completing the ritualistic dark editorial" +plate: "019" +slug: "demon-horns-red-throne" +image: "demon-horns-red-throne.png" +weight: 19 +categories: + - "Dark Fantasy" +tags: + - "Demon" + - "Horns" + - "Altar" + - "Roses" + - "Cape" + - "Supernatural" + - "Ritual" + - "Gothic" + - "Dark Fantasy" +--- diff --git a/content/posts/desert-queen-under-stars/desert-queen-under-stars.png b/content/posts/desert-queen-under-stars/desert-queen-under-stars.png new file mode 100644 index 0000000..aad0c72 Binary files /dev/null and b/content/posts/desert-queen-under-stars/desert-queen-under-stars.png differ diff --git a/content/posts/desert-queen-under-stars/index.md b/content/posts/desert-queen-under-stars/index.md new file mode 100644 index 0000000..de7fe6e --- /dev/null +++ b/content/posts/desert-queen-under-stars/index.md @@ -0,0 +1,19 @@ +--- +title: "Desert Queen Under Stars" +description: "a regal redhead in a jeweled gold headpiece and sweeping crimson silk cape posed against ornate arched columns at night, her elaborate regalia bathed in deep golds and reds" +plate: "020" +slug: "desert-queen-under-stars" +image: "desert-queen-under-stars.png" +weight: 20 +categories: + - "Dark Fantasy" +tags: + - "Crown" + - "Cape" + - "Night Sky" + - "Regal" + - "Stars" + - "Columns" + - "Dark Fantasy" + - "Mythic" +--- diff --git a/content/posts/elven-enchantress-among-serpents/elven-enchantress-among-serpents.png b/content/posts/elven-enchantress-among-serpents/elven-enchantress-among-serpents.png new file mode 100644 index 0000000..8705bfa Binary files /dev/null and b/content/posts/elven-enchantress-among-serpents/elven-enchantress-among-serpents.png differ diff --git a/content/posts/elven-enchantress-among-serpents/index.md b/content/posts/elven-enchantress-among-serpents/index.md new file mode 100644 index 0000000..51a15d1 --- /dev/null +++ b/content/posts/elven-enchantress-among-serpents/index.md @@ -0,0 +1,19 @@ +--- +title: "Elven Enchantress Among Serpents" +description: "a fiery-haired model in dramatic dark fashion armor with bold jeweled accessories posing in an atmospheric jungle setting, the mysterious primal editorial mood defined by dappled filtered light" +plate: "021" +slug: "elven-enchantress-among-serpents" +image: "elven-enchantress-among-serpents.png" +weight: 21 +categories: + - "Dark Fantasy" +tags: + - "Elf" + - "White Hair" + - "Serpents" + - "Jungle" + - "Armor" + - "Dark Fantasy" + - "Mysterious" + - "Primal" +--- diff --git a/content/posts/fairytale-queen-by-night-castle/fairytale-queen-by-night-castle.png b/content/posts/fairytale-queen-by-night-castle/fairytale-queen-by-night-castle.png new file mode 100644 index 0000000..3378ad0 Binary files /dev/null and b/content/posts/fairytale-queen-by-night-castle/fairytale-queen-by-night-castle.png differ diff --git a/content/posts/fairytale-queen-by-night-castle/index.md b/content/posts/fairytale-queen-by-night-castle/index.md new file mode 100644 index 0000000..962f490 --- /dev/null +++ b/content/posts/fairytale-queen-by-night-castle/index.md @@ -0,0 +1,20 @@ +--- +title: "Fairytale Queen by Night Castle" +description: "a glamorous redhead in a layered pink and red ballgown posing on a stone terrace with a dramatically illuminated architectural backdrop at night, storybook opulence and magical romanticism" +plate: "022" +slug: "fairytale-queen-by-night-castle" +image: "fairytale-queen-by-night-castle.png" +weight: 22 +categories: + - "Fantasy" + - "Mythology" +tags: + - "Fairy Tale" + - "Ballgown" + - "Castle" + - "Princess" + - "Night" + - "Romantic" + - "Storybook" + - "Magic" +--- diff --git a/content/posts/fire-warrior-storms-the-forest/fire-warrior-storms-the-forest.png b/content/posts/fire-warrior-storms-the-forest/fire-warrior-storms-the-forest.png new file mode 100644 index 0000000..2c9b342 Binary files /dev/null and b/content/posts/fire-warrior-storms-the-forest/fire-warrior-storms-the-forest.png differ diff --git a/content/posts/fire-warrior-storms-the-forest/index.md b/content/posts/fire-warrior-storms-the-forest/index.md new file mode 100644 index 0000000..8679163 --- /dev/null +++ b/content/posts/fire-warrior-storms-the-forest/index.md @@ -0,0 +1,19 @@ +--- +title: "Fire Warrior Storms the Forest" +description: "a fierce redhead in gleaming dark structured editorial couture wielding a sleek prop blade amid a cinematic fog-laden forest at night, fiery dramatic atmosphere in a battle-ready fashion moment" +plate: "023" +slug: "fire-warrior-storms-the-forest" +image: "fire-warrior-storms-the-forest.png" +weight: 23 +categories: + - "Dark Fantasy" +tags: + - "Warrior" + - "Fire" + - "Forest" + - "Armor" + - "Glowing Blade" + - "Dark Fantasy" + - "Battle" + - "Fog" +--- diff --git a/content/posts/firestorm-city-warrior/firestorm-city-warrior.png b/content/posts/firestorm-city-warrior/firestorm-city-warrior.png new file mode 100644 index 0000000..23c4f5b Binary files /dev/null and b/content/posts/firestorm-city-warrior/firestorm-city-warrior.png differ diff --git a/content/posts/firestorm-city-warrior/index.md b/content/posts/firestorm-city-warrior/index.md new file mode 100644 index 0000000..f5251cf --- /dev/null +++ b/content/posts/firestorm-city-warrior/index.md @@ -0,0 +1,21 @@ +--- +title: "Firestorm City Warrior" +description: "a fiery-haired model in black structured editorial fashion standing against a blazing red and orange atmospheric cityscape at night, her hair catching the fire-glow in an intense high-fashion editorial" +plate: "024" +slug: "firestorm-city-warrior" +image: "firestorm-city-warrior.png" +weight: 24 +categories: + - "Action" + - "Urban" +tags: + - "Fire" + - "City" + - "Warrior" + - "Tactical" + - "Night" + - "Flames" + - "Action" + - "Intense" + - "Embers" +--- diff --git a/content/posts/floral-silk-urban-dusk/floral-silk-urban-dusk.png b/content/posts/floral-silk-urban-dusk/floral-silk-urban-dusk.png new file mode 100644 index 0000000..cbe0d41 Binary files /dev/null and b/content/posts/floral-silk-urban-dusk/floral-silk-urban-dusk.png differ diff --git a/content/posts/floral-silk-urban-dusk/index.md b/content/posts/floral-silk-urban-dusk/index.md new file mode 100644 index 0000000..6f61b24 --- /dev/null +++ b/content/posts/floral-silk-urban-dusk/index.md @@ -0,0 +1,20 @@ +--- +title: "Floral Silk Urban Dusk" +description: "a flame-haired model in an elegant black kimono with large floral motifs standing against a vivid neon cityscape backdrop, sultry dramatic fashion merging high couture with Tokyo night street aesthetics" +plate: "025" +slug: "floral-silk-urban-dusk" +image: "floral-silk-urban-dusk.png" +weight: 25 +categories: + - "Cultural" +tags: + - "Kimono" + - "Floral" + - "Tokyo" + - "Neon" + - "City" + - "Dusk" + - "Fashion" + - "Japanese" + - "Sultry" +--- diff --git a/content/posts/forest-fairy-in-gold/forest-fairy-in-gold.png b/content/posts/forest-fairy-in-gold/forest-fairy-in-gold.png new file mode 100644 index 0000000..f2acb60 Binary files /dev/null and b/content/posts/forest-fairy-in-gold/forest-fairy-in-gold.png differ diff --git a/content/posts/forest-fairy-in-gold/index.md b/content/posts/forest-fairy-in-gold/index.md new file mode 100644 index 0000000..87d3132 --- /dev/null +++ b/content/posts/forest-fairy-in-gold/index.md @@ -0,0 +1,20 @@ +--- +title: "Forest Fairy in Gold" +description: "a radiant redhead in a flowing golden editorial fairy dress posing with sheer iridescent wing accessories in an enchanted forest setting with soft pink blossoms and dreamlike light" +plate: "026" +slug: "forest-fairy-in-gold" +image: "forest-fairy-in-gold.png" +weight: 26 +categories: + - "Fantasy" + - "Mythology" +tags: + - "Fairy" + - "Forest" + - "Wings" + - "Enchanted" + - "Golden Dress" + - "Magical" + - "Blossoms" + - "Dreamlike" +--- diff --git a/content/posts/futuristic-warrior-rain-stance/futuristic-warrior-rain-stance.png b/content/posts/futuristic-warrior-rain-stance/futuristic-warrior-rain-stance.png new file mode 100644 index 0000000..d2bec25 Binary files /dev/null and b/content/posts/futuristic-warrior-rain-stance/futuristic-warrior-rain-stance.png differ diff --git a/content/posts/futuristic-warrior-rain-stance/index.md b/content/posts/futuristic-warrior-rain-stance/index.md new file mode 100644 index 0000000..d946027 --- /dev/null +++ b/content/posts/futuristic-warrior-rain-stance/index.md @@ -0,0 +1,19 @@ +--- +title: "Futuristic Warrior Rain Stance" +description: "a fiery-haired model in sleek teal-and-black structured fashion couture standing poised in a rain-drenched architectural setting, resolute expression and glistening rain creating tense action-ready fashion atmosphere" +plate: "027" +slug: "futuristic-warrior-rain-stance" +image: "futuristic-warrior-rain-stance.png" +weight: 27 +categories: + - "Sci-Fi" +tags: + - "Sci-Fi" + - "Armor" + - "Rain" + - "Warrior" + - "Teal" + - "Action" + - "Futuristic" + - "Resolute" +--- diff --git a/content/posts/garden-glamour-in-black-latex/garden-glamour-in-black-latex.png b/content/posts/garden-glamour-in-black-latex/garden-glamour-in-black-latex.png new file mode 100644 index 0000000..f9cc24e Binary files /dev/null and b/content/posts/garden-glamour-in-black-latex/garden-glamour-in-black-latex.png differ diff --git a/content/posts/garden-glamour-in-black-latex/index.md b/content/posts/garden-glamour-in-black-latex/index.md new file mode 100644 index 0000000..11ce3f4 --- /dev/null +++ b/content/posts/garden-glamour-in-black-latex/index.md @@ -0,0 +1,20 @@ +--- +title: "Garden Glamour in Black Latex" +description: "a vibrant redhead in a glossy black latex crop top and mini skirt posing confidently amid a colorful flower garden, radiating playful sensuality against the lush floral backdrop" +plate: "028" +slug: "garden-glamour-in-black-latex" +image: "garden-glamour-in-black-latex.png" +weight: 28 +categories: + - "Boudoir" + - "Glamour" +tags: + - "Latex" + - "Garden" + - "Floral" + - "Glamour" + - "Sensual" + - "Playful" + - "Black" + - "Outdoor" +--- diff --git a/content/posts/garden-lantern-twilight/garden-lantern-twilight.png b/content/posts/garden-lantern-twilight/garden-lantern-twilight.png new file mode 100644 index 0000000..9aaa29f Binary files /dev/null and b/content/posts/garden-lantern-twilight/garden-lantern-twilight.png differ diff --git a/content/posts/garden-lantern-twilight/index.md b/content/posts/garden-lantern-twilight/index.md new file mode 100644 index 0000000..54ce69d --- /dev/null +++ b/content/posts/garden-lantern-twilight/index.md @@ -0,0 +1,20 @@ +--- +title: "Garden Lantern Twilight" +description: "a fiery-haired model in a soft floral editorial dress standing in a beautifully lit Japanese garden at dusk, surrounded by blooming flowers and glowing stone lanterns in a peaceful romantic fashion editorial" +plate: "029" +slug: "garden-lantern-twilight" +image: "garden-lantern-twilight.png" +weight: 29 +categories: + - "Cultural" + - "Romantic" +tags: + - "Japanese" + - "Garden" + - "Lanterns" + - "Dusk" + - "Floral" + - "Romantic" + - "Peaceful" + - "Fairy Tale" +--- diff --git a/content/posts/glamorous-bar-night-out/glamorous-bar-night-out.png b/content/posts/glamorous-bar-night-out/glamorous-bar-night-out.png new file mode 100644 index 0000000..a4172e9 Binary files /dev/null and b/content/posts/glamorous-bar-night-out/glamorous-bar-night-out.png differ diff --git a/content/posts/glamorous-bar-night-out/index.md b/content/posts/glamorous-bar-night-out/index.md new file mode 100644 index 0000000..a05d84b --- /dev/null +++ b/content/posts/glamorous-bar-night-out/index.md @@ -0,0 +1,18 @@ +--- +title: "Glamorous Bar Night Out" +description: "a vibrant redhead in a sparkling pink mini dress posing confidently at a neon-lit bar, warm magenta and purple lighting creating a lush upscale nightlife fashion editorial" +plate: "030" +slug: "glamorous-bar-night-out" +image: "glamorous-bar-night-out.png" +weight: 30 +categories: + - "Nightlife" +tags: + - "Bar" + - "Cocktail" + - "Neon Lights" + - "Nightclub" + - "Glamour" + - "Pink Dress" + - "Nightlife" +--- diff --git a/content/posts/goth-latex-night-stand/goth-latex-night-stand.png b/content/posts/goth-latex-night-stand/goth-latex-night-stand.png new file mode 100644 index 0000000..e0c4da0 Binary files /dev/null and b/content/posts/goth-latex-night-stand/goth-latex-night-stand.png differ diff --git a/content/posts/goth-latex-night-stand/index.md b/content/posts/goth-latex-night-stand/index.md new file mode 100644 index 0000000..8d37f88 --- /dev/null +++ b/content/posts/goth-latex-night-stand/index.md @@ -0,0 +1,19 @@ +--- +title: "Goth Latex Night Stand" +description: "a flame-haired model in an elegant black latex editorial bodysuit with long gloves and thigh-high stockings posing in a dimly lit gothic interior, composed sophisticated dark glamour" +plate: "031" +slug: "goth-latex-night-stand" +image: "goth-latex-night-stand.png" +weight: 31 +categories: + - "Gothic" +tags: + - "Gothic" + - "Latex" + - "Gloves" + - "Stockings" + - "Dark Glamour" + - "Sophisticated" + - "Elegant" + - "Dimly Lit" +--- diff --git a/content/posts/gothic-arch-black-elegance/gothic-arch-black-elegance.png b/content/posts/gothic-arch-black-elegance/gothic-arch-black-elegance.png new file mode 100644 index 0000000..ef48d05 Binary files /dev/null and b/content/posts/gothic-arch-black-elegance/gothic-arch-black-elegance.png differ diff --git a/content/posts/gothic-arch-black-elegance/index.md b/content/posts/gothic-arch-black-elegance/index.md new file mode 100644 index 0000000..416d8ec --- /dev/null +++ b/content/posts/gothic-arch-black-elegance/index.md @@ -0,0 +1,19 @@ +--- +title: "Gothic Arch Black Elegance" +description: "a slender redhead in a flowing black sleeveless editorial dress turning gracefully within a dark gothic stone archway, melancholic ethereal fashion quality with muted tones and dramatic architectural framing" +plate: "032" +slug: "gothic-arch-black-elegance" +image: "gothic-arch-black-elegance.png" +weight: 32 +categories: + - "Gothic" +tags: + - "Gothic" + - "Archway" + - "Elegant" + - "Dark" + - "Ethereal" + - "Melancholic" + - "Stone" + - "Architectural" +--- diff --git a/content/posts/gothic-cathedral-red-gown/gothic-cathedral-red-gown.png b/content/posts/gothic-cathedral-red-gown/gothic-cathedral-red-gown.png new file mode 100644 index 0000000..b0a5e2e Binary files /dev/null and b/content/posts/gothic-cathedral-red-gown/gothic-cathedral-red-gown.png differ diff --git a/content/posts/gothic-cathedral-red-gown/index.md b/content/posts/gothic-cathedral-red-gown/index.md new file mode 100644 index 0000000..e12a670 --- /dev/null +++ b/content/posts/gothic-cathedral-red-gown/index.md @@ -0,0 +1,19 @@ +--- +title: "Gothic Cathedral Red Gown" +description: "a fiery-haired model in a figure-hugging red gown standing in a vaulted gothic architectural hall bathed in warm amber light, crimson dress against ancient stone creating powerful editorial atmosphere" +plate: "033" +slug: "gothic-cathedral-red-gown" +image: "gothic-cathedral-red-gown.png" +weight: 33 +categories: + - "Gothic" +tags: + - "Gothic" + - "Cathedral" + - "Red Gown" + - "Amber" + - "Dark Romance" + - "Pillars" + - "Vaulted" + - "Elegant" +--- diff --git a/content/posts/gothic-green-enchantress/gothic-green-enchantress.png b/content/posts/gothic-green-enchantress/gothic-green-enchantress.png new file mode 100644 index 0000000..1b74022 Binary files /dev/null and b/content/posts/gothic-green-enchantress/gothic-green-enchantress.png differ diff --git a/content/posts/gothic-green-enchantress/index.md b/content/posts/gothic-green-enchantress/index.md new file mode 100644 index 0000000..acfcb31 --- /dev/null +++ b/content/posts/gothic-green-enchantress/index.md @@ -0,0 +1,19 @@ +--- +title: "Gothic Green Enchantress" +description: "a redhead in an elaborate dark structured corset ensemble with dramatic emerald-toned accessories before a shadowy atmospheric backdrop, moody violet-tinted editorial styling" +plate: "034" +slug: "gothic-green-enchantress" +image: "gothic-green-enchantress.png" +weight: 34 +categories: + - "Dark Fantasy" +tags: + - "Gothic" + - "Green Hair" + - "Manor" + - "Corset" + - "Villain" + - "Dark Fantasy" + - "Violet" + - "Atmospheric" +--- diff --git a/content/posts/gothic-hall-rock-rebel/gothic-hall-rock-rebel.png b/content/posts/gothic-hall-rock-rebel/gothic-hall-rock-rebel.png new file mode 100644 index 0000000..ac2b860 Binary files /dev/null and b/content/posts/gothic-hall-rock-rebel/gothic-hall-rock-rebel.png differ diff --git a/content/posts/gothic-hall-rock-rebel/index.md b/content/posts/gothic-hall-rock-rebel/index.md new file mode 100644 index 0000000..25ee26d --- /dev/null +++ b/content/posts/gothic-hall-rock-rebel/index.md @@ -0,0 +1,19 @@ +--- +title: "Gothic Hall Rock Rebel" +description: "a copper-haired model in a band T-shirt and black leather mini-skirt with dark thigh-highs standing in a torch-lit gothic stone hall, dark-academia rebellious fashion editorial flair" +plate: "035" +slug: "gothic-hall-rock-rebel" +image: "gothic-hall-rock-rebel.png" +weight: 35 +categories: + - "Gothic" +tags: + - "Gothic" + - "Rock" + - "Leather" + - "Dark Academia" + - "Alternative" + - "Candlelight" + - "Edgy" + - "Stone Hall" +--- diff --git a/content/posts/gothic-temptress-in-the-cathedral/gothic-temptress-in-the-cathedral.png b/content/posts/gothic-temptress-in-the-cathedral/gothic-temptress-in-the-cathedral.png new file mode 100644 index 0000000..cd42d6c Binary files /dev/null and b/content/posts/gothic-temptress-in-the-cathedral/gothic-temptress-in-the-cathedral.png differ diff --git a/content/posts/gothic-temptress-in-the-cathedral/index.md b/content/posts/gothic-temptress-in-the-cathedral/index.md new file mode 100644 index 0000000..3db72f7 --- /dev/null +++ b/content/posts/gothic-temptress-in-the-cathedral/index.md @@ -0,0 +1,19 @@ +--- +title: "Gothic Temptress in the Cathedral" +description: "a fiery-haired model in sleek black latex posing inside a grand gothic architectural setting, dramatic shadows and deep decadent dark elegance defining the editorial tone" +plate: "036" +slug: "gothic-temptress-in-the-cathedral" +image: "gothic-temptress-in-the-cathedral.png" +weight: 36 +categories: + - "Gothic" +tags: + - "Gothic" + - "Cathedral" + - "Latex" + - "Stained Glass" + - "Chandeliers" + - "Dark" + - "Decadent" + - "Elegant" +--- diff --git a/content/posts/graffiti-wall-winter-squat/graffiti-wall-winter-squat.png b/content/posts/graffiti-wall-winter-squat/graffiti-wall-winter-squat.png new file mode 100644 index 0000000..c8c22b5 Binary files /dev/null and b/content/posts/graffiti-wall-winter-squat/graffiti-wall-winter-squat.png differ diff --git a/content/posts/graffiti-wall-winter-squat/index.md b/content/posts/graffiti-wall-winter-squat/index.md new file mode 100644 index 0000000..706718d --- /dev/null +++ b/content/posts/graffiti-wall-winter-squat/index.md @@ -0,0 +1,20 @@ +--- +title: "Graffiti Wall Winter Squat" +description: "a fiery-haired model in all-black streetwear crouching before a large orange graffiti mural in a snowy urban setting, raw defiant street-art fashion editorial energy" +plate: "037" +slug: "graffiti-wall-winter-squat" +image: "graffiti-wall-winter-squat.png" +weight: 37 +categories: + - "Lifestyle" +tags: + - "Graffiti" + - "Winter" + - "Streetwear" + - "Snow" + - "Urban" + - "Street Art" + - "Defiant" + - "Orange" + - "Mural" +--- diff --git a/content/posts/highland-battle-fury/highland-battle-fury.png b/content/posts/highland-battle-fury/highland-battle-fury.png new file mode 100644 index 0000000..f0d3c31 Binary files /dev/null and b/content/posts/highland-battle-fury/highland-battle-fury.png differ diff --git a/content/posts/highland-battle-fury/index.md b/content/posts/highland-battle-fury/index.md new file mode 100644 index 0000000..d56a1cc --- /dev/null +++ b/content/posts/highland-battle-fury/index.md @@ -0,0 +1,21 @@ +--- +title: "Highland Battle Fury" +description: "a fierce redhead in silver structured fashion armor striding against a dramatic highland sky, the fur-trimmed cape and fierce editorial expression creating an epic mythological fashion moment" +plate: "038" +slug: "highland-battle-fury" +image: "highland-battle-fury.png" +weight: 38 +categories: + - "Fantasy" + - "Mythology" +tags: + - "Warrior" + - "Battle" + - "Highlands" + - "Armor" + - "Sword" + - "Storm" + - "Cape" + - "Mythological" + - "Epic" +--- diff --git a/content/posts/infernal-pirate-queen/index.md b/content/posts/infernal-pirate-queen/index.md new file mode 100644 index 0000000..b958d96 --- /dev/null +++ b/content/posts/infernal-pirate-queen/index.md @@ -0,0 +1,21 @@ +--- +title: "Infernal Pirate Queen" +description: "a fierce redhead in black theatrical fashion couture commanding a scene of dramatic orange and red ambient lighting, blazing tones and defiant posture creating explosive cinematic fashion intensity" +plate: "039" +slug: "infernal-pirate-queen" +image: "infernal-pirate-queen.png" +weight: 39 +categories: + - "Action" + - "Adventure" +tags: + - "Pirate" + - "Fire" + - "Ruins" + - "Storm" + - "Dark" + - "Action" + - "Cinematic" + - "Defiant" + - "Explosive" +--- diff --git a/content/posts/infernal-pirate-queen/infernal-pirate-queen.png b/content/posts/infernal-pirate-queen/infernal-pirate-queen.png new file mode 100644 index 0000000..327c6c5 Binary files /dev/null and b/content/posts/infernal-pirate-queen/infernal-pirate-queen.png differ diff --git a/content/posts/iron-heroine-in-the-rain/index.md b/content/posts/iron-heroine-in-the-rain/index.md new file mode 100644 index 0000000..38a87d8 --- /dev/null +++ b/content/posts/iron-heroine-in-the-rain/index.md @@ -0,0 +1,19 @@ +--- +title: "Iron Heroine in the Rain" +description: "a fiery-haired model in sleek structured editorial couture with glowing accent detailing standing in a neon-lit rainy city, cyberpunk aesthetics and powerful determined expression defining the fashion editorial" +plate: "040" +slug: "iron-heroine-in-the-rain" +image: "iron-heroine-in-the-rain.png" +weight: 40 +categories: + - "Cyberpunk" +tags: + - "Armor" + - "Rain" + - "Neon" + - "Orange Accents" + - "Cyberpunk" + - "Futuristic" + - "City" + - "Determined" +--- diff --git a/content/posts/iron-heroine-in-the-rain/iron-heroine-in-the-rain.png b/content/posts/iron-heroine-in-the-rain/iron-heroine-in-the-rain.png new file mode 100644 index 0000000..31bef13 Binary files /dev/null and b/content/posts/iron-heroine-in-the-rain/iron-heroine-in-the-rain.png differ diff --git a/content/posts/jungle-commando-sci-fi-strike/index.md b/content/posts/jungle-commando-sci-fi-strike/index.md new file mode 100644 index 0000000..3d98ec2 --- /dev/null +++ b/content/posts/jungle-commando-sci-fi-strike/index.md @@ -0,0 +1,19 @@ +--- +title: "Jungle Commando Sci-Fi Strike" +description: "a fiery-haired model in a sleek green-and-black structured fashion editorial posed against lush tropical foliage, bold graphic styling and an intense expression channeling editorial power" +plate: "041" +slug: "jungle-commando-sci-fi-strike" +image: "jungle-commando-sci-fi-strike.png" +weight: 41 +categories: + - "Sci-Fi" +tags: + - "Jungle" + - "Soldier" + - "Sci-Fi" + - "Combat Armor" + - "Rifle" + - "Military" + - "Futuristic" + - "Stealth" +--- diff --git a/content/posts/jungle-commando-sci-fi-strike/jungle-commando-sci-fi-strike.png b/content/posts/jungle-commando-sci-fi-strike/jungle-commando-sci-fi-strike.png new file mode 100644 index 0000000..d91d798 Binary files /dev/null and b/content/posts/jungle-commando-sci-fi-strike/jungle-commando-sci-fi-strike.png differ diff --git a/content/posts/jungle-horizon-tribal-queen/index.md b/content/posts/jungle-horizon-tribal-queen/index.md new file mode 100644 index 0000000..81f230c --- /dev/null +++ b/content/posts/jungle-horizon-tribal-queen/index.md @@ -0,0 +1,20 @@ +--- +title: "Jungle Horizon Tribal Queen" +description: "a regal redhead adorned in vibrant orange and gold tribal-inspired fashion couture standing on a sun-baked vantage point with a sweeping horizon view, rich earth tones and ornate jeweled styling" +plate: "042" +slug: "jungle-horizon-tribal-queen" +image: "jungle-horizon-tribal-queen.png" +weight: 42 +categories: + - "Cultural" + - "Fantasy" +tags: + - "Tribal" + - "Jungle" + - "Gold" + - "Regal" + - "Ancient" + - "Queen" + - "Ornate Jewelry" + - "Sun-Drenched" +--- diff --git a/content/posts/jungle-horizon-tribal-queen/jungle-horizon-tribal-queen.png b/content/posts/jungle-horizon-tribal-queen/jungle-horizon-tribal-queen.png new file mode 100644 index 0000000..900f326 Binary files /dev/null and b/content/posts/jungle-horizon-tribal-queen/jungle-horizon-tribal-queen.png differ diff --git a/content/posts/kimono-neon-geisha/index.md b/content/posts/kimono-neon-geisha/index.md new file mode 100644 index 0000000..a2dde76 --- /dev/null +++ b/content/posts/kimono-neon-geisha/index.md @@ -0,0 +1,19 @@ +--- +title: "Kimono Neon Geisha" +description: "a flame-haired model in a striking white kimono with bold dark patterns spreading her arms wide on a neon-blazing Japanese street, theatrical confidence radiating against warm red lanterns" +plate: "043" +slug: "kimono-neon-geisha" +image: "kimono-neon-geisha.png" +weight: 43 +categories: + - "Cultural" +tags: + - "Kimono" + - "Geisha" + - "Neon" + - "Japanese" + - "White" + - "Lanterns" + - "Theatrical" + - "Night" +--- diff --git a/content/posts/kimono-neon-geisha/kimono-neon-geisha.png b/content/posts/kimono-neon-geisha/kimono-neon-geisha.png new file mode 100644 index 0000000..ed6f036 Binary files /dev/null and b/content/posts/kimono-neon-geisha/kimono-neon-geisha.png differ diff --git a/content/posts/lantern-garden-thai-evening/index.md b/content/posts/lantern-garden-thai-evening/index.md new file mode 100644 index 0000000..dbf6062 --- /dev/null +++ b/content/posts/lantern-garden-thai-evening/index.md @@ -0,0 +1,21 @@ +--- +title: "Lantern Garden Thai Evening" +description: "a model with auburn hair in a delicate floral editorial dress standing in a warmly lit Thai-style garden at dusk, surrounded by glowing lanterns and tropical flowers in a magical serenity fashion editorial" +plate: "044" +slug: "lantern-garden-thai-evening" +image: "lantern-garden-thai-evening.png" +weight: 44 +categories: + - "Cultural" + - "Romantic" +tags: + - "Thai" + - "Garden" + - "Lanterns" + - "Dusk" + - "Floral" + - "Romantic" + - "Pavilion" + - "Tropical" + - "Cultural" +--- diff --git a/content/posts/lantern-garden-thai-evening/lantern-garden-thai-evening.png b/content/posts/lantern-garden-thai-evening/lantern-garden-thai-evening.png new file mode 100644 index 0000000..c85824a Binary files /dev/null and b/content/posts/lantern-garden-thai-evening/lantern-garden-thai-evening.png differ diff --git a/content/posts/lantern-glow-onsen-serenity/index.md b/content/posts/lantern-glow-onsen-serenity/index.md new file mode 100644 index 0000000..ec60ef9 --- /dev/null +++ b/content/posts/lantern-glow-onsen-serenity/index.md @@ -0,0 +1,21 @@ +--- +title: "Lantern Glow Onsen Serenity" +description: "a fiery-haired model in a white kimono-style editorial garment sitting peacefully in a traditional outdoor Japanese setting surrounded by warm stone and paper lanterns, tranquil quietly luminous fashion editorial" +plate: "045" +slug: "lantern-glow-onsen-serenity" +image: "lantern-glow-onsen-serenity.png" +weight: 45 +categories: + - "Cultural" + - "Romantic" +tags: + - "Onsen" + - "Kimono" + - "Lanterns" + - "Japanese" + - "Tranquil" + - "Hot Spring" + - "Serene" + - "White" + - "Elegant" +--- diff --git a/content/posts/lantern-glow-onsen-serenity/lantern-glow-onsen-serenity.png b/content/posts/lantern-glow-onsen-serenity/lantern-glow-onsen-serenity.png new file mode 100644 index 0000000..62fca64 Binary files /dev/null and b/content/posts/lantern-glow-onsen-serenity/lantern-glow-onsen-serenity.png differ diff --git a/content/posts/latex-elegance-among-hedges/index.md b/content/posts/latex-elegance-among-hedges/index.md new file mode 100644 index 0000000..4728a5b --- /dev/null +++ b/content/posts/latex-elegance-among-hedges/index.md @@ -0,0 +1,20 @@ +--- +title: "Latex Elegance Among Hedges" +description: "a striking redhead in a sleek black latex gown with a high thigh slit standing poised before manicured hedges, exuding dark glamour and composed confidence in a formal garden setting" +plate: "046" +slug: "latex-elegance-among-hedges" +image: "latex-elegance-among-hedges.png" +weight: 46 +categories: + - "Boudoir" + - "Glamour" +tags: + - "Latex" + - "Gown" + - "Hedges" + - "Estate" + - "Glamour" + - "Dark" + - "Elegant" + - "Outdoor" +--- diff --git a/content/posts/latex-elegance-among-hedges/latex-elegance-among-hedges.png b/content/posts/latex-elegance-among-hedges/latex-elegance-among-hedges.png new file mode 100644 index 0000000..aedfd99 Binary files /dev/null and b/content/posts/latex-elegance-among-hedges/latex-elegance-among-hedges.png differ diff --git a/content/posts/leather-goddess-city-twilight/index.md b/content/posts/leather-goddess-city-twilight/index.md new file mode 100644 index 0000000..7f13e2d --- /dev/null +++ b/content/posts/leather-goddess-city-twilight/index.md @@ -0,0 +1,20 @@ +--- +title: "Leather Goddess City Twilight" +description: "a poised redhead in a form-fitting black leather editorial dress and long gloves standing before grand neoclassical architecture in stormy twilight, cool composed noir-fashion elevated aesthetic" +plate: "047" +slug: "leather-goddess-city-twilight" +image: "leather-goddess-city-twilight.png" +weight: 47 +categories: + - "Urban" + - "Noir" +tags: + - "Leather" + - "Gloves" + - "Neoclassical" + - "Stormy" + - "Twilight" + - "Noir" + - "Composed" + - "City" +--- diff --git a/content/posts/leather-goddess-city-twilight/leather-goddess-city-twilight.png b/content/posts/leather-goddess-city-twilight/leather-goddess-city-twilight.png new file mode 100644 index 0000000..19abfe8 Binary files /dev/null and b/content/posts/leather-goddess-city-twilight/leather-goddess-city-twilight.png differ diff --git a/content/posts/library-power-silhouette/index.md b/content/posts/library-power-silhouette/index.md new file mode 100644 index 0000000..e3d88c5 --- /dev/null +++ b/content/posts/library-power-silhouette/index.md @@ -0,0 +1,20 @@ +--- +title: "Library Power Silhouette" +description: "a fiery-haired model in a form-fitting black lace dress standing commanding before a warmly lit private library, quiet editorial authority and elegance with rich wood tones and lamplight" +plate: "048" +slug: "library-power-silhouette" +image: "library-power-silhouette.png" +weight: 48 +categories: + - "Elegant" + - "Gothic" +tags: + - "Library" + - "Silver Hair" + - "Lace Dress" + - "Authority" + - "Elegant" + - "Lamplight" + - "Interior" + - "Sophisticated" +--- diff --git a/content/posts/library-power-silhouette/library-power-silhouette.png b/content/posts/library-power-silhouette/library-power-silhouette.png new file mode 100644 index 0000000..540514f Binary files /dev/null and b/content/posts/library-power-silhouette/library-power-silhouette.png differ diff --git a/content/posts/luxury-streetwear-noir/index.md b/content/posts/luxury-streetwear-noir/index.md new file mode 100644 index 0000000..ea1a4e4 --- /dev/null +++ b/content/posts/luxury-streetwear-noir/index.md @@ -0,0 +1,21 @@ +--- +title: "Luxury Streetwear Noir" +description: "a glamorous redhead in a tight black evening gown with a bold side slit posing beside a silver luxury vehicle on a sparkling city boulevard at night, confident urban fashion elegance" +plate: "049" +slug: "luxury-streetwear-noir" +image: "luxury-streetwear-noir.png" +weight: 49 +categories: + - "Luxury" + - "Lifestyle" +tags: + - "Luxury" + - "Car" + - "Evening Gown" + - "City" + - "Night" + - "Glamour" + - "Noir" + - "Mercedes" + - "Elegant" +--- diff --git a/content/posts/luxury-streetwear-noir/luxury-streetwear-noir.png b/content/posts/luxury-streetwear-noir/luxury-streetwear-noir.png new file mode 100644 index 0000000..6f86b52 Binary files /dev/null and b/content/posts/luxury-streetwear-noir/luxury-streetwear-noir.png differ diff --git a/content/posts/midnight-motorcycle-urban-rider/index.md b/content/posts/midnight-motorcycle-urban-rider/index.md new file mode 100644 index 0000000..b430703 --- /dev/null +++ b/content/posts/midnight-motorcycle-urban-rider/index.md @@ -0,0 +1,20 @@ +--- +title: "Midnight Motorcycle Urban Rider" +description: "a fiery-haired model in sleek structured editorial fashion crouching beside a powerful motorcycle on a rain-lit city street, the dramatic halo of headlights creating a cinematic speed-and-danger fashion editorial" +plate: "050" +slug: "midnight-motorcycle-urban-rider" +image: "midnight-motorcycle-urban-rider.png" +weight: 50 +categories: + - "Action" + - "Urban" +tags: + - "Motorcycle" + - "Rain" + - "Armor" + - "Boots" + - "City" + - "Action" + - "Cinematic" + - "Speed" +--- diff --git a/content/posts/midnight-motorcycle-urban-rider/midnight-motorcycle-urban-rider.png b/content/posts/midnight-motorcycle-urban-rider/midnight-motorcycle-urban-rider.png new file mode 100644 index 0000000..e1cf792 Binary files /dev/null and b/content/posts/midnight-motorcycle-urban-rider/midnight-motorcycle-urban-rider.png differ diff --git a/content/posts/midnight-rain-dancer/index.md b/content/posts/midnight-rain-dancer/index.md new file mode 100644 index 0000000..fbac404 --- /dev/null +++ b/content/posts/midnight-rain-dancer/index.md @@ -0,0 +1,20 @@ +--- +title: "Midnight Rain Dancer" +description: "a fiery-haired model in a sleek black latex editorial swimsuit posing dramatically on a rain-slicked city street at night, warm golden street lights reflecting off wet pavement in moody fashion atmosphere" +plate: "051" +slug: "midnight-rain-dancer" +image: "midnight-rain-dancer.png" +weight: 51 +categories: + - "Urban" + - "Noir" +tags: + - "Latex" + - "Rain" + - "City" + - "Night" + - "Dance" + - "Streetlights" + - "Golden" + - "Dramatic" +--- diff --git a/content/posts/midnight-rain-dancer/midnight-rain-dancer.png b/content/posts/midnight-rain-dancer/midnight-rain-dancer.png new file mode 100644 index 0000000..e961b39 Binary files /dev/null and b/content/posts/midnight-rain-dancer/midnight-rain-dancer.png differ diff --git a/content/posts/monsoon-rain-dance/index.md b/content/posts/monsoon-rain-dance/index.md new file mode 100644 index 0000000..943fa3a --- /dev/null +++ b/content/posts/monsoon-rain-dance/index.md @@ -0,0 +1,20 @@ +--- +title: "Monsoon Rain Dance" +description: "a fiery-haired model in jeweled tribal-inspired editorial fashion stretching her arms skyward amid a dramatic rain-soaked urban night scene, raw energy and warrior-goddess editorial mood" +plate: "052" +slug: "monsoon-rain-dance" +image: "monsoon-rain-dance.png" +weight: 52 +categories: + - "Cultural" + - "Fantasy" +tags: + - "Tribal" + - "Rain" + - "Jeweled" + - "Warrior Goddess" + - "Urban Night" + - "Energy" + - "Dance" + - "Monsoon" +--- diff --git a/content/posts/monsoon-rain-dance/monsoon-rain-dance.png b/content/posts/monsoon-rain-dance/monsoon-rain-dance.png new file mode 100644 index 0000000..bf38789 Binary files /dev/null and b/content/posts/monsoon-rain-dance/monsoon-rain-dance.png differ diff --git a/content/posts/moonlit-bridal-sea-column/index.md b/content/posts/moonlit-bridal-sea-column/index.md new file mode 100644 index 0000000..4255ed0 --- /dev/null +++ b/content/posts/moonlit-bridal-sea-column/index.md @@ -0,0 +1,21 @@ +--- +title: "Moonlit Bridal Sea Column" +description: "a flame-haired model in a bespoke white silk bridal gown standing between stone columns overlooking a moonlit sea at dusk, a silver tiara catching the last light in a timeless bridal editorial" +plate: "053" +slug: "moonlit-bridal-sea-column" +image: "moonlit-bridal-sea-column.png" +weight: 53 +categories: + - "Nature" + - "Romantic" +tags: + - "Bridal" + - "Moonlit" + - "Sea" + - "Columns" + - "Tiara" + - "Romantic" + - "Lavender" + - "Gold" + - "Timeless" +--- diff --git a/content/posts/moonlit-bridal-sea-column/moonlit-bridal-sea-column.png b/content/posts/moonlit-bridal-sea-column/moonlit-bridal-sea-column.png new file mode 100644 index 0000000..e5b85ff Binary files /dev/null and b/content/posts/moonlit-bridal-sea-column/moonlit-bridal-sea-column.png differ diff --git a/content/posts/neon-alley-kimono-tattoo/index.md b/content/posts/neon-alley-kimono-tattoo/index.md new file mode 100644 index 0000000..3934823 --- /dev/null +++ b/content/posts/neon-alley-kimono-tattoo/index.md @@ -0,0 +1,19 @@ +--- +title: "Neon Alley Kimono Tattoo" +description: "a fiery-haired model with an elaborate back tattoo in a modern black-and-white editorial kimono turning away on a neon-lit Japanese street at night, traditional fashion blended with urban body-art edge" +plate: "054" +slug: "neon-alley-kimono-tattoo" +image: "neon-alley-kimono-tattoo.png" +weight: 54 +categories: + - "Cultural" +tags: + - "Kimono" + - "Tattoo" + - "Japanese" + - "Neon" + - "Urban" + - "Back Tattoo" + - "Night" + - "Fashion" +--- diff --git a/content/posts/neon-alley-kimono-tattoo/neon-alley-kimono-tattoo.png b/content/posts/neon-alley-kimono-tattoo/neon-alley-kimono-tattoo.png new file mode 100644 index 0000000..2ba54f6 Binary files /dev/null and b/content/posts/neon-alley-kimono-tattoo/neon-alley-kimono-tattoo.png differ diff --git a/content/posts/neon-kimono-city-night/index.md b/content/posts/neon-kimono-city-night/index.md new file mode 100644 index 0000000..3389ab4 --- /dev/null +++ b/content/posts/neon-kimono-city-night/index.md @@ -0,0 +1,19 @@ +--- +title: "Neon Kimono City Night" +description: "a fiery-haired model in a traditional white kimono with a modern editorial twist posing on a neon-lit Tokyo street at night, classic Japanese fashion and glowing city signage creating vivid cultural fashion contrast" +plate: "056" +slug: "neon-kimono-city-night" +image: "neon-kimono-city-night.png" +weight: 56 +categories: + - "Cultural" +tags: + - "Kimono" + - "Tokyo" + - "Neon" + - "Tattoo" + - "Japanese" + - "Night" + - "Urban" + - "Cultural Contrast" +--- diff --git a/content/posts/neon-kimono-city-night/neon-kimono-city-night.png b/content/posts/neon-kimono-city-night/neon-kimono-city-night.png new file mode 100644 index 0000000..8e548f0 Binary files /dev/null and b/content/posts/neon-kimono-city-night/neon-kimono-city-night.png differ diff --git a/content/posts/neon-rain-cyber-siren/index.md b/content/posts/neon-rain-cyber-siren/index.md new file mode 100644 index 0000000..bfcac54 --- /dev/null +++ b/content/posts/neon-rain-cyber-siren/index.md @@ -0,0 +1,19 @@ +--- +title: "Neon Rain Cyber Siren" +description: "a flame-haired model in a sleek violet and blue bodysuit posing in a rain-soaked neon-drenched urban setting at night, electric color and reflective wet ground creating a futuristic editorial" +plate: "057" +slug: "neon-rain-cyber-siren" +image: "neon-rain-cyber-siren.png" +weight: 57 +categories: + - "Cyberpunk" +tags: + - "Cyberpunk" + - "Rain" + - "Neon" + - "Bodysuit" + - "Blue" + - "Violet" + - "Futuristic" + - "Night" +--- diff --git a/content/posts/neon-rain-cyber-siren/neon-rain-cyber-siren.png b/content/posts/neon-rain-cyber-siren/neon-rain-cyber-siren.png new file mode 100644 index 0000000..7d10689 Binary files /dev/null and b/content/posts/neon-rain-cyber-siren/neon-rain-cyber-siren.png differ diff --git a/content/posts/neon-street-cyber-punk/index.md b/content/posts/neon-street-cyber-punk/index.md new file mode 100644 index 0000000..ab16837 --- /dev/null +++ b/content/posts/neon-street-cyber-punk/index.md @@ -0,0 +1,19 @@ +--- +title: "Neon Street Cyber Punk" +description: "a vivid redhead in a colorful fashion-forward puffer jacket and neon-accented co-ord standing on a lively neon-lit street at night, bold futuristic street styling and vibrant city energy" +plate: "058" +slug: "neon-street-cyber-punk" +image: "neon-street-cyber-punk.png" +weight: 58 +categories: + - "Cyberpunk" +tags: + - "Neon" + - "Street" + - "Cyberpunk" + - "Futuristic" + - "Nightlife" + - "Colorful" + - "City" + - "Playful" +--- diff --git a/content/posts/neon-street-cyber-punk/neon-street-cyber-punk.png b/content/posts/neon-street-cyber-punk/neon-street-cyber-punk.png new file mode 100644 index 0000000..d75ac8e Binary files /dev/null and b/content/posts/neon-street-cyber-punk/neon-street-cyber-punk.png differ diff --git a/content/posts/neon-vigilante-rainy-streets/index.md b/content/posts/neon-vigilante-rainy-streets/index.md new file mode 100644 index 0000000..97f9a7a --- /dev/null +++ b/content/posts/neon-vigilante-rainy-streets/index.md @@ -0,0 +1,21 @@ +--- +title: "Neon Vigilante Rainy Streets" +description: "a fierce fiery-haired model in a black-and-orange dramatic cape and structured editorial fashion striding through rain-slicked city streets under orange streetlights, cinematic action-fashion editorial" +plate: "059" +slug: "neon-vigilante-rainy-streets" +image: "neon-vigilante-rainy-streets.png" +weight: 59 +categories: + - "Action" + - "Urban" +tags: + - "Superhero" + - "Rain" + - "Neon" + - "City" + - "Cape" + - "Combat" + - "Action" + - "Vigilante" + - "Orange" +--- diff --git a/content/posts/neon-vigilante-rainy-streets/neon-vigilante-rainy-streets.png b/content/posts/neon-vigilante-rainy-streets/neon-vigilante-rainy-streets.png new file mode 100644 index 0000000..1cbf7ec Binary files /dev/null and b/content/posts/neon-vigilante-rainy-streets/neon-vigilante-rainy-streets.png differ diff --git a/content/posts/night-market-temptress/index.md b/content/posts/night-market-temptress/index.md new file mode 100644 index 0000000..0106dcd --- /dev/null +++ b/content/posts/night-market-temptress/index.md @@ -0,0 +1,19 @@ +--- +title: "Night Market Temptress" +description: "a flame-haired model in a black qipao-inspired editorial fashion leaning forward at a vibrant Asian night market surrounded by colorful lanterns and festive neon lights, vivid cultural fashion contrast" +plate: "060" +slug: "night-market-temptress" +image: "night-market-temptress.png" +weight: 60 +categories: + - "Cultural" +tags: + - "Tattoo" + - "Pink Hair" + - "Qipao" + - "Night Market" + - "Lanterns" + - "Neon" + - "Asian" + - "Festival" +--- diff --git a/content/posts/night-market-temptress/night-market-temptress.png b/content/posts/night-market-temptress/night-market-temptress.png new file mode 100644 index 0000000..2d540dc Binary files /dev/null and b/content/posts/night-market-temptress/night-market-temptress.png differ diff --git a/content/posts/noir-trench-coat-phantom/index.md b/content/posts/noir-trench-coat-phantom/index.md new file mode 100644 index 0000000..7cce410 --- /dev/null +++ b/content/posts/noir-trench-coat-phantom/index.md @@ -0,0 +1,20 @@ +--- +title: "Noir Trench Coat Phantom" +description: "a commanding fiery-haired model in a long black trench coat standing in a rain-lit street at night, amber and grey tones of wet pavement and buildings reinforcing a classic noir fashion editorial" +plate: "061" +slug: "noir-trench-coat-phantom" +image: "noir-trench-coat-phantom.png" +weight: 61 +categories: + - "Urban" + - "Noir" +tags: + - "Noir" + - "Trench Coat" + - "Rain" + - "Night" + - "Silhouette" + - "Cinematic" + - "Amber Tones" + - "Street" +--- diff --git a/content/posts/noir-trench-coat-phantom/noir-trench-coat-phantom.png b/content/posts/noir-trench-coat-phantom/noir-trench-coat-phantom.png new file mode 100644 index 0000000..b54edf9 Binary files /dev/null and b/content/posts/noir-trench-coat-phantom/noir-trench-coat-phantom.png differ diff --git a/content/posts/norse-shield-maiden-vista/index.md b/content/posts/norse-shield-maiden-vista/index.md new file mode 100644 index 0000000..60297eb --- /dev/null +++ b/content/posts/norse-shield-maiden-vista/index.md @@ -0,0 +1,21 @@ +--- +title: "Norse Shield Maiden Vista" +description: "a redhead in layered leather and fur editorial fashion armor standing against a sweeping snow-dusted mountain landscape, stoic Scandinavian-inspired editorial radiating cold-weather fashion power" +plate: "062" +slug: "norse-shield-maiden-vista" +image: "norse-shield-maiden-vista.png" +weight: 62 +categories: + - "Fantasy" + - "Mythology" +tags: + - "Viking" + - "Shield Maiden" + - "Spear" + - "Armor" + - "Mountains" + - "Snow" + - "Norse" + - "Nordic" + - "Stoic" +--- diff --git a/content/posts/norse-shield-maiden-vista/norse-shield-maiden-vista.png b/content/posts/norse-shield-maiden-vista/norse-shield-maiden-vista.png new file mode 100644 index 0000000..87757d8 Binary files /dev/null and b/content/posts/norse-shield-maiden-vista/norse-shield-maiden-vista.png differ diff --git a/content/posts/paris-bridge-crimson-dusk/index.md b/content/posts/paris-bridge-crimson-dusk/index.md new file mode 100644 index 0000000..c9ab9d8 --- /dev/null +++ b/content/posts/paris-bridge-crimson-dusk/index.md @@ -0,0 +1,20 @@ +--- +title: "Paris Bridge Crimson Dusk" +description: "a poised redhead in a dark structured military-style jacket with a bold red necktie standing before an illuminated Parisian bridge at night, refined cinematic editorial with cool blue-gold city tones" +plate: "063" +slug: "paris-bridge-crimson-dusk" +image: "paris-bridge-crimson-dusk.png" +weight: 63 +categories: + - "Urban" + - "Noir" +tags: + - "Paris" + - "Eiffel Tower" + - "Bridge" + - "Military Jacket" + - "Night" + - "Cinematic" + - "City" + - "Refined" +--- diff --git a/content/posts/paris-bridge-crimson-dusk/paris-bridge-crimson-dusk.png b/content/posts/paris-bridge-crimson-dusk/paris-bridge-crimson-dusk.png new file mode 100644 index 0000000..42b8dc8 Binary files /dev/null and b/content/posts/paris-bridge-crimson-dusk/paris-bridge-crimson-dusk.png differ diff --git a/content/posts/pink-goth-among-pillars/index.md b/content/posts/pink-goth-among-pillars/index.md new file mode 100644 index 0000000..6a80dfd --- /dev/null +++ b/content/posts/pink-goth-among-pillars/index.md @@ -0,0 +1,19 @@ +--- +title: "Pink Goth Among Pillars" +description: "a redhead in a shiny black latex dress standing amid stone columns under dramatic violet evening light, candles flickering as she gazes back with knowing editorial confidence" +plate: "064" +slug: "pink-goth-among-pillars" +image: "pink-goth-among-pillars.png" +weight: 64 +categories: + - "Gothic" +tags: + - "Gothic" + - "Pink Hair" + - "Latex" + - "Columns" + - "Ruins" + - "Candles" + - "Violet" + - "Night" +--- diff --git a/content/posts/pink-goth-among-pillars/pink-goth-among-pillars.png b/content/posts/pink-goth-among-pillars/pink-goth-among-pillars.png new file mode 100644 index 0000000..6d32f19 Binary files /dev/null and b/content/posts/pink-goth-among-pillars/pink-goth-among-pillars.png differ diff --git a/content/posts/pixie-in-blue-command-center/index.md b/content/posts/pixie-in-blue-command-center/index.md new file mode 100644 index 0000000..cbb3f5c --- /dev/null +++ b/content/posts/pixie-in-blue-command-center/index.md @@ -0,0 +1,19 @@ +--- +title: "Pixie in Blue Command Center" +description: "a playful fiery-haired model in a bright cobalt blue form-fitting editorial bodysuit posing in a sleek futuristic interior setting, vibrant blue contrasting warm auburn curls in a comic-book fashion editorial" +plate: "065" +slug: "pixie-in-blue-command-center" +image: "pixie-in-blue-command-center.png" +weight: 65 +categories: + - "Sci-Fi" +tags: + - "Sci-Fi" + - "Bodysuit" + - "Command Room" + - "Futuristic" + - "Blue" + - "Comic Book" + - "Heroine" + - "Playful" +--- diff --git a/content/posts/pixie-in-blue-command-center/pixie-in-blue-command-center.png b/content/posts/pixie-in-blue-command-center/pixie-in-blue-command-center.png new file mode 100644 index 0000000..a3db763 Binary files /dev/null and b/content/posts/pixie-in-blue-command-center/pixie-in-blue-command-center.png differ diff --git a/content/posts/poolside-sunset-meditation/index.md b/content/posts/poolside-sunset-meditation/index.md new file mode 100644 index 0000000..9f1775b --- /dev/null +++ b/content/posts/poolside-sunset-meditation/index.md @@ -0,0 +1,19 @@ +--- +title: "Poolside Sunset Meditation" +description: "a fiery-haired model in a pink bikini sitting cross-legged in a serene pose beside a tropical pool at golden hour, blissful palm-tree editorial with radiant sunset sky" +plate: "066" +slug: "poolside-sunset-meditation" +image: "poolside-sunset-meditation.png" +weight: 66 +categories: + - "Lifestyle" +tags: + - "Pool" + - "Sunset" + - "Meditation" + - "Bikini" + - "Tropical" + - "Golden Hour" + - "Serene" + - "Palm Trees" +--- diff --git a/content/posts/poolside-sunset-meditation/poolside-sunset-meditation.png b/content/posts/poolside-sunset-meditation/poolside-sunset-meditation.png new file mode 100644 index 0000000..bf9814c Binary files /dev/null and b/content/posts/poolside-sunset-meditation/poolside-sunset-meditation.png differ diff --git a/content/posts/rain-city-cyber-strike/index.md b/content/posts/rain-city-cyber-strike/index.md new file mode 100644 index 0000000..30c7687 --- /dev/null +++ b/content/posts/rain-city-cyber-strike/index.md @@ -0,0 +1,19 @@ +--- +title: "Rain City Cyber Strike" +description: "a battle-ready fiery-haired model in a sleek structured editorial fashion suit crouching dynamically on a rain-slicked city street glowing with street lights, intense cyberpunk action fashion" +plate: "067" +slug: "rain-city-cyber-strike" +image: "rain-city-cyber-strike.png" +weight: 67 +categories: + - "Cyberpunk" +tags: + - "Rain" + - "City" + - "Armor" + - "Cyberpunk" + - "Action" + - "Street Lights" + - "Crouching" + - "Gritty" +--- diff --git a/content/posts/rain-city-cyber-strike/rain-city-cyber-strike.png b/content/posts/rain-city-cyber-strike/rain-city-cyber-strike.png new file mode 100644 index 0000000..2404fd3 Binary files /dev/null and b/content/posts/rain-city-cyber-strike/rain-city-cyber-strike.png differ diff --git a/content/posts/rain-drenched-voodoo-warrior/index.md b/content/posts/rain-drenched-voodoo-warrior/index.md new file mode 100644 index 0000000..ab23312 --- /dev/null +++ b/content/posts/rain-drenched-voodoo-warrior/index.md @@ -0,0 +1,21 @@ +--- +title: "Rain-Drenched Voodoo Warrior" +description: "a fiery-haired model in sleek black editorial fashion posing with a dramatic sculptural staff prop in a rain-soaked neon-lit urban night, dark street mysticism with rain catching city light" +plate: "068" +slug: "rain-drenched-voodoo-warrior" +image: "rain-drenched-voodoo-warrior.png" +weight: 68 +categories: + - "Urban" + - "Noir" +tags: + - "Voodoo" + - "Rain" + - "City" + - "Latex" + - "Staff" + - "Mysticism" + - "Neon" + - "Dark" + - "Night" +--- diff --git a/content/posts/rain-drenched-voodoo-warrior/rain-drenched-voodoo-warrior.png b/content/posts/rain-drenched-voodoo-warrior/rain-drenched-voodoo-warrior.png new file mode 100644 index 0000000..71993ec Binary files /dev/null and b/content/posts/rain-drenched-voodoo-warrior/rain-drenched-voodoo-warrior.png differ diff --git a/content/posts/rain-night-action-kick/index.md b/content/posts/rain-night-action-kick/index.md new file mode 100644 index 0000000..2e37d5e --- /dev/null +++ b/content/posts/rain-night-action-kick/index.md @@ -0,0 +1,20 @@ +--- +title: "Rain Night Action Kick" +description: "a dynamic redhead in a sleek black editorial bodysuit striking a dramatic pose in a rain-drenched dark setting, kinetic composition and moody lighting capturing a thrilling high-fashion moment" +plate: "069" +slug: "rain-night-action-kick" +image: "rain-night-action-kick.png" +weight: 69 +categories: + - "Action" + - "Urban" +tags: + - "Action" + - "Rain" + - "Kick" + - "Combat" + - "Alley" + - "Martial Arts" + - "Dynamic" + - "Night" +--- diff --git a/content/posts/rain-night-action-kick/rain-night-action-kick.png b/content/posts/rain-night-action-kick/rain-night-action-kick.png new file mode 100644 index 0000000..1e386b4 Binary files /dev/null and b/content/posts/rain-night-action-kick/rain-night-action-kick.png differ diff --git a/content/posts/rainy-city-badass/index.md b/content/posts/rainy-city-badass/index.md new file mode 100644 index 0000000..b48f68d --- /dev/null +++ b/content/posts/rainy-city-badass/index.md @@ -0,0 +1,21 @@ +--- +title: "Rainy City Badass" +description: "a fiery-haired model in a black leather jacket and thigh-high boots striking a defiant pose on a rain-soaked city street at night, blurred neon lights painting the wet asphalt in bold street fashion editorial" +plate: "070" +slug: "rainy-city-badass" +image: "rainy-city-badass.png" +weight: 70 +categories: + - "Urban" + - "Noir" +tags: + - "Leather Jacket" + - "Rain" + - "City" + - "Boots" + - "Night" + - "Neon" + - "Defiant" + - "Noir" + - "Street" +--- diff --git a/content/posts/rainy-city-badass/rainy-city-badass.png b/content/posts/rainy-city-badass/rainy-city-badass.png new file mode 100644 index 0000000..23c3eaa Binary files /dev/null and b/content/posts/rainy-city-badass/rainy-city-badass.png differ diff --git a/content/posts/rainy-city-black-armor/index.md b/content/posts/rainy-city-black-armor/index.md new file mode 100644 index 0000000..4ba9558 --- /dev/null +++ b/content/posts/rainy-city-black-armor/index.md @@ -0,0 +1,19 @@ +--- +title: "Rainy City Black Armor" +description: "a sleek fiery-haired model in a form-fitting black latex fashion suit striding through a rain-drenched city street silhouetted against blurred neon streetlights, cyberpunk antihero fashion aesthetic" +plate: "071" +slug: "rainy-city-black-armor" +image: "rainy-city-black-armor.png" +weight: 71 +categories: + - "Cyberpunk" +tags: + - "Latex" + - "Rain" + - "City" + - "Neon" + - "Cyberpunk" + - "Antihero" + - "Bodysuit" + - "Night" +--- diff --git a/content/posts/rainy-city-black-armor/rainy-city-black-armor.png b/content/posts/rainy-city-black-armor/rainy-city-black-armor.png new file mode 100644 index 0000000..2297b1f Binary files /dev/null and b/content/posts/rainy-city-black-armor/rainy-city-black-armor.png differ diff --git a/content/posts/rainy-city-dark-bodysuit/index.md b/content/posts/rainy-city-dark-bodysuit/index.md new file mode 100644 index 0000000..e471c1b --- /dev/null +++ b/content/posts/rainy-city-dark-bodysuit/index.md @@ -0,0 +1,21 @@ +--- +title: "Rainy City Dark Bodysuit" +description: "a fiery-haired model in a sleek black editorial bodysuit striking a confident pose on a rain-slicked urban street at night, warm amber streetlamps and glistening wet ground adding cinematic noir edge" +plate: "072" +slug: "rainy-city-dark-bodysuit" +image: "rainy-city-dark-bodysuit.png" +weight: 72 +categories: + - "Urban" + - "Noir" +tags: + - "Tattoo" + - "Rain" + - "City" + - "Bodysuit" + - "Amber" + - "Noir" + - "Cinematic" + - "Night" + - "Street" +--- diff --git a/content/posts/rainy-city-dark-bodysuit/rainy-city-dark-bodysuit.png b/content/posts/rainy-city-dark-bodysuit/rainy-city-dark-bodysuit.png new file mode 100644 index 0000000..95fd30e Binary files /dev/null and b/content/posts/rainy-city-dark-bodysuit/rainy-city-dark-bodysuit.png differ diff --git a/content/posts/red-cape-misty-forest/index.md b/content/posts/red-cape-misty-forest/index.md new file mode 100644 index 0000000..beb293e --- /dev/null +++ b/content/posts/red-cape-misty-forest/index.md @@ -0,0 +1,19 @@ +--- +title: "Red Cape Misty Forest" +description: "a fiery-haired model in a sleek black editorial ensemble with a flowing crimson cape striding through a bare fog-draped atmospheric setting, hauntingly mysterious and boldly contrasted" +plate: "073" +slug: "red-cape-misty-forest" +image: "red-cape-misty-forest.png" +weight: 73 +categories: + - "Gothic" +tags: + - "Gothic" + - "Forest" + - "Red Cape" + - "Fog" + - "Mysterious" + - "Dusk" + - "Haunting" + - "Dark" +--- diff --git a/content/posts/red-cape-misty-forest/red-cape-misty-forest.png b/content/posts/red-cape-misty-forest/red-cape-misty-forest.png new file mode 100644 index 0000000..8a48cec Binary files /dev/null and b/content/posts/red-cape-misty-forest/red-cape-misty-forest.png differ diff --git a/content/posts/red-jacket-urban-athlete/index.md b/content/posts/red-jacket-urban-athlete/index.md new file mode 100644 index 0000000..1851f89 --- /dev/null +++ b/content/posts/red-jacket-urban-athlete/index.md @@ -0,0 +1,19 @@ +--- +title: "Red Jacket Urban Athlete" +description: "a fiery-haired model in a red and black athletic fashion jacket standing on an open urban plaza at dusk, sporty self-assured editorial with graphic architectural backdrop" +plate: "074" +slug: "red-jacket-urban-athlete" +image: "red-jacket-urban-athlete.png" +weight: 74 +categories: + - "Lifestyle" +tags: + - "Athletic" + - "Urban" + - "Sporty" + - "Dusk" + - "Plaza" + - "Red Jacket" + - "Confident" + - "Outdoors" +--- diff --git a/content/posts/red-jacket-urban-athlete/red-jacket-urban-athlete.png b/content/posts/red-jacket-urban-athlete/red-jacket-urban-athlete.png new file mode 100644 index 0000000..e270731 Binary files /dev/null and b/content/posts/red-jacket-urban-athlete/red-jacket-urban-athlete.png differ diff --git a/content/posts/red-lantern-night-soak/index.md b/content/posts/red-lantern-night-soak/index.md new file mode 100644 index 0000000..de57395 --- /dev/null +++ b/content/posts/red-lantern-night-soak/index.md @@ -0,0 +1,21 @@ +--- +title: "Red Lantern Night Soak" +description: "a fiery-haired model in a flowing red editorial garment reclining in a night pool beneath glowing red lanterns and a starry coastal sky, lush sensual Japanese-aesthetic nocturnal fashion editorial" +plate: "075" +slug: "red-lantern-night-soak" +image: "red-lantern-night-soak.png" +weight: 75 +categories: + - "Cultural" + - "Romantic" +tags: + - "Onsen" + - "Lanterns" + - "Japanese" + - "Night" + - "Tattoo" + - "Coastal" + - "Stars" + - "Red" + - "Sensual" +--- diff --git a/content/posts/red-lantern-night-soak/red-lantern-night-soak.png b/content/posts/red-lantern-night-soak/red-lantern-night-soak.png new file mode 100644 index 0000000..c866d3f Binary files /dev/null and b/content/posts/red-lantern-night-soak/red-lantern-night-soak.png differ diff --git a/content/posts/red-latex-gothic-staircase/index.md b/content/posts/red-latex-gothic-staircase/index.md new file mode 100644 index 0000000..396b097 --- /dev/null +++ b/content/posts/red-latex-gothic-staircase/index.md @@ -0,0 +1,19 @@ +--- +title: "Red Latex Gothic Staircase" +description: "a fiery-haired model in a bold red latex editorial dress posed dramatically on an ornate stone staircase, rich crimson tones against dark architecture creating a gothic theatrical fashion mood" +plate: "076" +slug: "red-latex-gothic-staircase" +image: "red-latex-gothic-staircase.png" +weight: 76 +categories: + - "Gothic" +tags: + - "Gothic" + - "Latex" + - "Staircase" + - "Red" + - "Theatrical" + - "Seductive" + - "Ornate" + - "Dark Architecture" +--- diff --git a/content/posts/red-latex-gothic-staircase/red-latex-gothic-staircase.png b/content/posts/red-latex-gothic-staircase/red-latex-gothic-staircase.png new file mode 100644 index 0000000..fffad9e Binary files /dev/null and b/content/posts/red-latex-gothic-staircase/red-latex-gothic-staircase.png differ diff --git a/content/posts/red-warrior-rose-lamplight/index.md b/content/posts/red-warrior-rose-lamplight/index.md new file mode 100644 index 0000000..18e32be --- /dev/null +++ b/content/posts/red-warrior-rose-lamplight/index.md @@ -0,0 +1,19 @@ +--- +title: "Red Warrior Rose Lamplight" +description: "a fiery-haired model in black structured tactical fashion standing before darkened red roses and an ornate lamp, gothic power and deep shadows creating dramatic brooding fashion intensity" +plate: "077" +slug: "red-warrior-rose-lamplight" +image: "red-warrior-rose-lamplight.png" +weight: 77 +categories: + - "Gothic" +tags: + - "Gothic" + - "Warrior" + - "Roses" + - "Lamplight" + - "Tactical" + - "Dark" + - "Crimson" + - "Brooding" +--- diff --git a/content/posts/red-warrior-rose-lamplight/red-warrior-rose-lamplight.png b/content/posts/red-warrior-rose-lamplight/red-warrior-rose-lamplight.png new file mode 100644 index 0000000..be6b01d Binary files /dev/null and b/content/posts/red-warrior-rose-lamplight/red-warrior-rose-lamplight.png differ diff --git a/content/posts/royal-warrior-guards-the-gate/index.md b/content/posts/royal-warrior-guards-the-gate/index.md new file mode 100644 index 0000000..428a11e --- /dev/null +++ b/content/posts/royal-warrior-guards-the-gate/index.md @@ -0,0 +1,21 @@ +--- +title: "Royal Warrior Guards the Gate" +description: "a powerful redhead in ornate silver and gold structured fashion couture standing before an ancient stone architectural backdrop under a crisp winter sky, the heroic editorial projecting timeless valor" +plate: "078" +slug: "royal-warrior-guards-the-gate" +image: "royal-warrior-guards-the-gate.png" +weight: 78 +categories: + - "Fantasy" + - "Mythology" +tags: + - "Warrior" + - "Armor" + - "Fortress" + - "Winter" + - "Fantasy" + - "Shield" + - "Medieval" + - "Heroic" + - "Regal" +--- diff --git a/content/posts/royal-warrior-guards-the-gate/royal-warrior-guards-the-gate.png b/content/posts/royal-warrior-guards-the-gate/royal-warrior-guards-the-gate.png new file mode 100644 index 0000000..e747443 Binary files /dev/null and b/content/posts/royal-warrior-guards-the-gate/royal-warrior-guards-the-gate.png differ diff --git a/content/posts/shield-maiden-defends-the-keep/index.md b/content/posts/shield-maiden-defends-the-keep/index.md new file mode 100644 index 0000000..62fb144 --- /dev/null +++ b/content/posts/shield-maiden-defends-the-keep/index.md @@ -0,0 +1,20 @@ +--- +title: "Shield Maiden Defends the Keep" +description: "a fiery-haired model in polished silver and gold structured fashion armor posing in a battle-ready stance before a snow-dusted stone architectural backdrop, classic heroic fantasy-fashion editorial" +plate: "079" +slug: "shield-maiden-defends-the-keep" +image: "shield-maiden-defends-the-keep.png" +weight: 79 +categories: + - "Fantasy" + - "Mythology" +tags: + - "Shield Maiden" + - "Armor" + - "Fortress" + - "Snow" + - "Medieval" + - "Fantasy" + - "Heroic" + - "Winter" +--- diff --git a/content/posts/shield-maiden-defends-the-keep/shield-maiden-defends-the-keep.png b/content/posts/shield-maiden-defends-the-keep/shield-maiden-defends-the-keep.png new file mode 100644 index 0000000..869c7ab Binary files /dev/null and b/content/posts/shield-maiden-defends-the-keep/shield-maiden-defends-the-keep.png differ diff --git a/content/posts/silver-dress-by-the-benz/index.md b/content/posts/silver-dress-by-the-benz/index.md new file mode 100644 index 0000000..903ee35 --- /dev/null +++ b/content/posts/silver-dress-by-the-benz/index.md @@ -0,0 +1,20 @@ +--- +title: "Silver Dress by the Benz" +description: "a vivacious redhead in a shimmering silver mini dress leaning against a silver luxury convertible on a glittering night street, breezy high-society fashion editorial charm" +plate: "080" +slug: "silver-dress-by-the-benz" +image: "silver-dress-by-the-benz.png" +weight: 80 +categories: + - "Luxury" + - "Lifestyle" +tags: + - "Luxury" + - "Car" + - "Silver Dress" + - "Night" + - "Glamour" + - "Mercedes" + - "Convertible" + - "High Society" +--- diff --git a/content/posts/silver-dress-by-the-benz/silver-dress-by-the-benz.png b/content/posts/silver-dress-by-the-benz/silver-dress-by-the-benz.png new file mode 100644 index 0000000..7f44541 Binary files /dev/null and b/content/posts/silver-dress-by-the-benz/silver-dress-by-the-benz.png differ diff --git a/content/posts/silver-dress-neon-boulevard/index.md b/content/posts/silver-dress-neon-boulevard/index.md new file mode 100644 index 0000000..25af809 --- /dev/null +++ b/content/posts/silver-dress-neon-boulevard/index.md @@ -0,0 +1,20 @@ +--- +title: "Silver Dress Neon Boulevard" +description: "a fiery-haired model in a shimmering silver mini-dress sitting gracefully on a neon-lit city sidewalk at night with colorful storefronts behind her, playful retro-glamour pop-art fashion editorial" +plate: "081" +slug: "silver-dress-neon-boulevard" +image: "silver-dress-neon-boulevard.png" +weight: 81 +categories: + - "Urban" + - "Noir" +tags: + - "Neon" + - "City" + - "Silver Dress" + - "Retro-Glamour" + - "Night" + - "Sidewalk" + - "Pop Art" + - "Colorful" +--- diff --git a/content/posts/silver-dress-neon-boulevard/silver-dress-neon-boulevard.png b/content/posts/silver-dress-neon-boulevard/silver-dress-neon-boulevard.png new file mode 100644 index 0000000..7f31673 Binary files /dev/null and b/content/posts/silver-dress-neon-boulevard/silver-dress-neon-boulevard.png differ diff --git a/content/posts/silver-ruins-swordswoman/index.md b/content/posts/silver-ruins-swordswoman/index.md new file mode 100644 index 0000000..63e7bb1 --- /dev/null +++ b/content/posts/silver-ruins-swordswoman/index.md @@ -0,0 +1,21 @@ +--- +title: "Silver Ruins Swordswoman" +description: "a battle-ready redhead in gleaming silver structured couture with dramatic accessories posed amid textured stone, the turbulent moody backdrop and fierce expression creating a powerful high-fashion editorial" +plate: "082" +slug: "silver-ruins-swordswoman" +image: "silver-ruins-swordswoman.png" +weight: 82 +categories: + - "Fantasy" + - "Mythology" +tags: + - "Armor" + - "Swords" + - "Ruins" + - "Medieval" + - "Fantasy" + - "Silver" + - "Grit" + - "Heroic" + - "Storm" +--- diff --git a/content/posts/silver-ruins-swordswoman/silver-ruins-swordswoman.png b/content/posts/silver-ruins-swordswoman/silver-ruins-swordswoman.png new file mode 100644 index 0000000..a1a6af9 Binary files /dev/null and b/content/posts/silver-ruins-swordswoman/silver-ruins-swordswoman.png differ diff --git a/content/posts/stage-siren-in-gold-and-black/index.md b/content/posts/stage-siren-in-gold-and-black/index.md new file mode 100644 index 0000000..6a1cadc --- /dev/null +++ b/content/posts/stage-siren-in-gold-and-black/index.md @@ -0,0 +1,19 @@ +--- +title: "Stage Siren in Gold and Black" +description: "a glamorous redhead in an elaborate black and gold structured corset costume striking a theatrical pose on a dimly lit stage, ornate gold jewelry and dramatic editorial styling commanding attention" +plate: "083" +slug: "stage-siren-in-gold-and-black" +image: "stage-siren-in-gold-and-black.png" +weight: 83 +categories: + - "Steampunk" +tags: + - "Steampunk" + - "Corset" + - "Gold" + - "Stage" + - "Theatrical" + - "Jewelry" + - "Gloves" + - "Performance" +--- diff --git a/content/posts/stage-siren-in-gold-and-black/stage-siren-in-gold-and-black.png b/content/posts/stage-siren-in-gold-and-black/stage-siren-in-gold-and-black.png new file mode 100644 index 0000000..cc13450 Binary files /dev/null and b/content/posts/stage-siren-in-gold-and-black/stage-siren-in-gold-and-black.png differ diff --git a/content/posts/starry-night-luxury-pose/index.md b/content/posts/starry-night-luxury-pose/index.md new file mode 100644 index 0000000..4925572 --- /dev/null +++ b/content/posts/starry-night-luxury-pose/index.md @@ -0,0 +1,20 @@ +--- +title: "Starry Night Luxury Pose" +description: "a radiant redhead in a form-fitting silver dress standing beside a silver luxury vehicle under a star-dusted night sky, a grand illuminated boulevard stretching behind her in a glamorous nocturnal editorial" +plate: "084" +slug: "starry-night-luxury-pose" +image: "starry-night-luxury-pose.png" +weight: 84 +categories: + - "Luxury" + - "Lifestyle" +tags: + - "Luxury" + - "Car" + - "Silver Dress" + - "Stars" + - "Night" + - "Boulevard" + - "Mercedes" + - "Glamour" +--- diff --git a/content/posts/starry-night-luxury-pose/starry-night-luxury-pose.png b/content/posts/starry-night-luxury-pose/starry-night-luxury-pose.png new file mode 100644 index 0000000..ea7f015 Binary files /dev/null and b/content/posts/starry-night-luxury-pose/starry-night-luxury-pose.png differ diff --git a/content/posts/starship-bridge-sci-fi-pilot/index.md b/content/posts/starship-bridge-sci-fi-pilot/index.md new file mode 100644 index 0000000..bace1d1 --- /dev/null +++ b/content/posts/starship-bridge-sci-fi-pilot/index.md @@ -0,0 +1,19 @@ +--- +title: "Starship Bridge Sci-Fi Pilot" +description: "a serene redhead in a form-fitting silver editorial spacesuit posing in a sleek angular interior with a panoramic cosmic backdrop, cool metallic blues defining the polished sci-fi fashion editorial" +plate: "085" +slug: "starship-bridge-sci-fi-pilot" +image: "starship-bridge-sci-fi-pilot.png" +weight: 85 +categories: + - "Sci-Fi" +tags: + - "Spaceship" + - "Cockpit" + - "Spacesuit" + - "Planet" + - "Sci-Fi" + - "Space" + - "Futuristic" + - "Cosmic" +--- diff --git a/content/posts/starship-bridge-sci-fi-pilot/starship-bridge-sci-fi-pilot.png b/content/posts/starship-bridge-sci-fi-pilot/starship-bridge-sci-fi-pilot.png new file mode 100644 index 0000000..6748060 Binary files /dev/null and b/content/posts/starship-bridge-sci-fi-pilot/starship-bridge-sci-fi-pilot.png differ diff --git a/content/posts/steampunk-carnival-gothic-beauty/index.md b/content/posts/steampunk-carnival-gothic-beauty/index.md new file mode 100644 index 0000000..0ac6ea7 --- /dev/null +++ b/content/posts/steampunk-carnival-gothic-beauty/index.md @@ -0,0 +1,20 @@ +--- +title: "Steampunk Carnival Gothic Beauty" +description: "a fiery-haired model with tattoo-covered arms in a structured black corset and lace editorial fashion standing before a grand architectural setting with ornate ironwork, theatrical alternate-history high-fashion aesthetic" +plate: "086" +slug: "steampunk-carnival-gothic-beauty" +image: "steampunk-carnival-gothic-beauty.png" +weight: 86 +categories: + - "Steampunk" +tags: + - "Steampunk" + - "Carnival" + - "Gothic" + - "Tattoo" + - "Corset" + - "Fairground" + - "Lace" + - "Theatrical" + - "Alternate History" +--- diff --git a/content/posts/steampunk-carnival-gothic-beauty/steampunk-carnival-gothic-beauty.png b/content/posts/steampunk-carnival-gothic-beauty/steampunk-carnival-gothic-beauty.png new file mode 100644 index 0000000..95452d7 Binary files /dev/null and b/content/posts/steampunk-carnival-gothic-beauty/steampunk-carnival-gothic-beauty.png differ diff --git a/content/posts/storm-wing-valkyrie/index.md b/content/posts/storm-wing-valkyrie/index.md new file mode 100644 index 0000000..6871368 --- /dev/null +++ b/content/posts/storm-wing-valkyrie/index.md @@ -0,0 +1,19 @@ +--- +title: "Storm Wing Valkyrie" +description: "a fierce redhead in black futuristic structured fashion couture standing against a stormy backdrop gripping a dramatic dark sculptural prop, the epic composition radiating fashion gravitas" +plate: "087" +slug: "storm-wing-valkyrie" +image: "storm-wing-valkyrie.png" +weight: 87 +categories: + - "Sci-Fi" +tags: + - "Warrior" + - "Armor" + - "Storm" + - "Wings" + - "Sci-Fi" + - "Dark Fantasy" + - "Epic" + - "Gravitas" +--- diff --git a/content/posts/storm-wing-valkyrie/storm-wing-valkyrie.png b/content/posts/storm-wing-valkyrie/storm-wing-valkyrie.png new file mode 100644 index 0000000..376347a Binary files /dev/null and b/content/posts/storm-wing-valkyrie/storm-wing-valkyrie.png differ diff --git a/content/posts/sun-blessed-warrior-and-wolf/index.md b/content/posts/sun-blessed-warrior-and-wolf/index.md new file mode 100644 index 0000000..1b5e4a8 --- /dev/null +++ b/content/posts/sun-blessed-warrior-and-wolf/index.md @@ -0,0 +1,20 @@ +--- +title: "Sun-Blessed Warrior and Wolf" +description: "a radiant redhead in elaborate jeweled structured fashion armor posing in a golden sun-drenched architectural setting, heroic editorial warmth and regal jeweled couture detail" +plate: "088" +slug: "sun-blessed-warrior-and-wolf" +image: "sun-blessed-warrior-and-wolf.png" +weight: 88 +categories: + - "Cultural" + - "Fantasy" +tags: + - "Warrior Princess" + - "Wolf" + - "Temple" + - "Armor" + - "East Asian" + - "Fantasy" + - "Sun-Drenched" + - "Jeweled" +--- diff --git a/content/posts/sun-blessed-warrior-and-wolf/sun-blessed-warrior-and-wolf.png b/content/posts/sun-blessed-warrior-and-wolf/sun-blessed-warrior-and-wolf.png new file mode 100644 index 0000000..4a478d9 Binary files /dev/null and b/content/posts/sun-blessed-warrior-and-wolf/sun-blessed-warrior-and-wolf.png differ diff --git a/content/posts/sunny-kitchen-city-view/index.md b/content/posts/sunny-kitchen-city-view/index.md new file mode 100644 index 0000000..aed23b5 --- /dev/null +++ b/content/posts/sunny-kitchen-city-view/index.md @@ -0,0 +1,19 @@ +--- +title: "Sunny Kitchen City View" +description: "a cheerful redhead in vibrant casual summer fashion in a bright colorful kitchen with a sweeping panoramic view of a sunlit European city, warm lively domestic fashion editorial" +plate: "089" +slug: "sunny-kitchen-city-view" +image: "sunny-kitchen-city-view.png" +weight: 89 +categories: + - "Lifestyle" +tags: + - "Kitchen" + - "City View" + - "Summer" + - "Casual" + - "Cheerful" + - "Domestic" + - "European" + - "Sunny" +--- diff --git a/content/posts/sunny-kitchen-city-view/sunny-kitchen-city-view.png b/content/posts/sunny-kitchen-city-view/sunny-kitchen-city-view.png new file mode 100644 index 0000000..69b40ca Binary files /dev/null and b/content/posts/sunny-kitchen-city-view/sunny-kitchen-city-view.png differ diff --git a/content/posts/sunset-pagoda-coastal-reclining/index.md b/content/posts/sunset-pagoda-coastal-reclining/index.md new file mode 100644 index 0000000..3cf3129 --- /dev/null +++ b/content/posts/sunset-pagoda-coastal-reclining/index.md @@ -0,0 +1,20 @@ +--- +title: "Sunset Pagoda Coastal Reclining" +description: "a fiery-haired model in a shimmering white editorial fashion ensemble reclining gracefully on a stone terrace overlooking a serene coastal sunset with traditional architecture visible, dreamlike editorial peace" +plate: "090" +slug: "sunset-pagoda-coastal-reclining" +image: "sunset-pagoda-coastal-reclining.png" +weight: 90 +categories: + - "Cultural" + - "Romantic" +tags: + - "Pagoda" + - "Coastal" + - "Sunset" + - "Peaceful" + - "Japanese" + - "Dreamy" + - "Golden Light" + - "Terrace" +--- diff --git a/content/posts/sunset-pagoda-coastal-reclining/sunset-pagoda-coastal-reclining.png b/content/posts/sunset-pagoda-coastal-reclining/sunset-pagoda-coastal-reclining.png new file mode 100644 index 0000000..a4ee0bd Binary files /dev/null and b/content/posts/sunset-pagoda-coastal-reclining/sunset-pagoda-coastal-reclining.png differ diff --git a/content/posts/tattoo-warrior-night-rain/index.md b/content/posts/tattoo-warrior-night-rain/index.md new file mode 100644 index 0000000..b8226b1 --- /dev/null +++ b/content/posts/tattoo-warrior-night-rain/index.md @@ -0,0 +1,20 @@ +--- +title: "Tattoo Warrior Night Rain" +description: "a tattooed fiery-haired model in a black editorial bodysuit leaning dynamically on a rain-soaked rooftop under cold industrial lights, gritty urban fashion editorial with rebellious edge" +plate: "091" +slug: "tattoo-warrior-night-rain" +image: "tattoo-warrior-night-rain.png" +weight: 91 +categories: + - "Urban" + - "Noir" +tags: + - "Tattoo" + - "Rain" + - "Rooftop" + - "Bodysuit" + - "Industrial" + - "Edgy" + - "Urban" + - "Wind" +--- diff --git a/content/posts/tattoo-warrior-night-rain/tattoo-warrior-night-rain.png b/content/posts/tattoo-warrior-night-rain/tattoo-warrior-night-rain.png new file mode 100644 index 0000000..2c3b524 Binary files /dev/null and b/content/posts/tattoo-warrior-night-rain/tattoo-warrior-night-rain.png differ diff --git a/content/posts/tattooed-dusk-ocean-vista/index.md b/content/posts/tattooed-dusk-ocean-vista/index.md new file mode 100644 index 0000000..6ba54bc --- /dev/null +++ b/content/posts/tattooed-dusk-ocean-vista/index.md @@ -0,0 +1,21 @@ +--- +title: "Tattooed Dusk Ocean Vista" +description: "a fiery-haired model in a red editorial fashion posing with raised arms before a wide ocean horizon at dusk, framed by warm lanterns and a tropical pavilion in a confident beauty editorial" +plate: "092" +slug: "tattooed-dusk-ocean-vista" +image: "tattooed-dusk-ocean-vista.png" +weight: 92 +categories: + - "Beach" + - "Outdoor" +tags: + - "Beach" + - "Ocean" + - "Dusk" + - "Tattoo" + - "Bikini" + - "Lanterns" + - "Tropical" + - "Pavilion" + - "Confident" +--- diff --git a/content/posts/tattooed-dusk-ocean-vista/tattooed-dusk-ocean-vista.png b/content/posts/tattooed-dusk-ocean-vista/tattooed-dusk-ocean-vista.png new file mode 100644 index 0000000..c6b2abd Binary files /dev/null and b/content/posts/tattooed-dusk-ocean-vista/tattooed-dusk-ocean-vista.png differ diff --git a/content/posts/tattooed-goth-garden-portrait/index.md b/content/posts/tattooed-goth-garden-portrait/index.md new file mode 100644 index 0000000..947c8ff --- /dev/null +++ b/content/posts/tattooed-goth-garden-portrait/index.md @@ -0,0 +1,19 @@ +--- +title: "Tattooed Goth Garden Portrait" +description: "a curly fiery-haired model with extensive sleeve tattoos in dark gothic lace editorial fashion gazing softly at the camera amid a lush sunlit garden bursting with orange roses and green foliage" +plate: "093" +slug: "tattooed-goth-garden-portrait" +image: "tattooed-goth-garden-portrait.png" +weight: 93 +categories: + - "Gothic" +tags: + - "Gothic" + - "Tattoo" + - "Garden" + - "Roses" + - "Lace" + - "Sunlit" + - "Portrait" + - "Sleeve Tattoos" +--- diff --git a/content/posts/tattooed-goth-garden-portrait/tattooed-goth-garden-portrait.png b/content/posts/tattooed-goth-garden-portrait/tattooed-goth-garden-portrait.png new file mode 100644 index 0000000..f056ca3 Binary files /dev/null and b/content/posts/tattooed-goth-garden-portrait/tattooed-goth-garden-portrait.png differ diff --git a/content/posts/temple-enchantress-golden-light/index.md b/content/posts/temple-enchantress-golden-light/index.md new file mode 100644 index 0000000..2fc4525 --- /dev/null +++ b/content/posts/temple-enchantress-golden-light/index.md @@ -0,0 +1,19 @@ +--- +title: "Temple Enchantress Golden Light" +description: "a commanding redhead in black and gold armor-inspired couture bathed in warm golden light, a sheer black veil flowing as she meets the viewer's gaze with regal presence" +plate: "094" +slug: "temple-enchantress-golden-light" +image: "temple-enchantress-golden-light.png" +weight: 94 +categories: + - "Dark Fantasy" +tags: + - "Temple" + - "Armor" + - "Veil" + - "Torchlight" + - "Ancient" + - "Gothic" + - "Fantasy" + - "Regal" +--- diff --git a/content/posts/temple-enchantress-golden-light/temple-enchantress-golden-light.png b/content/posts/temple-enchantress-golden-light/temple-enchantress-golden-light.png new file mode 100644 index 0000000..6ae32d9 Binary files /dev/null and b/content/posts/temple-enchantress-golden-light/temple-enchantress-golden-light.png differ diff --git a/content/posts/temple-raider-ancient-ruins/index.md b/content/posts/temple-raider-ancient-ruins/index.md new file mode 100644 index 0000000..a6afb6e --- /dev/null +++ b/content/posts/temple-raider-ancient-ruins/index.md @@ -0,0 +1,20 @@ +--- +title: "Temple Raider Ancient Ruins" +description: "a determined redhead in a blue crop top and cargo editorial styling standing amid atmospheric stone columns in a jungle ruin, adventurous action-fashion editorial mood" +plate: "095" +slug: "temple-raider-ancient-ruins" +image: "temple-raider-ancient-ruins.png" +weight: 95 +categories: + - "Action" + - "Adventure" +tags: + - "Ruins" + - "Ancient" + - "Jungle" + - "Adventure" + - "Tactical" + - "Columns" + - "Explorer" + - "Action" +--- diff --git a/content/posts/temple-raider-ancient-ruins/temple-raider-ancient-ruins.png b/content/posts/temple-raider-ancient-ruins/temple-raider-ancient-ruins.png new file mode 100644 index 0000000..6bdcf39 Binary files /dev/null and b/content/posts/temple-raider-ancient-ruins/temple-raider-ancient-ruins.png differ diff --git a/content/posts/tokyo-white-curve/index.md b/content/posts/tokyo-white-curve/index.md new file mode 100644 index 0000000..5a74173 --- /dev/null +++ b/content/posts/tokyo-white-curve/index.md @@ -0,0 +1,19 @@ +--- +title: "Tokyo White Curve" +description: "a confident redhead in a sculpted white corset dress seen from behind on a crowded neon Tokyo street, intricate sleeve tattoos and bold urban glamour creating a striking fashion editorial" +plate: "096" +slug: "tokyo-white-curve" +image: "tokyo-white-curve.png" +weight: 96 +categories: + - "Cultural" +tags: + - "Tokyo" + - "Tattoo" + - "Corset" + - "Neon" + - "Urban" + - "Fashion" + - "Crowd" + - "White Dress" +--- diff --git a/content/posts/tokyo-white-curve/tokyo-white-curve.png b/content/posts/tokyo-white-curve/tokyo-white-curve.png new file mode 100644 index 0000000..d36c0fe Binary files /dev/null and b/content/posts/tokyo-white-curve/tokyo-white-curve.png differ diff --git a/content/posts/tropical-goddess-terrace/index.md b/content/posts/tropical-goddess-terrace/index.md new file mode 100644 index 0000000..e999d4a --- /dev/null +++ b/content/posts/tropical-goddess-terrace/index.md @@ -0,0 +1,20 @@ +--- +title: "Tropical Goddess Terrace" +description: "a vibrant redhead in a shimmering teal fashion-forward embellished couture with gold jewelry posing on a sunlit terrace overlooking brilliant turquoise waters, warm exotic editorial allure" +plate: "097" +slug: "tropical-goddess-terrace" +image: "tropical-goddess-terrace.png" +weight: 97 +categories: + - "Cultural" + - "Fantasy" +tags: + - "Belly Dancer" + - "Tropical" + - "Teal" + - "Gold Jewelry" + - "Ocean View" + - "Terrace" + - "Exotic" + - "Allure" +--- diff --git a/content/posts/tropical-goddess-terrace/tropical-goddess-terrace.png b/content/posts/tropical-goddess-terrace/tropical-goddess-terrace.png new file mode 100644 index 0000000..8825922 Binary files /dev/null and b/content/posts/tropical-goddess-terrace/tropical-goddess-terrace.png differ diff --git a/content/posts/underwater-dance-with-sharks/index.md b/content/posts/underwater-dance-with-sharks/index.md new file mode 100644 index 0000000..714a7c7 --- /dev/null +++ b/content/posts/underwater-dance-with-sharks/index.md @@ -0,0 +1,20 @@ +--- +title: "Underwater Dance With Sharks" +description: "a fiery-haired model in a sleek black one-piece editorial swimsuit posed dynamically in a vivid blue aquatic setting, dynamic light filtering creating a thrilling graceful underwater fashion editorial" +plate: "098" +slug: "underwater-dance-with-sharks" +image: "underwater-dance-with-sharks.png" +weight: 98 +categories: + - "Beach" + - "Outdoor" +tags: + - "Underwater" + - "Sharks" + - "Swimming" + - "Ocean" + - "Adventure" + - "Blue Water" + - "Thrilling" + - "Graceful" +--- diff --git a/content/posts/underwater-dance-with-sharks/underwater-dance-with-sharks.png b/content/posts/underwater-dance-with-sharks/underwater-dance-with-sharks.png new file mode 100644 index 0000000..24a0c5f Binary files /dev/null and b/content/posts/underwater-dance-with-sharks/underwater-dance-with-sharks.png differ diff --git a/content/posts/velvet-gown-evening-drive/index.md b/content/posts/velvet-gown-evening-drive/index.md new file mode 100644 index 0000000..b856de5 --- /dev/null +++ b/content/posts/velvet-gown-evening-drive/index.md @@ -0,0 +1,20 @@ +--- +title: "Velvet Gown Evening Drive" +description: "a curvaceous redhead in a sleek black evening gown with a thigh-high slit leaning against a luxury vehicle on a glittering night city street, opulent nocturnal fashion glamour" +plate: "099" +slug: "velvet-gown-evening-drive" +image: "velvet-gown-evening-drive.png" +weight: 99 +categories: + - "Luxury" + - "Lifestyle" +tags: + - "Luxury" + - "Car" + - "Evening Gown" + - "Night" + - "City" + - "Mercedes" + - "Glamour" + - "Opulence" +--- diff --git a/content/posts/velvet-gown-evening-drive/velvet-gown-evening-drive.png b/content/posts/velvet-gown-evening-drive/velvet-gown-evening-drive.png new file mode 100644 index 0000000..3d8a4b0 Binary files /dev/null and b/content/posts/velvet-gown-evening-drive/velvet-gown-evening-drive.png differ diff --git a/content/posts/volcanic-blade-sorceress/index.md b/content/posts/volcanic-blade-sorceress/index.md new file mode 100644 index 0000000..7915b2d --- /dev/null +++ b/content/posts/volcanic-blade-sorceress/index.md @@ -0,0 +1,19 @@ +--- +title: "Volcanic Blade Sorceress" +description: "a powerful redhead in dark structured battle-inspired fashion couture raising a sleek editorial prop in a dramatic moody landscape, charged dark elemental fashion energy defining the look" +plate: "100" +slug: "volcanic-blade-sorceress" +image: "volcanic-blade-sorceress.png" +weight: 100 +categories: + - "Dark Fantasy" +tags: + - "Volcano" + - "Blade" + - "Armor" + - "Dark Fantasy" + - "Elemental" + - "Storm" + - "Sorceress" + - "Glowing" +--- diff --git a/content/posts/volcanic-blade-sorceress/volcanic-blade-sorceress.png b/content/posts/volcanic-blade-sorceress/volcanic-blade-sorceress.png new file mode 100644 index 0000000..5eec889 Binary files /dev/null and b/content/posts/volcanic-blade-sorceress/volcanic-blade-sorceress.png differ diff --git a/content/posts/wet-street-midnight-noir/index.md b/content/posts/wet-street-midnight-noir/index.md new file mode 100644 index 0000000..d7e5e64 --- /dev/null +++ b/content/posts/wet-street-midnight-noir/index.md @@ -0,0 +1,20 @@ +--- +title: "Wet Street Midnight Noir" +description: "a fiery-haired model in a dark open coat and minimal editorial fashion standing on a rain-slicked city street at night, neon reflections pooling around her feet in moody cinematic classic noir" +plate: "101" +slug: "wet-street-midnight-noir" +image: "wet-street-midnight-noir.png" +weight: 101 +categories: + - "Urban" + - "Noir" +tags: + - "Noir" + - "Rain" + - "City" + - "Night" + - "Cinematic" + - "Moody" + - "Reflections" + - "Open Coat" +--- diff --git a/content/posts/wet-street-midnight-noir/wet-street-midnight-noir.png b/content/posts/wet-street-midnight-noir/wet-street-midnight-noir.png new file mode 100644 index 0000000..c4b6565 Binary files /dev/null and b/content/posts/wet-street-midnight-noir/wet-street-midnight-noir.png differ diff --git a/data/issues.json b/data/issues.json new file mode 100644 index 0000000..8f0e6ef --- /dev/null +++ b/data/issues.json @@ -0,0 +1,29 @@ +[ + { + "id": "01", + "number": "\u2116 01", + "title": "Fabric, Light & Gesture", + "season": "Spring MMXXVI", + "publishedAt": "2026-03-21", + "blurb": "The inaugural plates \u2014 one hundred photographs gathered across ateliers, streets, and quiet hotel corridors.", + "status": "current" + }, + { + "id": "02", + "number": "\u2116 02", + "title": "The Glasshouse", + "season": "Summer MMXXVI", + "publishedAt": "2026-06-21", + "blurb": "Forthcoming \u2014 a study in transparency, condensation, and the long late light of June.", + "status": "forthcoming" + }, + { + "id": "03", + "number": "\u2116 03", + "title": "Atelier After Hours", + "season": "Autumn MMXXVI", + "publishedAt": "2026-09-22", + "blurb": "Forthcoming \u2014 the slow work of cloth and thread, photographed when the studio is half-empty.", + "status": "forthcoming" + } +] \ No newline at end of file diff --git a/hugo.toml b/hugo.toml new file mode 100644 index 0000000..f7cade5 --- /dev/null +++ b/hugo.toml @@ -0,0 +1,45 @@ +baseURL = "https://roux.pivoine.art/" +languageCode = "en" +title = "Roux" +enableRobotsTXT = true +enableGitInfo = false +[pagination] +pagerSize = 200 + +[taxonomies] +category = "categories" +tag = "tags" + +[outputs] +home = ["HTML", "RSS", "JSON"] +page = ["HTML"] +section = ["HTML"] +taxonomy = ["HTML"] +term = ["HTML"] + +[params] +description = "Roux is a slow-publishing fashion journal — one hundred photographs at a time. Editorial, couture, beauty and backstage plates." +author = "Roux Editorial" +issueNumber = "01" +issueName = "Fabric, Light & Gesture" +issueSeason = "Spring MMXXVI" +issueBlurb = "The inaugural plates — one hundred photographs gathered across ateliers, streets, and quiet hotel corridors." +siteURL = "https://roux.pivoine.art" + +[markup.goldmark.renderer] +unsafe = true + +[build] +writeStats = true + +[imaging] +quality = 85 +resampleFilter = "lanczos" + +[imaging.exif] +disableDate = false +disableLatLong = true + +[sitemap] +changefreq = "monthly" +priority = 0.5 diff --git a/hugo_stats.json b/hugo_stats.json new file mode 100644 index 0000000..55532d3 --- /dev/null +++ b/hugo_stats.json @@ -0,0 +1,129 @@ +{ + "htmlElements": { + "tags": [ + "a", + "aside", + "body", + "br", + "button", + "circle", + "defs", + "div", + "ellipse", + "em", + "footer", + "g", + "h1", + "h2", + "h4", + "head", + "header", + "html", + "img", + "input", + "label", + "link", + "main", + "meta", + "p", + "path", + "picture", + "polyline", + "radialgradient", + "script", + "section", + "source", + "span", + "stop", + "sup", + "svg", + "title" + ], + "classes": [ + "card", + "card__cat", + "card__desc", + "card__frame", + "card__img", + "card__meta", + "card__num", + "card__sub", + "card__title", + "dot", + "foot", + "foot__roux", + "grid", + "hero", + "hero__eyebrow", + "hero__lede", + "hero__title", + "issue-card", + "issue-card--forthcoming", + "issue-card__blurb", + "issue-card__cover", + "issue-card__cta", + "issue-card__cta--muted", + "issue-card__foot", + "issue-card__forth", + "issue-card__meta", + "issue-card__num", + "issue-card__title", + "issues-grid", + "lb", + "lb__brand", + "lb__close", + "lb__index", + "lb__meta", + "lb__nav", + "lb__nav--next", + "lb__nav--prev", + "lb__stage", + "lb__thumbs", + "lb__topbar", + "lb__track", + "logo", + "logo__mark", + "logo__tag", + "logo__word", + "masthead", + "masthead__date", + "masthead__inner", + "masthead__left", + "masthead__logo", + "masthead__right", + "mh-city", + "mh-issue", + "mh-link", + "mh-pub", + "mh-sep", + "ribbon", + "searchpop", + "subhead", + "subhead__count", + "subhead__kbd", + "subhead__search", + "tabs" + ], + "ids": [ + "content", + "count", + "grid", + "hero", + "lb", + "lbBloom", + "lbIndex", + "lbMeta", + "lbThumbs", + "lbTrack", + "masthead", + "mhBloom", + "mhDate", + "ribbon", + "ribbonClose", + "roux-data", + "searchInput", + "searchpop", + "tabs" + ] + } +} diff --git a/layouts/_default/list.html b/layouts/_default/list.html new file mode 100644 index 0000000..4a7bc82 --- /dev/null +++ b/layouts/_default/list.html @@ -0,0 +1,60 @@ +{{ define "main" }} +{{/* Category / tag taxonomy list pages */}} +
+ {{- if eq .Kind "taxonomy" }} +
{{ .Type | humanize }}
+

{{ .Title }}

+

+ {{ len .Pages }} {{ if eq (len .Pages) 1 }}plate{{ else }}plates{{ end }} in this section. + Return to archive → +

+ {{- else if eq .Kind "term" }} +
{{ .Type | humanize | singularize }}
+

{{ .Title }}

+

+ {{ len .Pages }} {{ if eq (len .Pages) 1 }}plate{{ else }}plates{{ end }} tagged {{ .Title }}. + Return to archive → +

+ {{- else }} +
The Archive
+

All plates

+

Return to home →

+ {{- end }} +
+ +
+ {{- range $i, $p := .Pages }} + {{- $img := $p.Resources.GetMatch "*.png" }} + +
+ {{- if $img }} + {{- $w := $img.Resize "600x900 webp" }} + + + {{ $p.Title }} + + {{- end }} + PLATE №{{ $p.Params.plate }} + {{ index ($p.Params.categories | default (slice "")) 0 }} +
+
+

{{ $p.Title }}

+
+ {{ index ($p.Params.categories | default (slice "")) 0 }} + {{- if $p.Params.tags }}{{ index $p.Params.tags 0 }}{{ end }} +
+

{{ $p.Params.description }}

+
+
+ {{- end }} +
+{{ end }} diff --git a/layouts/_default/single.html b/layouts/_default/single.html new file mode 100644 index 0000000..c3c8d0f --- /dev/null +++ b/layouts/_default/single.html @@ -0,0 +1,46 @@ +{{ define "main" }} +{{/* Individual post page — grid renders in background, JS opens lightbox for this slug */}} +
+
{{ index (.Params.categories | default (slice "Plate")) 0 }}
+

{{ .Title }}

+

{{ .Params.description }} Return to archive →

+
+ +
+ {{- $posts := where .Site.RegularPages "Section" "posts" }} + {{- range $i, $p := $posts }} + {{- $img := $p.Resources.GetMatch "*.png" }} + +
+ {{- if $img }} + {{- $w := $img.Resize "600x900 webp" }} + + + {{ $p.Title }} + + {{- end }} + PLATE №{{ $p.Params.plate }} + {{ index ($p.Params.categories | default (slice "")) 0 }} +
+
+

{{ $p.Title }}

+
+ {{ index ($p.Params.categories | default (slice "")) 0 }} + {{- if $p.Params.tags }}{{ index $p.Params.tags 0 }}{{ end }} +
+

{{ $p.Params.description }}

+
+
+ {{- end }} +
+ +{{/* Tell JS which slug to open in the lightbox */}} + +{{ end }} diff --git a/layouts/baseof.html b/layouts/baseof.html new file mode 100644 index 0000000..7b25ede --- /dev/null +++ b/layouts/baseof.html @@ -0,0 +1,55 @@ + + + + {{- partial "head.html" . }} + + + {{- partial "header.html" . }} + +
+ {{- block "main" . }}{{- end }} +
+ + {{- partial "footer.html" . }} + + {{- partial "lightbox.html" . }} + +
+ Roux № {{ .Site.Params.issueNumber }} — out now. See the plates → + +
+ + {{/* Inline posts data for JS search + lightbox */}} + + + + + diff --git a/layouts/home.json.json b/layouts/home.json.json new file mode 100644 index 0000000..86098f9 --- /dev/null +++ b/layouts/home.json.json @@ -0,0 +1,25 @@ +{{- $posts := slice }} +{{- range (where .Site.RegularPages "Section" "posts") }} + {{- $img := .Resources.GetMatch "*.png" }} + {{- $thumb := "" }} + {{- $card := "" }} + {{- if $img }} + {{- $t := $img.Resize "300x450 webp" }} + {{- $c := $img.Resize "900x1350 webp" }} + {{- $thumb = $t.RelPermalink }} + {{- $card = $c.RelPermalink }} + {{- end }} + {{- $post := dict + "id" .Params.plate + "slug" .Params.slug + "title" .Title + "description" .Params.description + "categories" .Params.categories + "tags" .Params.tags + "thumb" $thumb + "card" $card + "url" .RelPermalink + }} + {{- $posts = $posts | append $post }} +{{- end }} +{{- $posts | jsonify }} diff --git a/layouts/index.html b/layouts/index.html new file mode 100644 index 0000000..d3be044 --- /dev/null +++ b/layouts/index.html @@ -0,0 +1,55 @@ +{{ define "main" }} +
+
+ № {{ .Site.Params.issueNumber }} · {{ .Site.Params.issueSeason }} · + View all issues +
+

An almanac
of fabric, light,
and gesture.

+

+ Roux is a slow-publishing fashion journal — one hundred photographs at a time, + gathered from ateliers, streets, glasshouses and quiet hotel corridors. + You are reading {{ .Site.Params.issueName }}, our № {{ .Site.Params.issueNumber }} issue. +

+
+ +
+ {{- $posts := where .Site.RegularPages "Section" "posts" }} + {{- range $i, $p := $posts }} + {{- $img := $p.Resources.GetMatch "*.png" }} + {{- $card := "" }} + {{- $full := "" }} + {{- if $img }} + {{- $c := $img.Resize "600x900 webp" }} + {{- $card = $c.RelPermalink }} + {{- end }} + +
+ + {{- if $img }} + {{- $w := $img.Resize "600x900 webp" }} + + {{ $p.Title }} — Roux Plate №{{ $p.Params.plate }} + {{- end }} + + PLATE №{{ $p.Params.plate }} + {{ index ($p.Params.categories | default (slice "")) 0 }} +
+
+

{{ $p.Title }}

+
+ {{ index ($p.Params.categories | default (slice "")) 0 }} + {{- if $p.Params.tags }}{{ index $p.Params.tags 0 }}{{ end }} +
+

{{ $p.Params.description }}

+
+
+ {{- end }} +
+{{ end }} diff --git a/layouts/issues/list.html b/layouts/issues/list.html new file mode 100644 index 0000000..2231aef --- /dev/null +++ b/layouts/issues/list.html @@ -0,0 +1,63 @@ +{{ define "main" }} +{{- $issues := .Site.Data.issues }} +
+
Archive · Every issue
+

The issues

+

Roux publishes one hundred photographs at a time, once a season. Each issue is a complete thing.

+
+ + +{{ end }} diff --git a/layouts/partials/footer.html b/layouts/partials/footer.html new file mode 100644 index 0000000..88e467c --- /dev/null +++ b/layouts/partials/footer.html @@ -0,0 +1,28 @@ +
+
+

Roux

+

Roux№{{ .Site.Params.issueNumber }}

+

A slow-publishing fashion journal, gathered in Paris. One hundred photographs at a time, printed and unprinted.
roux.pivoine.art

+
+
+

Categories

+

Gothic

+

Cyberpunk

+

Dark Fantasy

+

Sci-Fi

+

Cultural

+
+
+

Index

+

Cape

+

Neon

+

Rain

+

Gothic

+

Warrior

+
+
+

Colophon

+

Set in Italiana & Cormorant Garamond, with Outfit for typographic furniture. © Roux MMXXVI.

+

Press ⌘K from anywhere to search.

+
+
diff --git a/layouts/partials/head.html b/layouts/partials/head.html new file mode 100644 index 0000000..a0e9dfa --- /dev/null +++ b/layouts/partials/head.html @@ -0,0 +1,30 @@ + + +{{ if .IsHome }}{{ .Site.Title }} — {{ .Site.Params.description | truncate 60 }}{{ else }}{{ .Title }} — {{ .Site.Title }}{{ end }} + + + +{{- template "_internal/opengraph.html" . }} +{{- template "_internal/twitter_cards.html" . }} +{{- template "_internal/schema.html" . }} +{{/* Add og:image from page resource */}} +{{- $img := .Resources.GetMatch "*.png" }} +{{- if $img }} + {{- $og := $img.Resize "1200x630 webp q80" }} + + + + + +{{- end }} + + + + + + + + + + +{{ with .OutputFormats.Get "RSS" }}{{ end }} diff --git a/layouts/partials/header.html b/layouts/partials/header.html new file mode 100644 index 0000000..009eb7e --- /dev/null +++ b/layouts/partials/header.html @@ -0,0 +1,38 @@ +{{- $cats := slice "Gothic" "Cyberpunk" "Dark Fantasy" "Urban" "Noir" "Fantasy" "Cultural" "Sci-Fi" "Boudoir" "Steampunk" "Luxury" "Action" "Lifestyle" "Nature" "Romantic" "Nightlife" "Elegant" "Adventure" "Mythology" }} +
+
+
+ + № {{ .Site.Params.issueNumber }} + · + Roux Quarterly +
+ + + +
+ Issues + · + Paris +
+
+ +
+ +
+
+
+ +
+ + {{- range $cats }} + + {{- end }} +
+
diff --git a/layouts/partials/lightbox.html b/layouts/partials/lightbox.html new file mode 100644 index 0000000..d03f334 --- /dev/null +++ b/layouts/partials/lightbox.html @@ -0,0 +1,31 @@ + diff --git a/layouts/partials/logo.html b/layouts/partials/logo.html new file mode 100644 index 0000000..1f90cc4 --- /dev/null +++ b/layouts/partials/logo.html @@ -0,0 +1,38 @@ + diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..b72ba4b --- /dev/null +++ b/nginx.conf @@ -0,0 +1,30 @@ +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + charset utf-8; + + gzip on; + gzip_types text/plain text/css application/json application/javascript image/svg+xml; + gzip_min_length 256; + + # Long-cache static assets (CSS, JS, images, fonts) + location ~* \.(css|js|woff2?|ttf|otf|eot|svg|webp|png|jpg|jpeg|ico|gif)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + add_header Vary Accept-Encoding; + } + + # HTML pages — no-cache so updates are picked up immediately + location ~* \.html$ { + add_header Cache-Control "no-cache, must-revalidate"; + } + + # SPA-style routing: serve index.html for unknown paths + location / { + try_files $uri $uri/ $uri.html =404; + } + + error_page 404 /404.html; +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..b728b03 --- /dev/null +++ b/package.json @@ -0,0 +1,15 @@ +{ + "name": "roux", + "private": true, + "scripts": { + "build:css": "tailwindcss -i assets/css/main.css -o static/css/main.css --minify", + "watch:css": "tailwindcss -i assets/css/main.css -o static/css/main.css --watch", + "dev": "concurrently \"pnpm watch:css\" \"hugo server -D\"", + "build": "pnpm build:css && hugo --minify" + }, + "devDependencies": { + "@tailwindcss/cli": "^4.1.7", + "tailwindcss": "^4.1.7", + "concurrently": "^9.1.2" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..74ebe81 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,754 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@tailwindcss/cli': + specifier: ^4.1.7 + version: 4.3.0 + concurrently: + specifier: ^9.1.2 + version: 9.2.1 + tailwindcss: + specifier: ^4.1.7 + version: 4.3.0 + +packages: + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@parcel/watcher-android-arm64@2.5.6': + resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + + '@parcel/watcher-darwin-arm64@2.5.6': + resolution: {integrity: sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + + '@parcel/watcher-darwin-x64@2.5.6': + resolution: {integrity: sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + + '@parcel/watcher-freebsd-x64@2.5.6': + resolution: {integrity: sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + + '@parcel/watcher-linux-arm-glibc@2.5.6': + resolution: {integrity: sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm-musl@2.5.6': + resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm64-glibc@2.5.6': + resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-arm64-musl@2.5.6': + resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-x64-glibc@2.5.6': + resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-linux-x64-musl@2.5.6': + resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-win32-arm64@2.5.6': + resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + + '@parcel/watcher-win32-ia32@2.5.6': + resolution: {integrity: sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + + '@parcel/watcher-win32-x64@2.5.6': + resolution: {integrity: sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + + '@parcel/watcher@2.5.6': + resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==} + engines: {node: '>= 10.0.0'} + + '@tailwindcss/cli@4.3.0': + resolution: {integrity: sha512-X9kdlqyMopO9fewbgHsEeuy31YzMHbdZ9VsKt004tB+mxSg1CNbyhZYCzvhciN0AM4R4b5lvIprPjtNq7iQxpQ==} + hasBin: true + + '@tailwindcss/node@4.3.0': + resolution: {integrity: sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==} + + '@tailwindcss/oxide-android-arm64@4.3.0': + resolution: {integrity: sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.3.0': + resolution: {integrity: sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.3.0': + resolution: {integrity: sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.3.0': + resolution: {integrity: sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': + resolution: {integrity: sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': + resolution: {integrity: sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.3.0': + resolution: {integrity: sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.3.0': + resolution: {integrity: sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.3.0': + resolution: {integrity: sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.3.0': + resolution: {integrity: sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': + resolution: {integrity: sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.3.0': + resolution: {integrity: sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.3.0': + resolution: {integrity: sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==} + engines: {node: '>= 20'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + concurrently@9.2.1: + resolution: {integrity: sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==} + engines: {node: '>=18'} + hasBin: true + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + enhanced-resolve@5.21.3: + resolution: {integrity: sha512-QyL119InA+XXEkNLNTPCXPugSvOfhwv0JOlGNzvxs0hZaiHLNvXSpudUWsOlsXGWJh8G6ckCScEkVHfX3kw/2Q==} + engines: {node: '>=10.13.0'} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + + shell-quote@1.8.3: + resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} + engines: {node: '>= 0.4'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + tailwindcss@4.3.0: + resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + +snapshots: + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@parcel/watcher-android-arm64@2.5.6': + optional: true + + '@parcel/watcher-darwin-arm64@2.5.6': + optional: true + + '@parcel/watcher-darwin-x64@2.5.6': + optional: true + + '@parcel/watcher-freebsd-x64@2.5.6': + optional: true + + '@parcel/watcher-linux-arm-glibc@2.5.6': + optional: true + + '@parcel/watcher-linux-arm-musl@2.5.6': + optional: true + + '@parcel/watcher-linux-arm64-glibc@2.5.6': + optional: true + + '@parcel/watcher-linux-arm64-musl@2.5.6': + optional: true + + '@parcel/watcher-linux-x64-glibc@2.5.6': + optional: true + + '@parcel/watcher-linux-x64-musl@2.5.6': + optional: true + + '@parcel/watcher-win32-arm64@2.5.6': + optional: true + + '@parcel/watcher-win32-ia32@2.5.6': + optional: true + + '@parcel/watcher-win32-x64@2.5.6': + optional: true + + '@parcel/watcher@2.5.6': + dependencies: + detect-libc: 2.1.2 + is-glob: 4.0.3 + node-addon-api: 7.1.1 + picomatch: 4.0.4 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.6 + '@parcel/watcher-darwin-arm64': 2.5.6 + '@parcel/watcher-darwin-x64': 2.5.6 + '@parcel/watcher-freebsd-x64': 2.5.6 + '@parcel/watcher-linux-arm-glibc': 2.5.6 + '@parcel/watcher-linux-arm-musl': 2.5.6 + '@parcel/watcher-linux-arm64-glibc': 2.5.6 + '@parcel/watcher-linux-arm64-musl': 2.5.6 + '@parcel/watcher-linux-x64-glibc': 2.5.6 + '@parcel/watcher-linux-x64-musl': 2.5.6 + '@parcel/watcher-win32-arm64': 2.5.6 + '@parcel/watcher-win32-ia32': 2.5.6 + '@parcel/watcher-win32-x64': 2.5.6 + + '@tailwindcss/cli@4.3.0': + dependencies: + '@parcel/watcher': 2.5.6 + '@tailwindcss/node': 4.3.0 + '@tailwindcss/oxide': 4.3.0 + enhanced-resolve: 5.21.3 + mri: 1.2.0 + picocolors: 1.1.1 + tailwindcss: 4.3.0 + + '@tailwindcss/node@4.3.0': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.21.3 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.3.0 + + '@tailwindcss/oxide-android-arm64@4.3.0': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.3.0': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.3.0': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.3.0': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.3.0': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.3.0': + optional: true + + '@tailwindcss/oxide@4.3.0': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.3.0 + '@tailwindcss/oxide-darwin-arm64': 4.3.0 + '@tailwindcss/oxide-darwin-x64': 4.3.0 + '@tailwindcss/oxide-freebsd-x64': 4.3.0 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.0 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.0 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.0 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.0 + '@tailwindcss/oxide-linux-x64-musl': 4.3.0 + '@tailwindcss/oxide-wasm32-wasi': 4.3.0 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.0 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.0 + + ansi-regex@5.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + concurrently@9.2.1: + dependencies: + chalk: 4.1.2 + rxjs: 7.8.2 + shell-quote: 1.8.3 + supports-color: 8.1.1 + tree-kill: 1.2.2 + yargs: 17.7.2 + + detect-libc@2.1.2: {} + + emoji-regex@8.0.0: {} + + enhanced-resolve@5.21.3: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + + escalade@3.2.0: {} + + get-caller-file@2.0.5: {} + + graceful-fs@4.2.11: {} + + has-flag@4.0.0: {} + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + jiti@2.7.0: {} + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + mri@1.2.0: {} + + node-addon-api@7.1.1: {} + + picocolors@1.1.1: {} + + picomatch@4.0.4: {} + + require-directory@2.1.1: {} + + rxjs@7.8.2: + dependencies: + tslib: 2.8.1 + + shell-quote@1.8.3: {} + + source-map-js@1.2.1: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + tailwindcss@4.3.0: {} + + tapable@2.3.3: {} + + tree-kill@1.2.2: {} + + tslib@2.8.1: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + y18n@5.0.8: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 diff --git a/scripts/import-posts.py b/scripts/import-posts.py new file mode 100644 index 0000000..5c7eeb0 --- /dev/null +++ b/scripts/import-posts.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 +""" +Import posts from ~/projects/ginger/posts.csv into Hugo content. +Only imports posts whose generated_image exists in the selected images folder. +Run from the site root: python3 scripts/import-posts.py +""" +import csv +import json +import os +import shutil +from pathlib import Path + +GINGER = Path.home() / "projects" / "ginger" +CSV_PATH = GINGER / "posts.csv" +IMG_DIR = GINGER / "images" / "final" / "selected" +SITE = Path(__file__).parent.parent +CONTENT = SITE / "content" / "posts" +DATA_DIR = SITE / "data" + +CONTENT.mkdir(parents=True, exist_ok=True) +DATA_DIR.mkdir(parents=True, exist_ok=True) + +# Collect available images +available = {f.name for f in IMG_DIR.iterdir() if f.is_file()} + +matched = [] +with open(CSV_PATH, newline="", encoding="utf-8") as f: + reader = csv.DictReader(f) + for row in reader: + gen = row.get("generated_image", "").strip() + if gen and gen in available: + matched.append(row) + +print(f"Matched {len(matched)} posts out of {len(available)} available images") + +# Sort deterministically by generated_image filename for stable plate numbers +matched.sort(key=lambda r: r["generated_image"]) + +for idx, row in enumerate(matched, start=1): + plate = f"{idx:03d}" + gen_img = row["generated_image"].strip() + slug = gen_img.replace(".png", "") + title = row["title"].strip() + desc = row["description"].strip().replace('"', '\\"') + raw_cat = row.get("category", "").strip() + raw_tags = row.get("tags", "").strip() + + cats = [c.strip() for c in raw_cat.split(",") if c.strip()] + tags = [t.strip() for t in raw_tags.split(",") if t.strip()] + + cats_yaml = "\n".join(f' - "{c}"' for c in cats) + tags_yaml = "\n".join(f' - "{t}"' for t in tags) if tags else ' []' + + bundle = CONTENT / slug + bundle.mkdir(exist_ok=True) + + src_img = IMG_DIR / gen_img + dst_img = bundle / gen_img + if not dst_img.exists(): + shutil.copy2(src_img, dst_img) + + md = f"""--- +title: "{title.replace('"', '\\"')}" +description: "{desc}" +plate: "{plate}" +slug: "{slug}" +image: "{gen_img}" +weight: {idx} +categories: +{cats_yaml} +tags: +{tags_yaml} +--- +""" + (bundle / "index.md").write_text(md, encoding="utf-8") + +print(f"Created {len(matched)} page bundles in {CONTENT}") + +# Write data/issues.json +issues = [ + { + "id": "01", + "number": "№ 01", + "title": "Fabric, Light & Gesture", + "season": "Spring MMXXVI", + "publishedAt": "2026-03-21", + "blurb": "The inaugural plates — one hundred photographs gathered across ateliers, streets, and quiet hotel corridors.", + "status": "current" + }, + { + "id": "02", + "number": "№ 02", + "title": "The Glasshouse", + "season": "Summer MMXXVI", + "publishedAt": "2026-06-21", + "blurb": "Forthcoming — a study in transparency, condensation, and the long late light of June.", + "status": "forthcoming" + }, + { + "id": "03", + "number": "№ 03", + "title": "Atelier After Hours", + "season": "Autumn MMXXVI", + "publishedAt": "2026-09-22", + "blurb": "Forthcoming — the slow work of cloth and thread, photographed when the studio is half-empty.", + "status": "forthcoming" + } +] +(DATA_DIR / "issues.json").write_text(json.dumps(issues, indent=2), encoding="utf-8") +print("Wrote data/issues.json") diff --git a/static/assets/roux-mark.svg b/static/assets/roux-mark.svg new file mode 100644 index 0000000..c4780b5 --- /dev/null +++ b/static/assets/roux-mark.svg @@ -0,0 +1,43 @@ + + Roux — peony mark + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/static/js/app.js b/static/js/app.js new file mode 100644 index 0000000..9d26430 --- /dev/null +++ b/static/js/app.js @@ -0,0 +1,452 @@ +/* ROUX — app.js */ +(function () { + 'use strict'; + + // ── Data (injected by Hugo into a JSON script tag) + let POSTS = []; + try { + const el = document.getElementById('roux-data'); + if (el) POSTS = JSON.parse(el.textContent) || []; + } catch (e) { console.warn('roux-data parse failed', e); } + + const STOP = new Set(['the','a','an','of','and','in','on','at','by','with','is','to','for','from','as','into','onto','its','it','that','this','but','or','be','not','no','one','two','three']); + + // ── Helpers + function esc(s) { return String(s).replace(/[&<>"]/g, c => ({'&':'&','<':'<','>':'>','"':'"'}[c])); } + + function highlight(text, terms) { + if (!terms.length) return esc(text); + const re = new RegExp('(' + terms.map(t => t.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|') + ')', 'ig'); + return esc(text).replace(re, '$1'); + } + + // ── Inverted search index + const INDEX = (() => { + const map = new Map(); + function add(token, idx, weight) { + const t = token.toLowerCase(); + if (!t || t.length < 2 || STOP.has(t)) return; + let b = map.get(t); + if (!b) { b = new Map(); map.set(t, b); } + b.set(idx, (b.get(idx) || 0) + weight); + } + function tok(s) { return (s || '').toLowerCase().split(/[^a-z0-9àâäéèêëîïôöùûüçœæñ]+/i).filter(Boolean); } + + POSTS.forEach((p, i) => { + tok(p.title).forEach(t => add(t, i, 6)); + (p.categories || []).forEach(c => tok(c).forEach(t => add(t, i, 4))); + (p.tags || []).forEach(tag => tok(tag).forEach(t => add(t, i, 5))); + tok(p.description).forEach(t => add(t, i, 1)); + tok(p.id).forEach(t => add(t, i, 8)); + }); + + return function search(q) { + const tokens = tok(q); + if (!tokens.length) return null; + const perToken = tokens.map(tok => { + const merged = new Map(); + for (const [term, b] of map) { + if (term.startsWith(tok)) { + const factor = term === tok ? 1.0 : tok.length / term.length; + for (const [pi, w] of b) merged.set(pi, (merged.get(pi) || 0) + w * factor); + } + } + return merged; + }); + const first = perToken[0]; + const scores = new Map(); + for (const [idx, w] of first) { + let total = w, ok = true; + for (let i = 1; i < perToken.length; i++) { + const v = perToken[i].get(idx); + if (!v) { ok = false; break; } + total += v; + } + if (ok) scores.set(idx, total); + } + return Array.from(scores.entries()) + .sort((a, b) => b[1] - a[1]) + .map(([i]) => POSTS[i]); + }; + })(); + + // ── Masthead date + const mhDate = document.getElementById('mhDate'); + if (mhDate) { + const d = new Date(); + mhDate.textContent = d.toLocaleDateString('en-GB', { day:'numeric', month:'long', year:'numeric' }); + } + + // ── Count display + const countEl = document.getElementById('count'); + function setCount(n) { + if (!countEl) return; + countEl.innerHTML = `${String(n).padStart(3,'0')} ${n === 1 ? 'post' : 'posts'}`; + } + setCount(POSTS.length); + + // ── Tabs: sync active state with current URL + function syncTabs() { + const tabs = document.querySelectorAll('.tabs button[data-cat]'); + const path = location.pathname; + tabs.forEach(btn => { + const cat = btn.dataset.cat; + const active = (cat === 'All' && (path === '/' || path === '/posts/' || path.startsWith('/posts'))) + || (cat !== 'All' && path.toLowerCase().includes(cat.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, ''))); + btn.setAttribute('aria-pressed', active ? 'true' : 'false'); + }); + } + syncTabs(); + + // Tab click → navigate to category page + document.addEventListener('click', e => { + const btn = e.target.closest('.tabs button[data-cat]'); + if (!btn) return; + const cat = btn.dataset.cat; + if (cat === 'All') navigate('/'); + else navigate('/categories/' + cat.toLowerCase().replace(/[\s,]+/g, '-').replace(/[^a-z0-9-]/g, '') + '/'); + }); + + // ── Search popup + const searchInput = document.getElementById('searchInput'); + const searchPop = document.getElementById('searchpop'); + + function allCats() { + const s = new Set(); + POSTS.forEach(p => (p.categories || []).forEach(c => s.add(c))); + return Array.from(s).slice(0, 8); + } + function allTags() { + const freq = new Map(); + POSTS.forEach(p => (p.tags || []).forEach(t => freq.set(t, (freq.get(t)||0)+1))); + return Array.from(freq.entries()).sort((a,b)=>b[1]-a[1]).slice(0,10).map(([t])=>t); + } + + function renderSearchPop(q) { + if (!searchPop) return; + if (!q) { + const cats = allCats(); + const tags = allTags(); + searchPop.innerHTML = ` +
+
Categories ${cats.length}
+
+ ${cats.map(c => ``).join('')} +
+
+
+
Popular tags ${tags.length}
+
+ ${tags.map(t => ``).join('')} +
+
`; + searchPop.dataset.open = 'true'; + return; + } + const hits = INDEX(q) || []; + const terms = q.toLowerCase().split(/\s+/).filter(t => t.length > 1); + if (!hits.length) { + searchPop.innerHTML = `

No plates match — try gothic, warrior, or neon.

`; + searchPop.dataset.open = 'true'; + return; + } + const shown = hits.slice(0, 6); + searchPop.innerHTML = ` +
+
Plates ${hits.length}
+
+ ${shown.map(p => ` + `).join('')} +
+
`; + searchPop.dataset.open = 'true'; + } + + if (searchInput) { + searchInput.addEventListener('input', () => renderSearchPop(searchInput.value.trim())); + searchInput.addEventListener('focus', () => renderSearchPop(searchInput.value.trim())); + document.addEventListener('keydown', e => { + if ((e.metaKey || e.ctrlKey) && e.key === 'k') { e.preventDefault(); searchInput.focus(); renderSearchPop(''); } + if (e.key === 'Escape') closeSearch(); + }); + } + + if (searchPop) { + searchPop.addEventListener('click', e => { + const btn = e.target.closest('[data-jump]'); + if (btn) { closeSearch(); navigate(btn.dataset.jump); } + }); + } + + document.addEventListener('click', e => { + if (searchPop && searchPop.dataset.open === 'true' && !e.target.closest('.subhead')) closeSearch(); + }); + + function closeSearch() { + if (searchPop) { searchPop.dataset.open = 'false'; searchPop.innerHTML = ''; } + if (searchInput) searchInput.blur(); + } + + // ── Lightbox + const lb = document.getElementById('lb'); + const lbTrack = document.getElementById('lbTrack'); + const lbMeta = document.getElementById('lbMeta'); + const lbThumbs = document.getElementById('lbThumbs'); + const lbIndex = document.getElementById('lbIndex'); + + let lbList = []; // current scoped post list + let lbIdx = -1; // index into lbList + let lbBuilt = false; + + function lbOpen(slug, scopedList) { + lbList = scopedList || POSTS; + const idx = lbList.findIndex(p => p.slug === slug); + if (idx === -1) return; + lbIdx = idx; + if (!lbBuilt) buildLbSlides(); + lb.dataset.open = 'true'; + document.body.style.overflow = 'hidden'; + goToSlide(lbIdx, false); + lbBuildMeta(lbList[lbIdx]); + lbBuildThumbs(); + } + + function lbClose() { + if (!lb) return; + lb.dataset.open = 'false'; + document.body.style.overflow = ''; + // pop back to gallery if we're on a single-post URL + if (window.__ROUX_OPEN_SLUG) { + navigate('/'); + } + } + + function buildLbSlides() { + if (!lbTrack) return; + lbTrack.innerHTML = lbList.map((p, i) => { + const imgSrc = p.card || p.thumb || ''; + return `
+
+ ${esc(p.title)} +
+
`; + }).join(''); + lbBuilt = true; + // Preload neighbors + preloadNeighbors(lbIdx); + } + + function goToSlide(idx, smooth = true) { + if (!lbTrack) return; + lbIdx = Math.max(0, Math.min(idx, lbList.length - 1)); + lbTrack.style.transition = smooth ? '' : 'none'; + lbTrack.style.transform = `translateX(-${lbIdx * 100}%)`; + if (!smooth) lbTrack.getBoundingClientRect(); // force reflow + if (lbIndex) { + lbIndex.innerHTML = `${String(lbIdx + 1).padStart(3,'0')} / ${lbList.length}`; + } + lbBuildMeta(lbList[lbIdx]); + syncThumbs(); + preloadNeighbors(lbIdx); + } + + function preloadNeighbors(idx) { + if (!lbTrack) return; + [-1, 0, 1, 2].forEach(d => { + const ni = idx + d; + if (ni < 0 || ni >= lbList.length) return; + const slide = lbTrack.querySelector(`.lb__slide[data-i="${ni}"]`); + if (!slide) return; + const img = slide.querySelector('img'); + if (img && !img.src) img.src = lbList[ni].card || lbList[ni].thumb || ''; + }); + } + + function lbBuildMeta(p) { + if (!lbMeta || !p) return; + const cats = (p.categories || []).join(', '); + const tags = (p.tags || []).slice(0, 8); + lbMeta.innerHTML = ` +
${esc(cats)}
+

${esc(p.title)}

+

${esc(p.description)}

+
+
Plate
№ ${esc(p.id)}
+
Category
${esc((p.categories||['—'])[0])}
+
+
${tags.map(t => `${esc(t)}`).join('')}
+ `; + + document.getElementById('lbCopy')?.addEventListener('click', function () { + const url = new URL(this.dataset.url, location.origin).href; + navigator.clipboard.writeText(url).then(() => { + this.classList.add('is-ok'); + this.querySelector('.lb__sh-l').textContent = 'Copied!'; + setTimeout(() => { this.classList.remove('is-ok'); this.querySelector('.lb__sh-l').textContent = 'Copy link'; }, 2000); + }); + }); + } + + function lbBuildThumbs() { + if (!lbThumbs) return; + lbThumbs.innerHTML = lbList.map((p, i) => + `` + ).join(''); + lbThumbs.addEventListener('click', e => { + const btn = e.target.closest('.lb__thumb'); + if (btn) goToSlide(parseInt(btn.dataset.i)); + }); + } + + function syncThumbs() { + if (!lbThumbs) return; + lbThumbs.querySelectorAll('.lb__thumb').forEach((b, i) => { + b.setAttribute('aria-current', i === lbIdx ? 'true' : 'false'); + }); + const active = lbThumbs.querySelector('.lb__thumb[aria-current="true"]'); + if (active) active.scrollIntoView({ inline: 'center', behavior: 'smooth' }); + } + + // Lightbox controls + if (lb) { + lb.addEventListener('click', e => { + const act = e.target.closest('[data-act]')?.dataset.act; + if (act === 'close') lbClose(); + else if (act === 'prev') goToSlide(lbIdx - 1); + else if (act === 'next') goToSlide(lbIdx + 1); + }); + document.addEventListener('keydown', e => { + if (lb.dataset.open !== 'true') return; + if (e.key === 'Escape') { lbClose(); } + if (e.key === 'ArrowLeft') { e.preventDefault(); goToSlide(lbIdx - 1); } + if (e.key === 'ArrowRight') { e.preventDefault(); goToSlide(lbIdx + 1); } + }); + + // Touch swipe + let touchX = null; + lb.addEventListener('touchstart', e => { touchX = e.touches[0].clientX; }, { passive: true }); + lb.addEventListener('touchend', e => { + if (touchX === null) return; + const dx = e.changedTouches[0].clientX - touchX; + if (Math.abs(dx) > 50) { dx < 0 ? goToSlide(lbIdx + 1) : goToSlide(lbIdx - 1); } + touchX = null; + }); + } + + // ── Card clicks → open lightbox (no full page navigation for same-origin) + document.addEventListener('click', e => { + const card = e.target.closest('.card[data-slug]'); + if (!card) return; + e.preventDefault(); + const slug = card.dataset.slug; + const visibleSlugs = Array.from(document.querySelectorAll('.card[data-slug]')).map(c => c.dataset.slug); + const scopedList = POSTS.filter(p => visibleSlugs.includes(p.slug)); + // Update URL without page reload + history.pushState({ slug }, '', card.href); + lbOpen(slug, scopedList.length ? scopedList : POSTS); + }); + + // Handle browser back/forward + window.addEventListener('popstate', e => { + if (lb && lb.dataset.open === 'true') { + if (!e.state?.slug) { lb.dataset.open = 'false'; document.body.style.overflow = ''; } + } + }); + + // ── Ribbon + const ribbon = document.getElementById('ribbon'); + const ribbonClose = document.getElementById('ribbonClose'); + if (ribbonClose && ribbon) { + if (sessionStorage.getItem('ribbon-closed')) ribbon.classList.add('hidden'); + ribbonClose.addEventListener('click', () => { + ribbon.classList.add('hidden'); + sessionStorage.setItem('ribbon-closed', '1'); + }); + } + + // ── Async page transitions (View Transitions API) + function isSameOrigin(url) { + try { return new URL(url).origin === location.origin; } catch { return false; } + } + + async function navigate(url) { + if (!isSameOrigin(url)) { location.href = url; return; } + + if (!document.startViewTransition) { + location.href = url; + return; + } + + document.startViewTransition(async () => { + const res = await fetch(url, { headers: { 'X-Requested-With': 'fetch' } }); + const text = await res.text(); + const doc = new DOMParser().parseFromString(text, 'text/html'); + + const newContent = doc.getElementById('content'); + const newData = doc.getElementById('roux-data'); + const oldContent = document.getElementById('content'); + + if (newContent && oldContent) { + oldContent.replaceWith(newContent); + } + if (newData) { + try { + POSTS = JSON.parse(newData.textContent) || []; + lbBuilt = false; // force rebuild on next open + } catch {} + } + + document.title = doc.title; + history.pushState({}, '', url); + + // Re-init page state + setCount(POSTS.length); + syncTabs(); + + // If new page has a slug to open + const script = doc.querySelector('script[data-open-slug]'); + const openSlug = window.__ROUX_OPEN_SLUG = doc.querySelector('[data-open-slug]')?.dataset.openSlug || null; + if (openSlug) { + const visibleSlugs = Array.from(document.querySelectorAll('.card[data-slug]')).map(c => c.dataset.slug); + const scoped = POSTS.filter(p => visibleSlugs.includes(p.slug)); + lbOpen(openSlug, scoped.length ? scoped : POSTS); + } + }); + } + + // Intercept link clicks for async transitions + document.addEventListener('click', e => { + if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return; + const a = e.target.closest('a[href]'); + if (!a || a.target || a.hasAttribute('download')) return; + if (!isSameOrigin(a.href)) return; + // Skip lightbox card clicks (handled above) + if (a.closest('.card[data-slug]')) return; + // Skip anchor links + if (a.href.includes('#')) return; + e.preventDefault(); + navigate(a.href); + }); + + // ── On single-post pages: auto-open lightbox + if (window.__ROUX_OPEN_SLUG && POSTS.length) { + const visibleSlugs = Array.from(document.querySelectorAll('.card[data-slug]')).map(c => c.dataset.slug); + const scoped = POSTS.filter(p => visibleSlugs.includes(p.slug)); + lbOpen(window.__ROUX_OPEN_SLUG, scoped.length ? scoped : POSTS); + } + +})();