Pushed the cosmos theme further:
- Cursor aurora — 600px soft cyan/violet/magenta halo follows the
pointer with lag (mix-blend-mode: screen, blur 8px). Fades in on
first move, fades out on pointerleave.
- Card 3D tilt — every cosmos card rotates up to ~6deg toward the
cursor on hover via custom-property-driven rotateX/rotateY, with a
cursor-tracking radial shimmer painted inside via mix-blend-mode:
screen. RAF-throttled. Skipped for testimonial + client tiles since
they have no chrome.
- Hero parallax — name, tagline, and drift-orb all shift relative to
cursor position via --cm-x / --cm-y custom properties set globally
from the pointer move handler.
- Shader: doubled the gravity-well strength (0.03 -> 0.06) and added
a click-driven ripple — pointerdown sets u_ripple_pos/u_ripple_age
uniforms; the shader propagates a cyan/magenta luminous ring of
displacement that decays over ~2s.
- Comets — 3 CSS-only streaks crossing the page on staggered 14/22/
19s loops with cyan/violet drop-shadow trails.
- Turtle — new .cosmos-turtle img auto-loads if assets/img/turtle.png
resolves (or theme.turtle URL is set). Floats in from the left,
arcs across, fades out off the right; pulses its aurora glow on a
4s bob. Reduced-motion users see it positioned statically.
- All new chrome respects prefers-reduced-motion: halo/comets hidden,
card tilt + parallax disabled, turtle pinned static.
Also adds section.headless = true (per user request): renders the
section body with no header/kicker chrome and a tighter top margin so
the contents read as nested under the prior section. Example JSON now
uses this to slide the testimonials carousel under the clients wall.
New `type: "testimonial"` with structured attribution
(quote/name/role/org/url/image/date) plus a `layout: "testimonials"`
section behavior that renders the items as a tasteful crossfade
carousel — one quote at a time, 7s auto-advance, prev/next nav, dot
indicators, swipe support, ←/→ keys, pause on hover/focus, ARIA
live region.
Reduced-motion users automatically get .carousel--stacked: every
testimonial visible at once, controls hidden, no auto-advance. A
single-item section also skips the carousel chrome.
Per-template treatment: editorial uses Fraunces italic for the curly
quote mark and the body, swiss strips uppercase from titles per prior
fix, cosmos glows the mark with the cyan/violet accent stack.
Section auto-detects the layout when the first item is a testimonial,
matching how the clients layout already works.
Swiss: drop all-caps on titles, soften heavy ink borders to muted rules
or remove them where background contrast carries the form, balance hero
name weights (smaller lighter first name vs heavier italic last name),
fix unreadable white description text on portfolio hover.
Editorial: enlarge the section "No" mark and set it in italic Fraunces so
it reads as typography instead of a tick, swap the first name into DM
Serif Display for a different J, sharpen the section number caption.
Client tile: contain custom logos at 86% so wide marks like
"The Cooperative Way" stop getting cropped to "operative".
New: optional `date` field on every item type (link/card/portfolio/
youtube/client). Accepts YYYY, YYYY-MM, or YYYY-MM-DD. Rendered
human-friendly with the raw ISO preserved in <time datetime>.
Documented in README and demonstrated in links.example.json.
A hand-rolled linktree alternative — pure static HTML/CSS/JS, no build
step. Drop on any shared host via SFTP and edit data/links.json to update.
Features
- File-driven content via data/links.json (links, projects, YouTube,
client tiles, portfolio pieces)
- Two interchangeable templates: editorial (Fraunces + paper + vermilion)
and swiss (Archivo grotesque, all-caps poster)
- Auto/light/dark theme toggle with no-flash boot script
- Auto-fetched favicons via Google S2 (with image-URL override)
- Lazy YouTube facades (no third-party JS until clicked)
- Adaptive client-logo grid
- Scroll-triggered reveal animations
- ~40 KB total payload, ~12 KB gzipped
The repo ships links.example.json as a demo; data/links.json is
gitignored so personal content stays out of the public repo.