From c6810548e4ac0357b4c0e482998a180396229ee5 Mon Sep 17 00:00:00 2001 From: 0xa0 Date: Tue, 22 Sep 2026 19:28:00 +0200 Subject: [PATCH] changed background --- css/style.css | 83 +++++ guestbook.php | 8 +- img/bg/forest-21.png | Bin 0 -> 13971 bytes img/bg/forest-4.png | Bin 0 -> 13774 bytes img/bg/forest-57.png | Bin 0 -> 13949 bytes img/bg/forest-93.png | Bin 0 -> 14119 bytes inc/backgrounds.php | 31 ++ inc/footer.php | 16 + inc/header.php | 22 +- tools/__pycache__/background.cpython-313.pyc | Bin 0 -> 23428 bytes tools/background.py | 299 +++++++++++++++++++ 11 files changed, 456 insertions(+), 3 deletions(-) create mode 100644 img/bg/forest-21.png create mode 100644 img/bg/forest-4.png create mode 100644 img/bg/forest-57.png create mode 100644 img/bg/forest-93.png create mode 100644 inc/backgrounds.php create mode 100644 tools/__pycache__/background.cpython-313.pyc create mode 100644 tools/background.py diff --git a/css/style.css b/css/style.css index 6a0bf70..14db4f7 100644 --- a/css/style.css +++ b/css/style.css @@ -186,3 +186,86 @@ button { padding-left: 1rem; color: var(--muted); } + +/* ── sky ──────────────────────────────────────────────────────────────── + Generated, not photographed. tools/background.py renders every style into + img/bg/; inc/header.php enumerates that directory and emits one custom + property per style, so --bg-img follows html[data-bg]. Only the matching + rule's url() is fetched. Each is Bayer ordered-dithered to a few grey + levels and upscaled with pixelated rendering so the cells stay crunchy. + Regenerate everything: python tools/background.py all */ +:root { + --bg: #060606; + /* opacity of the text-column scrim; raise for busier background styles */ + --scrim: .82; +} + +body { position: relative; } + +/* background layer */ +body::before { + content: ""; + position: fixed; + inset: 0; + z-index: -2; + background: #060606 var(--bg-img) center center / cover no-repeat; + image-rendering: pixelated; +} + +/* Readability scrim + diagonal hatch. + The first layer is a feathered vertical band, ~880px wide and centred on + the 680px text column, sitting above the artwork (z-index -2) but below + the content. It gives every background style a consistent dark bed to + read against instead of relying on each one being quiet in the middle, + and because the edges fade out there is no visible panel or card. */ +body::after { + content: ""; + position: fixed; + inset: 0; + z-index: -1; + pointer-events: none; + background: + linear-gradient(90deg, + transparent 0%, + rgba(4, 4, 4, var(--scrim)) 14%, + rgba(4, 4, 4, var(--scrim)) 86%, + transparent 100%), + radial-gradient(ellipse 70% 60% at 50% 38%, rgba(4, 4, 4, .32), transparent 82%), + repeating-linear-gradient(-45deg, rgba(240, 240, 240, .045) 0 1px, transparent 1px 8px); + background-size: 880px 100%, auto, auto; + background-position: center top, center, center; + background-repeat: no-repeat, no-repeat, repeat; +} + +/* cards sat on flat #161616 before; let the sky read through them */ +.status-card, +.spotify-card, +.post-body pre { background-color: rgba(6, 6, 6, .66); } +input, textarea { background: rgba(6, 6, 6, .66); } + +/* guestbook sign button */ +.btn-sign { + display: inline-flex; + align-items: center; + gap: .5rem; + background: var(--fg); + color: var(--bg); + border: 1px solid var(--fg); + padding: .5rem 1.4rem; + border-radius: 4px; + font: inherit; + cursor: pointer; + transition: background .12s ease, color .12s ease, transform .08s ease; +} +.btn-sign .arrow { transition: transform .15s ease; } +.btn-sign:hover:not(:disabled) { background: transparent; color: var(--fg); } +.btn-sign:hover:not(:disabled) .arrow { transform: translateX(3px); } +.btn-sign:active:not(:disabled) { transform: translateY(1px); } +.btn-sign:focus-visible { outline: 2px solid var(--muted); outline-offset: 2px; } +.btn-sign:disabled { opacity: .55; cursor: progress; } + +/* htmx swaps the label while the request is in flight */ +.btn-sign .pending { display: none; } +.btn-sign.htmx-request .idle { display: none; } +.btn-sign.htmx-request .pending { display: inline; } +.btn-sign.htmx-request .arrow { display: none; } diff --git a/guestbook.php b/guestbook.php index f8ea795..5cb77c7 100644 --- a/guestbook.php +++ b/guestbook.php @@ -98,12 +98,18 @@ require __DIR__ . '/inc/header.php';
- +
diff --git a/img/bg/forest-21.png b/img/bg/forest-21.png new file mode 100644 index 0000000000000000000000000000000000000000..7da5c766534c80115dd63c0f114672707c9d7dde GIT binary patch literal 13971 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 XzAwxH;2ezG00000NkvXXu0mjfqj~&M literal 0 HcmV?d00001 diff --git a/img/bg/forest-93.png b/img/bg/forest-93.png new file mode 100644 index 0000000000000000000000000000000000000000..6928e414696e5e49075ef10c0f60912593878ec5 GIT binary patch literal 14119 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 l3?ptttU& pathinfo($f, PATHINFO_FILENAME), $files); + sort($names); + return $names; +} + +function bg_default(): string +{ + $all = bg_styles(); + return in_array('flow', $all, true) ? 'flow' : ($all[0] ?? ''); +} + +/** A different style on every page load. */ +function bg_pick(): string +{ + $all = bg_styles(); + return $all ? $all[random_int(0, count($all) - 1)] : ''; +} diff --git a/inc/footer.php b/inc/footer.php index f820bcb..d6d7f11 100644 --- a/inc/footer.php +++ b/inc/footer.php @@ -10,5 +10,21 @@ $build = preg_match('/[0-9a-f]{7,40}/i', $build, $m) ? $m[0] : ($build ?: 'dev')
© · build: + + 1): ?> + + diff --git a/inc/header.php b/inc/header.php index 28db7db..f5e36a6 100644 --- a/inc/header.php +++ b/inc/header.php @@ -1,12 +1,30 @@ - + - +> <?= htmlspecialchars($page_title ?? SITE_TITLE) ?> + + + diff --git a/tools/__pycache__/background.cpython-313.pyc b/tools/__pycache__/background.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..00fcbe06abb3cd77a09ff61176733b822f317f1d GIT binary patch literal 23428 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 BRTBUJ literal 0 HcmV?d00001 diff --git a/tools/background.py b/tools/background.py new file mode 100644 index 0000000..792eb93 --- /dev/null +++ b/tools/background.py @@ -0,0 +1,299 @@ +#!/usr/bin/env python3 +"""Generate the dithered backgrounds for 0xa0.dev. + + python tools/background.py all # every style -> img/bg/ + python tools/background.py attractor # just one + python tools/background.py flow out.png # explicit destination + python tools/background.py forest img/bg/forest-2.png 21 # pick a seed + +All procedural, no source photos. Each is Bayer ordered-dithered to a few +grey levels so it matches the terminal aesthetic and stays small. Drop a new +PNG into img/bg/ and the site picks it up automatically -- inc/header.php +enumerates that directory, so nothing else needs editing. +""" +import numpy as np +from PIL import Image +import sys, os + +W, H = 1400, 875 +OUT = 'img/bg' + + +# -- helpers ---------------------------------------------------------- +def vnoise(res, seed, w=W, h=H): + r = np.random.default_rng(seed).random((res + 1, res + 1)) + im = Image.fromarray((r * 255).astype(np.uint8), 'L').resize((w, h), Image.BICUBIC) + return np.asarray(im, dtype=np.float64) / 255.0 + + +def fbm(octaves=5, base=3, seed=1, w=W, h=H): + o = np.zeros((h, w)); a = 1.0; t = 0.0 + for i in range(octaves): + o += a * vnoise(base * 2 ** i, seed + i * 101, w, h); t += a; a *= 0.5 + return o / t + + +def bayer(n): + m = np.array([[0.0]]); s = 1 + while s < n: + m = np.block([[4 * m, 4 * m + 2], [4 * m + 3, 4 * m + 1]]); s *= 2 + return (m + 0.5) / (s * s) + + +def calm(strength=0.55, width=0.32, shape=None): + """Damp the middle of the frame, where the text column sits.""" + h, w = shape or (H, W) + _, xx = np.mgrid[0:h, 0:w] + return (1 - strength) + strength * np.clip(np.abs(xx / w - 0.5) / width, 0, 1) ** 1.3 + + +def seg(c, x0, y0, x1, y1, val=1.0): + h, w = c.shape + n = int(max(abs(x1 - x0), abs(y1 - y0))) + 1 + xs = np.linspace(x0, x1, n).astype(int); ys = np.linspace(y0, y1, n).astype(int) + ok = (xs >= 0) & (xs < w) & (ys >= 0) & (ys < h) + np.add.at(c, (ys[ok], xs[ok]), val) + + +def dither(v, levels=4, mn=4, lo=6, hi=196, mode='bayer'): + """Quantise to `levels` greys. + + mode 'bayer': ordered dither against an n x n Bayer matrix. The matrix + size caps how many densities are distinguishable -- 4x4 gives 17 steps, + 8x8 gives 65 -- so bigger matrices band far less on smooth gradients at + the cost of a finer, less chunky texture. + + mode 'fs': Floyd-Steinberg error diffusion. No repeating pattern at all, + so gradients are smooth and organic, but it loses the woven/print look. + """ + v = np.clip(v, 0, 1) + h, w = v.shape + if mode == 'fs': + a = v.copy() * (levels - 1) + for yy in range(h): + for xx in range(w): + old = a[yy, xx] + new = round(min(max(old, 0), levels - 1)) + err = old - new + a[yy, xx] = new + if xx + 1 < w: a[yy, xx + 1] += err * 7 / 16 + if yy + 1 < h: + if xx: a[yy + 1, xx - 1] += err * 3 / 16 + a[yy + 1, xx] += err * 5 / 16 + if xx + 1 < w: a[yy + 1, xx + 1] += err * 1 / 16 + out = np.clip(a, 0, levels - 1) / (levels - 1) + else: + t = bayer(mn); th = np.tile(t, (h // mn + 1, w // mn + 1))[:h, :w] + s = v * (levels - 1); low = np.floor(s) + out = np.clip(low + (s - low > th), 0, levels - 1) / (levels - 1) + g = (lo + out * (hi - lo)).astype(np.uint8) + return Image.fromarray(g, 'L').convert('P', palette=Image.ADAPTIVE, colors=levels) + + +# -- styles ----------------------------------------------------------- +def flow(seed=29): + """Particles advected through a noise vector field; the bright filaments + are where the field converges and thousands of paths pile up.""" + rng = np.random.default_rng(seed) + ang = fbm(4, 3, seed) * np.pi * 3.0 + c = np.zeros((H, W)); n = 22000 + px = rng.random(n) * W; py = rng.random(n) * H + for _ in range(240): + a = ang[np.clip(py.astype(int), 0, H - 1), np.clip(px.astype(int), 0, W - 1)] + px += np.cos(a) * 1.3; py += np.sin(a) * 1.3 + ok = (px >= 0) & (px < W) & (py >= 0) & (py < H) + np.add.at(c, (py[ok].astype(int), px[ok].astype(int)), 1.0) + return np.clip(c / np.percentile(c, 99.5), 0, 1) ** 0.9 * calm() * 0.92, {} + + +def attractor(a=-1.7, b=1.8, cc=-1.9, d=-0.4, seed=3): + """Clifford attractor: x' = sin(a*y) + c*cos(a*x). The bright edges are + density caustics where orbits crowd together.""" + rng = np.random.default_rng(seed) + n = 260000; x = rng.uniform(-2, 2, n); y = rng.uniform(-2, 2, n) + c = np.zeros((H, W)) + for i in range(70): + x, y = np.sin(a * y) + cc * np.cos(a * x), np.sin(b * x) + d * np.cos(b * y) + if i > 8: + px = ((x + 2.6) / 5.2 * W).astype(int) + py = ((y + 2.6) / 5.2 * H).astype(int) + ok = (px >= 0) & (px < W) & (py >= 0) & (py < H) + np.add.at(c, (py[ok], px[ok]), 1.0) + return np.clip(c / np.percentile(c, 99.6), 0, 1) ** 0.75 * 0.95, {} + + +def truchet(cell=46, seed=5): + """Quarter-arc maze tiles. Regular and quiet; genuinely tileable.""" + c = np.zeros((H, W)); rng = np.random.default_rng(seed) + yy, xx = np.mgrid[0:H, 0:W] + for gy in range(0, H, cell): + for gx in range(0, W, cell): + sl = (slice(gy, min(gy + cell, H)), slice(gx, min(gx + cell, W))) + ly = yy[sl] - gy; lx = xx[sl] - gx + if rng.random() < 0.5: + d1 = np.hypot(lx, ly); d2 = np.hypot(lx - cell, ly - cell) + else: + d1 = np.hypot(lx - cell, ly); d2 = np.hypot(lx, ly - cell) + r = cell / 2.0 + c[sl] = np.maximum(np.clip(1 - np.abs(d1 - r) / 2.0, 0, 1), + np.clip(1 - np.abs(d2 - r) / 2.0, 0, 1)) + return c * 0.78, {'levels': 3} + + +def circuit(seed=13, g=16, traces=150): + """PCB-style routed traces at 45/90 degrees, with vias.""" + c = np.zeros((H, W)); rng = np.random.default_rng(seed) + dirs = [(g, 0), (-g, 0), (0, g), (0, -g), (g, g), (-g, g), (g, -g), (-g, -g)] + yy, xx = np.mgrid[0:H, 0:W] + for _ in range(traces): + x, y = int(rng.integers(0, W // g)) * g, int(rng.integers(0, H // g)) * g + dx, dy = dirs[int(rng.integers(len(dirs)))] + for _ in range(int(rng.integers(8, 30))): + nx, ny = x + dx, y + dy + if not (0 <= nx < W and 0 <= ny < H): + break + seg(c, x, y, nx, ny, 1.0); x, y = nx, ny + if rng.random() < 0.28: + dx, dy = dirs[int(rng.integers(len(dirs)))] + if rng.random() < 0.45: + c += np.clip(1 - np.abs(np.hypot(xx - x, yy - y) - 3.5) / 1.6, 0, 1) * 0.9 + return np.clip(c, 0, 1) * calm(0.5) * 0.72, {'levels': 3} + + +def reaction(seed=9, steps=3800): + """Gray-Scott reaction-diffusion. Striking but dense, so it is knocked + well back in tone to stay readable behind text.""" + gw, gh = 450, 282 + U = np.ones((gh, gw)); V = np.zeros((gh, gw)) + rng = np.random.default_rng(seed) + for _ in range(26): + sx, sy = int(rng.integers(12, gw - 12)), int(rng.integers(12, gh - 12)) + U[sy - 5:sy + 5, sx - 5:sx + 5] = 0.5 + V[sy - 5:sy + 5, sx - 5:sx + 5] = 0.25 + Du, Dv, F, k = 0.16, 0.08, 0.0545, 0.062 + + def lap(Z): + return (np.roll(Z, 1, 0) + np.roll(Z, -1, 0) + + np.roll(Z, 1, 1) + np.roll(Z, -1, 1) - 4 * Z) + + for _ in range(steps): + uvv = U * V * V + U += Du * lap(U) - uvv + F * (1 - U) + V += Dv * lap(V) + uvv - (F + k) * V + v = np.clip(V / max(V.max(), 1e-6), 0, 1) + v = np.asarray(Image.fromarray((v * 255).astype(np.uint8), 'L') + .resize((W, H), Image.BICUBIC)) / 255.0 + return v ** 1.1 * calm(0.45) * 0.42, {} + + +def ridge(seed=900, lines=40): + """Stacked ridgelines, Joy Division style.""" + c = np.zeros((H, W)) + for i in range(lines): + base = H * 0.10 + i * (H * 0.84 / lines) + prof = fbm(5, 4, seed + i * 7, w=W, h=8)[0] + amp = (H * 0.84 / lines) * 11.0 * (0.25 + 0.75 * np.exp(-((i / lines - 0.5) ** 2) / 0.055)) + ys = base - (prof - prof.mean()) * amp + for x in range(W - 1): + seg(c, x, ys[x], x + 1, ys[x + 1], 1.0) + return np.clip(c, 0, 1) * 0.85, {'levels': 3} + + +def topo(seed=11, bands=16): + """Iso-contour map of a fractal-noise height field.""" + h = fbm(6, 3, seed) + d = np.abs((h * bands) % 1.0 - 0.5) + return (np.clip(1 - d * 7.0, 0, 1) ** 2.2 * 0.7 + h * 0.12) * calm(0.4), {} + + +def _pine(c, cx, base, h, w, val): + """One tiered conifer, drawn as rows of spans so the edges stay blocky.""" + fh, fw = c.shape + top = int(base - h) + rows = np.arange(max(top, 0), min(int(base), fh)) + if rows.size == 0: + return + t = (rows - top) / max(h, 1.0) + tier = (t * 3.0) % 1.0 # three stacked skirts + hw = w * (0.10 + 0.90 * t) * (0.55 + 0.45 * tier) + for r, half in zip(rows, hw): + x0 = max(int(cx - half), 0); x1 = min(int(cx + half) + 1, fw) + if x1 > x0: + c[r, x0:x1] = val + + +def forest(seed=4, layers=4): + """1-bit pixel-art conifer forest. + + Composition follows the knitwear reference: dark starry sky across the + top (where the text column sits), a dithered mist band at the horizon, + then receding layers of pines. Trees are drawn bright against the dark + sky -- each gets a dark outline pass first, so overlapping trees stay + separate instead of merging into one white mass. Rendered small and + upscaled by CSS with image-rendering: pixelated, so it reads as sprite + art rather than a photo. + """ + fw, fh = 760, 475 + rng = np.random.default_rng(seed) + v = np.zeros((fh, fw)) + y = np.arange(fh)[:, None] / fh + ones = np.ones((1, fw)) + horizon = 0.66 + + # stars, denser toward the top of the sky + n = 440 + sx = rng.integers(0, fw, n) + sy = (rng.random(n) ** 2.3 * fh * horizon).astype(int) + v[sy, sx] = 1.0 + + # mist: a narrow glow hugging the horizon, not a wash over the whole + # middle. The ordered dither turns this band into the scattered + # transition that the knitwear reference has. + v = np.maximum(v, np.exp(-((y - horizon) ** 2) / 0.0040) * 0.26 * ones) + + # receding tree layers, far to near. Each tree gets a slightly larger + # dark pass first so overlapping trees stay separate; the outline hugs + # the shape rather than overshooting it. + for d in range(layers): + f = d / max(layers - 1, 1) + base = fh * (horizon + 0.02 + 0.34 * f ** 1.2) + count = int(120 * (1 - 0.80 * f)) + 8 + val = 0.38 + 0.36 * f + for _ in range(count): + cx = rng.random() * (fw + 140) - 70 + hgt = (20 + 74 * f ** 1.3) * (0.72 + 0.56 * rng.random()) + wid = hgt * (0.27 + 0.11 * rng.random()) + jitter = (rng.random() - 0.5) * 12 * (0.3 + f) + _pine(v, cx, base + jitter, hgt * 1.04 + 2, wid * 1.16 + 1.2, 0.0) + _pine(v, cx, base + jitter, hgt, wid, val) + + # a little ground haze at the very bottom for the nearest trees to sit on + v = np.maximum(v, np.clip((y - 0.96) / 0.04, 0, 1) * 0.30 * ones) + return v, {'levels': 2, 'mn': 8, 'hi': 205} + + +STYLES = {'flow': flow, 'attractor': attractor, 'truchet': truchet, + 'circuit': circuit, 'reaction': reaction, 'ridge': ridge, + 'topo': topo, 'forest': forest} + + +def render(name, dest=None, seed=None): + v, opts = STYLES[name](seed=seed) if seed is not None else STYLES[name]() + img = dither(v, **{**{'levels': 4, 'mn': 4}, **opts}) + dest = dest or os.path.join(OUT, name + '.png') + os.makedirs(os.path.dirname(dest) or '.', exist_ok=True) + img.save(dest, optimize=True) + a = np.asarray(img.convert('L')) + print(" %-10s -> %-22s %3dKB mean=%.0f" + % (name, dest, os.path.getsize(dest) // 1024, a.mean())) + + +if __name__ == '__main__': + what = sys.argv[1] if len(sys.argv) > 1 else 'all' + if what == 'all': + for n in STYLES: + render(n) + else: + dest = sys.argv[2] if len(sys.argv) > 2 else None + seed = int(sys.argv[3]) if len(sys.argv) > 3 else None + render(what, dest, seed)