Drop turtle, honor ?template= URL param, add warp easter egg

- Removed the cosmos turtle (CSS rules + auto-load probe + JS hook).
  Reduced-motion turtle branch removed too.
- ?template=editorial|swiss|cosmos URL param now wins over the value
  in data/links.json (and the cached localStorage fallback). Wired in
  both the pre-paint boot script and main() so deep links work
  without flashing the wrong template.
- New hidden easter egg: type the letters w-a-r-p anywhere on the
  page (no input focused) and the page reloads on the next template
  in the cycle editorial -> swiss -> cosmos -> editorial. The URL is
  updated with the new ?template= param so the override survives
  refresh and is shareable. A small "↯ <name>" toast pops up after
  the reload via sessionStorage handoff, fades after ~2.5s, respects
  prefers-reduced-motion.
- README documents both the URL param and the warp keyword.
This commit is contained in:
Joel Brock
2026-05-16 09:35:45 -07:00
parent c16ee37096
commit ff0abee349
5 changed files with 102 additions and 63 deletions

View File

@@ -284,10 +284,9 @@
});
}
function bootCosmos(theme) {
function bootCosmos() {
const root = document.documentElement;
const reducedMotion = matchMedia("(prefers-reduced-motion: reduce)").matches;
attachCosmosTurtle(theme);
if (reducedMotion) { root.classList.add("cosmos-static"); return; }
attachCosmosCursor();
attachCosmosComets();
@@ -566,19 +565,44 @@
});
}
function attachCosmosTurtle(theme) {
const src = (theme && theme.turtle) || "assets/img/turtle.png";
const probe = new Image();
probe.onload = () => {
const t = document.createElement("img");
t.src = src;
t.alt = "";
t.className = "cosmos-turtle";
t.setAttribute("aria-hidden", "true");
document.body.appendChild(t);
};
probe.onerror = () => {};
probe.src = src;
function attachWarpEgg() {
const order = ["editorial", "swiss", "cosmos"];
let buf = "";
const KEY = "warp";
document.addEventListener("keydown", (e) => {
const tgt = e.target;
if (tgt && tgt.matches && tgt.matches("input, textarea, [contenteditable]")) return;
if (!e.key || e.key.length !== 1) return;
buf = (buf + e.key.toLowerCase()).slice(-KEY.length);
if (buf !== KEY) return;
buf = "";
const cur = document.documentElement.dataset.template || "editorial";
const next = order[(order.indexOf(cur) + 1) % order.length];
try { sessionStorage.setItem("dlstack-warp-toast", next); } catch (err) {}
const url = new URL(location.href);
url.searchParams.set("template", next);
location.replace(url.toString());
});
let pending = null;
try { pending = sessionStorage.getItem("dlstack-warp-toast"); } catch (err) {}
if (!pending) return;
try { sessionStorage.removeItem("dlstack-warp-toast"); } catch (err) {}
const toast = document.createElement("div");
toast.className = "warp-toast";
toast.setAttribute("role", "status");
const arrow = document.createElement("span");
arrow.className = "warp-toast__arrow";
arrow.setAttribute("aria-hidden", "true");
arrow.textContent = "↯";
const label = document.createElement("span");
label.className = "warp-toast__label";
label.textContent = pending;
toast.append(arrow, label);
document.body.appendChild(toast);
setTimeout(() => toast.classList.add("warp-toast--out"), 1600);
setTimeout(() => toast.remove(), 2500);
}
function attachCarousels(root) {
@@ -676,10 +700,14 @@
document.documentElement.style.setProperty("--accent", data.theme.accent);
}
const validTpl = new Set(["editorial", "swiss", "cosmos"]);
const tpl = validTpl.has(data.theme?.template) ? data.theme.template : "editorial";
let urlTpl = null;
try { urlTpl = new URL(location.href).searchParams.get("template"); } catch (e) {}
const tpl = validTpl.has(urlTpl) ? urlTpl
: validTpl.has(data.theme?.template) ? data.theme.template
: "editorial";
document.documentElement.dataset.template = tpl;
try { localStorage.setItem("dlstack-template", tpl); } catch (e) {}
if (tpl === "cosmos") bootCosmos(data.theme || {});
if (tpl === "cosmos") bootCosmos();
const p = data.profile || {};
const sections = data.sections || [];
@@ -719,6 +747,7 @@
attachCarousels(app);
attachReveal(app);
attachTheme();
attachWarpEgg();
}
if (document.readyState === "loading") {