Code — how this page is built
Under the hood
The actual source of the components on this page, read straight from the repo. Copy it, read it, or open it on GitHub.
DecayGameview on GitHub ↗
Computes integrity from the hours since first visit; a seeded shuffle of character indices decides the rot order so decay is deterministic and monotonic across reloads.
'use client';
import * as React from 'react';
const KEY = 'kaspirius:decay:first';
const DECAY_DAYS = 7;
const TEXT =
'This page is dying. From the moment you first opened it, it began to rot — a little every hour, whether you watch or not. Nothing you do will bring it back. It does not reset. Some things are only allowed to happen once, and this is one of them. Come back tomorrow and there will be less of it. Eventually there will be nothing here at all, just the shape of where words used to be.';
// Deterministic order in which characters rot (seeded shuffle of indices).
function rotOrder(len: number): number[] {
const idx = Array.from({ length: len }, (_, i) => i);
let seed = 1337;
for (let i = len - 1; i > 0; i--) {
seed = (seed * 1103515245 + 12345) & 0x7fffffff;
const j = seed % (i + 1);
[idx[i], idx[j]] = [idx[j], idx[i]];
}
return idx;
}
export function DecayGame() {
const [integrity, setIntegrity] = React.useState<number | null>(null);
const order = React.useMemo(() => rotOrder(TEXT.length), []);
React.useEffect(() => {
let first = Number(localStorage.getItem(KEY));
if (!first) {
first = Date.now();
localStorage.setItem(KEY, String(first));
}
const update = () => {
const hours = (Date.now() - first) / 3_600_000;
setIntegrity(Math.max(0, 100 - (hours / (DECAY_DAYS * 24)) * 100));
};
update();
const id = window.setInterval(update, 5000);
return () => window.clearInterval(id);
}, []);
if (integrity == null) return null;
const rotCount = Math.round((1 - integrity / 100) * TEXT.length);
const rotted = new Set(order.slice(0, rotCount));
const chars = [...TEXT].map((ch, i) => (rotted.has(i) && ch !== ' ' ? '█' : ch));
return (
<div className="flex w-full max-w-xl flex-col items-center gap-6">
<p
className="text-center text-lg leading-relaxed"
style={{ opacity: 0.25 + (integrity / 100) * 0.75 }}
>
{chars.join('')}
</p>
<div className="w-full max-w-xs">
<div className="h-1.5 w-full overflow-hidden rounded-full bg-foreground/10">
<div className="h-full bg-[var(--accent-red)]" style={{ width: `${integrity}%` }} />
</div>
<div className="mt-2 text-center font-mono text-[11px] uppercase tracking-[0.12em] opacity-55">
{integrity.toFixed(1)}% remaining · never resets
</div>
</div>
</div>
);
}