This commit is contained in:
@@ -141,6 +141,117 @@
|
||||
"A late visitor gets the soft lamp."
|
||||
];
|
||||
|
||||
const secondLayer = {
|
||||
quotes: [
|
||||
"The archive does not keep score. It keeps chairs.",
|
||||
"Some families pass down recipes. This one also passes down tabs left open for later.",
|
||||
"A page can be a room if enough people arrive softly.",
|
||||
"The oldest link on the site still expects a hand cursor.",
|
||||
"If a memory changes, it may be trying to fit through a smaller door.",
|
||||
"The guestbook is not empty. It is holding its breath between signatures.",
|
||||
"Every backup is a small superstition against forgetting.",
|
||||
"Somewhere in the CSS, a lamp is deciding whether to stay on.",
|
||||
"The radio under the stairs only plays songs it has already missed.",
|
||||
"A train can leave a station and still remain in the family story.",
|
||||
"Kindness is the only password the house accepts without checking case.",
|
||||
"The website learned your pace and stopped rushing the hallway.",
|
||||
"A draft is just a letter still gathering courage.",
|
||||
"The cursor is a visitor. The margin is a host.",
|
||||
"If you hover long enough, even a heading may remember being handwritten.",
|
||||
"The old forum banner says: welcome back, even if you are new.",
|
||||
"Not all broken pages need repair. Some need a name.",
|
||||
"The site keeps its mysteries low to the ground, where tired people can reach them.",
|
||||
"A year is a folder that keeps renaming itself.",
|
||||
"Some evenings are survived by the exact right mug."
|
||||
],
|
||||
poems: [
|
||||
"A train in the rain / waits beside an empty platform / so memory can board.",
|
||||
"Grandma's radio / tuned between two stations / found us anyway.",
|
||||
"A flower pressed flat / still teaches the book / how spring once leaned.",
|
||||
"The lamp stayed awake / not because it was brave / but because someone might need it.",
|
||||
"Old usernames fade / but the welcome thread remains / warm at the top.",
|
||||
"I found a draft / with no ending / and felt less alone.",
|
||||
"The house at midnight / is mostly refrigerator hum / and unsent kindness.",
|
||||
"A calendar page / falls without bitterness / into tomorrow's hands.",
|
||||
"There is a road home / made entirely of small tabs / you meant to close.",
|
||||
"A cassette clicks / and the room becomes younger / for one more minute."
|
||||
],
|
||||
conversations: [
|
||||
["Nettle", "The ticket drawer is humming again.", "Morrow", "That is normal. It hums when someone is almost ready."],
|
||||
["Aunt Safiya", "Who put the screwdriver in the biscuit tin?", "Nadir", "A person with vision and no labelling discipline."],
|
||||
["Morrow", "The lamp keeps following the visitor.", "Etta", "Good. Lamps should have hobbies."],
|
||||
["Old Guest 14", "is this page still alive?", "Webmaster", "yes, but quietly, please. the baby is asleep."],
|
||||
["Nettle", "Filed under: feelings disguised as infrastructure.", "Morrow", "Approved without changes."],
|
||||
["Luma", "The radio said my name.", "Aunt Safiya", "Then say salaam back. Manners matter."],
|
||||
["Nadir", "The server made soup noises.", "Etta", "That means the deployment is nearly done."],
|
||||
["Morrow", "I found a page that says do not open.", "Nettle", "That usually means open gently."]
|
||||
],
|
||||
journals: [
|
||||
"Journal scrap, 2006: We changed the wallpaper and everyone pretended it was not emotional.",
|
||||
"Journal scrap, 2011: The old router blinked like it was trying to stay in the conversation.",
|
||||
"Journal scrap, 2018: I learned that homesickness can happen inside your own house.",
|
||||
"Journal scrap, 2024: Somebody laughed in the kitchen and the whole week became easier.",
|
||||
"Journal scrap, undated: The marigolds came back where nobody planted them.",
|
||||
"Journal scrap, undated: We kept the cracked mug because it knew too much.",
|
||||
"Journal scrap, winter: I saved a voicemail just to remember the background noise.",
|
||||
"Journal scrap, summer: The fan turned all afternoon and made the curtains look like boats."
|
||||
],
|
||||
warnings: [
|
||||
"COMFORT WARNING: this page may contain traces of old carpet, warm rice, and unfinished errands.",
|
||||
"SOFT ERROR: the archive attempted to be impressive and became sincere instead.",
|
||||
"NOTICE: do not stack heavy feelings on the top shelf.",
|
||||
"LEGACY WARNING: this layout remembers 800x600 and asks you to be respectful.",
|
||||
"SYSTEM MESSAGE: no achievement unlocked. You were kind anyway.",
|
||||
"CACHE NOTE: the page kept a copy of the good part.",
|
||||
"RECOVERY MODE: make tea, rename file, try again.",
|
||||
"PERMISSION DENIED: the sadness may enter, but it must wipe its feet."
|
||||
],
|
||||
dreams: [
|
||||
"Dream 01: a train full of empty mugs waited at a station called Later.",
|
||||
"Dream 02: the search box became a letterbox and returned every question with a family recipe.",
|
||||
"Dream 03: a radio under the stairs played tomorrow's weather in a grandparent's voice.",
|
||||
"Dream 04: the old homepage had a porch, and every link was a moth-wing-soft knock.",
|
||||
"Dream 05: someone had folded the sitemap into a paper flower and left it in a browser tab."
|
||||
],
|
||||
cassettes: [
|
||||
"CASSETTE A / side 1: You can hear plates, rain, and someone saying, no, leave the light on.",
|
||||
"CASSETTE A / side 2: Three seconds of silence, then laughter too close to the microphone.",
|
||||
"CASSETTE B / side 1: Nadir explains backups to a child using rice grains and a spoon.",
|
||||
"CASSETTE C / side 2: A song with no words, hummed badly, loved completely.",
|
||||
"CASSETTE D / side ?: The tape label only says for when the house feels far away."
|
||||
],
|
||||
fakeUsers: [
|
||||
"sunnydialup88: first!!!! but emotionally",
|
||||
"auntie-admin: please stop uploading files named newnewnewfinal",
|
||||
"railway_morrow: platform 3 smells like rain today",
|
||||
"nettle_mod: moved thread from Bugs to Feelings",
|
||||
"luma-lamp: does anyone else hear the margins singing",
|
||||
"guest_000: I signed this once and then grew up"
|
||||
],
|
||||
seasonal: {
|
||||
winter: "The archive put an extra blanket on the footer.",
|
||||
spring: "A pressed flower appeared between two cached pages.",
|
||||
summer: "The page opened a window and let the fan turn the silence.",
|
||||
autumn: "The old links sound like leaves when the cursor passes."
|
||||
},
|
||||
homepageTakeovers: [
|
||||
"For one rare minute, the homepage believes it is an old family desktop.",
|
||||
"The dashboard has become a late-night noticeboard with one pin missing.",
|
||||
"The homepage found its old forum skin in a drawer and is trying it on."
|
||||
],
|
||||
roomLinks: [
|
||||
["/play/radio-room.html", "radio room"],
|
||||
["/play/guestbook-1999.html", "guestbook 1999"],
|
||||
["/play/do-not-open.html", "do not open"],
|
||||
["/play/cassette-log.html", "cassette log"],
|
||||
["/play/train-platform.html", "train platform"],
|
||||
["/play/forgotten-draft.html", "forgotten draft"],
|
||||
["/play/corrupted-recipe.html", "corrupted recipe"],
|
||||
["/play/terminal-cupboard.html", "terminal cupboard"],
|
||||
["/play/patience-game.html", "patience game"]
|
||||
]
|
||||
};
|
||||
|
||||
function readState() {
|
||||
try {
|
||||
return JSON.parse(localStorage.getItem(KEY) || "{}");
|
||||
@@ -186,10 +297,13 @@
|
||||
function rememberVisit() {
|
||||
const visits = (state.visits || 0) + 1;
|
||||
const seen = Array.isArray(state.seen) ? state.seen : [];
|
||||
const pathCounts = { ...(state.pathCounts || {}) };
|
||||
pathCounts[path] = (pathCounts[path] || 0) + 1;
|
||||
const next = {
|
||||
...state,
|
||||
visits,
|
||||
lastPath: path,
|
||||
pathCounts,
|
||||
seen: Array.from(new Set([...seen, path])).slice(-80),
|
||||
firstSeen: state.firstSeen || new Date().toISOString(),
|
||||
lastSeen: new Date().toISOString()
|
||||
@@ -326,7 +440,8 @@
|
||||
[
|
||||
["/play/left-behind.html", "left behind"],
|
||||
["/play/dream-corridor.html", "dream corridor"],
|
||||
["/play/kitchen-light.html", "kitchen light"]
|
||||
["/play/kitchen-light.html", "kitchen light"],
|
||||
...secondLayer.roomLinks
|
||||
].forEach(([href, label], index) => {
|
||||
const link = document.createElement("a");
|
||||
link.className = "hidden-secret-link";
|
||||
@@ -339,10 +454,289 @@
|
||||
|
||||
function enhanceErrors() {
|
||||
if (document.title.match(/404|not found/i) || document.body.textContent.match(/404|not found/i)) {
|
||||
toast("This page is missing, but you are not. Try the sitemap, or sit here a second.");
|
||||
toast(pick([
|
||||
"This page is missing, but you are not. Try the sitemap, or sit here a second.",
|
||||
"404: the page went to check on the rice and has not returned.",
|
||||
"The address is wrong, but the welcome is still valid.",
|
||||
"Nothing is here except a very apologetic lamp."
|
||||
], "error"));
|
||||
}
|
||||
}
|
||||
|
||||
function addContinuity(memory) {
|
||||
const milestones = {
|
||||
2: "The site has placed your second visit beside the spare keys.",
|
||||
5: "A quiet ledger now lists you under people who came back.",
|
||||
9: "Nettle has started a folder called regular visitors, handle gently.",
|
||||
17: "Morrow left a platform ticket in the footer for you.",
|
||||
31: "The archive trusts you enough to misplace something important nearby.",
|
||||
64: "A very old counter turned over and made the sound of a cupboard closing."
|
||||
};
|
||||
if (milestones[memory.visits] && !state[`milestone_${memory.visits}`]) {
|
||||
window.setTimeout(() => toast(milestones[memory.visits], 6500), 1200);
|
||||
writeState({ ...readState(), [`milestone_${memory.visits}`]: true });
|
||||
}
|
||||
|
||||
const count = memory.pathCounts?.[path] || 0;
|
||||
if ([3, 7, 12].includes(count)) {
|
||||
window.setTimeout(() => toast([
|
||||
"This page recognizes the shape of your return.",
|
||||
"The paragraph straightened the cushions before you arrived.",
|
||||
"A repeat visit is the gentlest kind of knock."
|
||||
][[3, 7, 12].indexOf(count)], 6200), 1700);
|
||||
}
|
||||
}
|
||||
|
||||
function addSeasonAndDates(memory) {
|
||||
const month = now.getMonth();
|
||||
const day = now.getDate();
|
||||
const season = month < 2 || month === 11 ? "winter" : month < 5 ? "spring" : month < 8 ? "summer" : "autumn";
|
||||
if (Math.random() < 0.18) {
|
||||
window.setTimeout(() => toast(secondLayer.seasonal[season], 5200), 2600);
|
||||
}
|
||||
if (month === 4 && day === 9) {
|
||||
window.setTimeout(() => toast("Site birthday: the candles are imaginary, but the crumbs are real."), 900);
|
||||
}
|
||||
const first = memory.firstSeen ? new Date(memory.firstSeen) : null;
|
||||
if (first && memory.visits > 1 && first.getMonth() === month && first.getDate() === day) {
|
||||
window.setTimeout(() => toast("Visitor anniversary: the site saved a paper flower from your first day here.", 7000), 1400);
|
||||
}
|
||||
if (now.getMinutes() === 13) {
|
||||
window.setTimeout(() => toast("At minute thirteen, the radio under the stairs clears its throat."), 2100);
|
||||
}
|
||||
}
|
||||
|
||||
function addObjectConstellation(memory) {
|
||||
const rail = document.createElement("div");
|
||||
rail.className = "hidden-object-rail";
|
||||
rail.setAttribute("aria-label", "Hidden keepsake objects");
|
||||
const objects = [
|
||||
["lamp", "The lamp clicks once, then pretends it did not."],
|
||||
["mug", "The mug is chipped in exactly the familiar place."],
|
||||
["ticket", "The ticket says RETURN, but not to where."],
|
||||
["radio", "The radio hums between weather and memory."],
|
||||
["flower", "The pressed flower has kept its appointment with spring."]
|
||||
];
|
||||
objects.forEach(([name, message]) => {
|
||||
const button = document.createElement("button");
|
||||
button.type = "button";
|
||||
button.className = `hidden-keepsake hidden-keepsake--${name}`;
|
||||
button.title = name;
|
||||
button.textContent = { lamp: "i", mug: "u", ticket: "=", radio: "o", flower: "+" }[name];
|
||||
button.addEventListener("click", () => {
|
||||
const next = readState();
|
||||
next.keepsakes = Array.from(new Set([...(next.keepsakes || []), name]));
|
||||
writeState(next);
|
||||
toast(message);
|
||||
if (next.keepsakes.length >= objects.length) {
|
||||
window.setTimeout(() => toast("The five keepsakes align. Search for radio under stairs."), 1100);
|
||||
}
|
||||
});
|
||||
rail.appendChild(button);
|
||||
});
|
||||
document.body.appendChild(rail);
|
||||
}
|
||||
|
||||
function addWeatherWindow(memory) {
|
||||
if (memory.visits < 3 || !("geolocation" in navigator)) return;
|
||||
const button = document.createElement("button");
|
||||
button.className = "hidden-weather-window";
|
||||
button.type = "button";
|
||||
button.title = "Ask the outside window";
|
||||
button.textContent = "window";
|
||||
button.addEventListener("click", () => {
|
||||
toast("The window is checking whether the outside agrees with the archive.");
|
||||
navigator.geolocation.getCurrentPosition((pos) => {
|
||||
const { latitude, longitude } = pos.coords;
|
||||
fetch(`https://api.open-meteo.com/v1/forecast?latitude=${latitude.toFixed(3)}&longitude=${longitude.toFixed(3)}¤t=temperature_2m,precipitation,weather_code&timezone=auto`)
|
||||
.then((res) => res.json())
|
||||
.then((data) => {
|
||||
const current = data.current || {};
|
||||
const rain = Number(current.precipitation || 0) > 0;
|
||||
const temp = Math.round(Number(current.temperature_2m));
|
||||
toast(rain ? `Outside: rain. Inside: the archive moved a towel closer to the door. ${temp}C.` : `Outside: ${temp}C. Inside: possible comfort, mild nostalgia.`);
|
||||
})
|
||||
.catch(() => toast("The weather window fogged up, so the site invented indoor weather: quiet with a chance of tea."));
|
||||
}, () => toast("No outside weather today. The indoor forecast is lamp-light and manageable clouds."));
|
||||
});
|
||||
document.body.appendChild(button);
|
||||
}
|
||||
|
||||
function addOldWebLayer(memory) {
|
||||
if (Math.random() < 0.08 || memory.visits > 10) {
|
||||
const stamp = document.createElement("div");
|
||||
stamp.className = "hidden-oldweb-stamp";
|
||||
stamp.title = pick(secondLayer.fakeUsers, "fake-user");
|
||||
stamp.textContent = "best viewed with patience";
|
||||
stamp.addEventListener("click", () => toast(stamp.title));
|
||||
document.body.appendChild(stamp);
|
||||
}
|
||||
const comments = document.querySelector("#comments");
|
||||
if (comments && !comments.querySelector(".hidden-guestbook-line")) {
|
||||
const line = document.createElement("p");
|
||||
line.className = "hidden-guestbook-line";
|
||||
line.textContent = pick(secondLayer.fakeUsers, "comment-lore");
|
||||
comments.appendChild(line);
|
||||
}
|
||||
}
|
||||
|
||||
function addSourceRelics() {
|
||||
// RELIC: Aunt Safiya says source comments are the attic of the page.
|
||||
const marker = document.createComment("hidden-song: hum the lamp, hum the train, hum the long way home");
|
||||
document.documentElement.appendChild(marker);
|
||||
document.querySelectorAll("img[alt=''], img:not([alt])").forEach((img, index) => {
|
||||
if (index > 2) return;
|
||||
img.alt = pick([
|
||||
"A quiet image that remembers being taped into a scrapbook.",
|
||||
"An old visual keepsake, labelled by someone who arrived later.",
|
||||
"A picture with its shoes by the door."
|
||||
], `alt-${index}`);
|
||||
});
|
||||
}
|
||||
|
||||
function addSearchAndKeySecrets() {
|
||||
const search = document.querySelector("#search-input");
|
||||
if (search) {
|
||||
search.addEventListener("input", () => {
|
||||
const value = search.value.trim().toLowerCase();
|
||||
const routes = {
|
||||
"radio under stairs": "/play/radio-room.html",
|
||||
"guestbook 1999": "/play/guestbook-1999.html",
|
||||
"do not open": "/play/do-not-open.html",
|
||||
"cassette": "/play/cassette-log.html",
|
||||
"return ticket": "/play/train-platform.html",
|
||||
"unfinished letter": "/play/forgotten-draft.html",
|
||||
"burnt sugar": "/play/corrupted-recipe.html",
|
||||
"cupboard": "/play/terminal-cupboard.html",
|
||||
"patience": "/play/patience-game.html"
|
||||
};
|
||||
if (routes[value]) window.location.href = routes[value];
|
||||
if (value === "marigold") toast("Search result: pressed flower, May rain, a promise nobody announced.");
|
||||
if (value === "luma") toast("Search result: lamp-child, margin-song, brave small glow.");
|
||||
if (value === "nadir") toast("Search result: backups, train tickets, practical tenderness.");
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("keydown", (event) => {
|
||||
const chain = `${sessionStorage.getItem("zxh_second_chain") || ""}${event.key.toLowerCase()}`.slice(-18);
|
||||
sessionStorage.setItem("zxh_second_chain", chain);
|
||||
if (chain.endsWith("leave the light on")) window.location.href = "/play/kitchen-light.html";
|
||||
if (chain.endsWith("oldweb")) toast("A 2004 table layout briefly considers returning, then thinks better of it.");
|
||||
if (chain.endsWith("safiya")) toast("Aunt Safiya says the screwdriver is absolutely not in the biscuit tin.");
|
||||
if (chain.endsWith("luma")) playTinySong();
|
||||
});
|
||||
}
|
||||
|
||||
function addPatienceRewards(memory) {
|
||||
if (memory.visits < 2) return;
|
||||
let idleTimer = null;
|
||||
const startIdle = () => {
|
||||
window.clearTimeout(idleTimer);
|
||||
idleTimer = window.setTimeout(() => {
|
||||
toast(pick([
|
||||
"Thank you for waiting. The page used the time to remember a window.",
|
||||
"Patience noted. No badge will be shown, which is how the archive prefers it.",
|
||||
"A tiny secret achievement happened quietly and did not ask to be announced."
|
||||
], "idle"), 7000);
|
||||
const next = readState();
|
||||
next.patientMoments = (next.patientMoments || 0) + 1;
|
||||
writeState(next);
|
||||
}, 90000);
|
||||
};
|
||||
["mousemove", "keydown", "scroll", "click"].forEach((name) => document.addEventListener(name, startIdle, { passive: true }));
|
||||
startIdle();
|
||||
}
|
||||
|
||||
function addRareSecondLayer(memory) {
|
||||
const roll = Math.random();
|
||||
if ((path === "/" || path === "/index.html") && roll < 0.006) {
|
||||
document.body.classList.add("hidden-home-takeover");
|
||||
window.setTimeout(() => showDriftNote(pick(secondLayer.homepageTakeovers, "takeover"), "WELCOME_BACK.GIF\nUNDER_CONSTRUCTION\nSIGN_GUESTBOOK"), 600);
|
||||
} else if (roll < 0.002) {
|
||||
window.setTimeout(() => showDriftNote("A cassette starts by itself, then politely asks permission.", "play? y/n\n[no autoplay. the site has manners.]"), 1500);
|
||||
} else if (roll < 0.006) {
|
||||
window.setTimeout(() => toast(pick(secondLayer.dreams, "rare-dream"), 7000), 2000);
|
||||
} else if (roll < 0.014) {
|
||||
window.setTimeout(() => toast(pick(secondLayer.warnings, "rare-warning"), 6200), 2300);
|
||||
}
|
||||
}
|
||||
|
||||
function addPageSpecificSecrets(memory) {
|
||||
if (path.includes("/play/cassette-log")) {
|
||||
document.querySelectorAll("[data-cassette]").forEach((button, index) => {
|
||||
button.addEventListener("click", () => {
|
||||
toast(secondLayer.cassettes[index % secondLayer.cassettes.length], 7000);
|
||||
playTinySong();
|
||||
});
|
||||
});
|
||||
}
|
||||
if (path.includes("/play/patience-game")) {
|
||||
const target = document.querySelector("[data-patience-target]");
|
||||
const count = document.querySelector("[data-patience-count]");
|
||||
if (target && count) {
|
||||
let seconds = 0;
|
||||
setInterval(() => {
|
||||
seconds += 1;
|
||||
count.textContent = String(seconds);
|
||||
if ([30, 90, 180].includes(seconds)) {
|
||||
target.textContent = seconds === 30 ? "The lamp notices you are still here." : seconds === 90 ? "The train has not left without you." : "The room trusts your quiet.";
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
if (path.includes("/play/terminal-cupboard")) {
|
||||
const input = document.querySelector("[data-cupboard-input]");
|
||||
const log = document.querySelector("[data-cupboard-log]");
|
||||
const commands = {
|
||||
help: "commands: listen, inventory, tea, open, remember, exit",
|
||||
listen: "Behind the jars: a radio, rain, one sentence from 2003.",
|
||||
inventory: "one cracked mug; two return tickets; marigolds; screwdriver absent, allegedly.",
|
||||
tea: "The cupboard approves. Morale +1. Biscuit tin remains suspicious.",
|
||||
open: "The cupboard opens into another cupboard. This is a family tradition.",
|
||||
remember: "You remember a room you may never have visited.",
|
||||
exit: "The cupboard lets you leave with both hands full of nothing heavy."
|
||||
};
|
||||
input?.addEventListener("keydown", (event) => {
|
||||
if (event.key !== "Enter") return;
|
||||
const value = input.value.trim().toLowerCase();
|
||||
const line = document.createElement("p");
|
||||
line.textContent = `> ${value}\n${commands[value] || "The cupboard does not know that command, but respects the attempt."}`;
|
||||
log.appendChild(line);
|
||||
input.value = "";
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function addInvisibleHoverSecrets() {
|
||||
document.querySelectorAll("h1, h2").forEach((heading, index) => {
|
||||
if (index > 5) return;
|
||||
heading.classList.add("hidden-hover-memory");
|
||||
heading.dataset.hiddenMemory = pick([...secondLayer.quotes, ...secondLayer.poems], `heading-${index}`);
|
||||
});
|
||||
}
|
||||
|
||||
function playTinySong() {
|
||||
try {
|
||||
const AudioContext = window.AudioContext || window.webkitAudioContext;
|
||||
if (!AudioContext) return;
|
||||
const ctx = new AudioContext();
|
||||
const notes = [392, 440, 330, 294, 392];
|
||||
notes.forEach((freq, index) => {
|
||||
const osc = ctx.createOscillator();
|
||||
const gain = ctx.createGain();
|
||||
osc.frequency.value = freq;
|
||||
osc.type = "sine";
|
||||
gain.gain.setValueAtTime(0.0001, ctx.currentTime + index * 0.18);
|
||||
gain.gain.exponentialRampToValueAtTime(0.05, ctx.currentTime + index * 0.18 + 0.03);
|
||||
gain.gain.exponentialRampToValueAtTime(0.0001, ctx.currentTime + index * 0.18 + 0.16);
|
||||
osc.connect(gain);
|
||||
gain.connect(ctx.destination);
|
||||
osc.start(ctx.currentTime + index * 0.18);
|
||||
osc.stop(ctx.currentTime + index * 0.18 + 0.18);
|
||||
});
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
function escapeHtml(value) {
|
||||
return String(value).replace(/[&<>"']/g, (char) => ({
|
||||
"&": "&",
|
||||
@@ -363,5 +757,16 @@
|
||||
addRareEvents();
|
||||
addSecretLinks();
|
||||
enhanceErrors();
|
||||
addContinuity(memory);
|
||||
addSeasonAndDates(memory);
|
||||
addObjectConstellation(memory);
|
||||
addWeatherWindow(memory);
|
||||
addOldWebLayer(memory);
|
||||
addSourceRelics();
|
||||
addSearchAndKeySecrets();
|
||||
addPatienceRewards(memory);
|
||||
addRareSecondLayer(memory);
|
||||
addPageSpecificSecrets(memory);
|
||||
addInvisibleHoverSecrets();
|
||||
});
|
||||
}());
|
||||
|
||||
@@ -108,6 +108,143 @@
|
||||
margin-top: 0.8rem;
|
||||
}
|
||||
|
||||
.hidden-object-rail {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
bottom: 0.35rem;
|
||||
display: flex;
|
||||
gap: 0.3rem;
|
||||
transform: translateX(-50%);
|
||||
opacity: 0.18;
|
||||
transition: opacity 180ms ease;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.hidden-object-rail:hover,
|
||||
.hidden-object-rail:focus-within {
|
||||
opacity: 0.94;
|
||||
}
|
||||
|
||||
.hidden-keepsake {
|
||||
width: 1.35rem;
|
||||
height: 1.35rem;
|
||||
border: 1px solid color-mix(in oklab, var(--border) 72%, transparent);
|
||||
border-radius: 50%;
|
||||
background: color-mix(in oklab, var(--surface) 78%, transparent);
|
||||
color: var(--muted);
|
||||
font: 0.8rem/1 monospace;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.hidden-keepsake:hover,
|
||||
.hidden-keepsake:focus-visible {
|
||||
color: var(--fg);
|
||||
background: var(--surface);
|
||||
}
|
||||
|
||||
.hidden-weather-window {
|
||||
position: fixed;
|
||||
right: 0.7rem;
|
||||
top: 7.5rem;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
background: color-mix(in oklab, var(--surface) 84%, transparent);
|
||||
color: var(--muted);
|
||||
font-size: 0.72rem;
|
||||
padding: 0.25rem 0.45rem;
|
||||
opacity: 0.24;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.hidden-weather-window:hover,
|
||||
.hidden-weather-window:focus-visible {
|
||||
opacity: 1;
|
||||
color: var(--fg);
|
||||
}
|
||||
|
||||
.hidden-oldweb-stamp {
|
||||
position: fixed;
|
||||
right: 0.75rem;
|
||||
bottom: 4.2rem;
|
||||
max-width: 12rem;
|
||||
padding: 0.25rem 0.4rem;
|
||||
border: 1px dashed var(--border);
|
||||
background: var(--surface);
|
||||
color: var(--muted);
|
||||
font: 0.72rem/1.2 "Times New Roman", serif;
|
||||
text-align: center;
|
||||
opacity: 0.34;
|
||||
cursor: help;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.hidden-oldweb-stamp:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.hidden-guestbook-line {
|
||||
color: var(--muted);
|
||||
font-size: 0.86rem;
|
||||
font-family: "Times New Roman", serif;
|
||||
opacity: 0.78;
|
||||
}
|
||||
|
||||
.hidden-hover-memory {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.hidden-hover-memory:hover::after {
|
||||
content: attr(data-hidden-memory);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 100%;
|
||||
width: min(28rem, 80vw);
|
||||
margin-top: 0.25rem;
|
||||
padding: 0.55rem 0.65rem;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
background: var(--surface);
|
||||
color: var(--muted);
|
||||
font-size: 0.78rem;
|
||||
font-family: 'Noto', system-ui, sans-serif;
|
||||
font-weight: 400;
|
||||
line-height: 1.35;
|
||||
z-index: 30;
|
||||
box-shadow: 0 12px 28px color-mix(in oklab, #000 12%, transparent);
|
||||
}
|
||||
|
||||
body.hidden-home-takeover .db-root {
|
||||
filter: saturate(0.9) contrast(1.03);
|
||||
}
|
||||
|
||||
body.hidden-home-takeover .db-hero::before {
|
||||
content: "under construction, emotionally";
|
||||
display: inline-block;
|
||||
margin-bottom: 0.5rem;
|
||||
color: var(--muted);
|
||||
font: 0.82rem "Times New Roman", serif;
|
||||
}
|
||||
|
||||
.hidden-terminal {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
}
|
||||
|
||||
.hidden-terminal input {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
background: var(--code-bg);
|
||||
color: var(--fg);
|
||||
padding: 0.65rem;
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
.hidden-terminal-log {
|
||||
min-height: 10rem;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.hidden-secret-link {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
|
||||
Reference in New Issue
Block a user