registry/blocks/dev-snake.tsx
"use client";
/**
* A purely decorative snake that grazes across a contribution grid — a
* light head with a fading emerald tail, sweeping row by row. Original
* implementation of a common visual idea; no data, no interaction.
* Freezes to a static grid under prefers-reduced-motion.
*/
import { useEffect, useMemo, useState } from "react";
import { cn } from "@/lib/utils";
const WEEKS = 53;
const DAYS = 7;
const TRAIL = 6;
const levelClass = [
"bg-muted-foreground/12",
"bg-emerald-500/25",
"bg-emerald-500/45",
"bg-emerald-500/70",
"bg-emerald-500",
];
function baseLevel(week: number, day: number) {
const n = (week * 7 + day) * 2654435761;
const v = ((n ^ (n >>> 15)) >>> 0) % 100;
if (v < 55) return 0;
if (v < 76) return 1;
if (v < 90) return 2;
if (v < 97) return 3;
return 4;
}
export default function DevSnake() {
// Boustrophedon path: sweep each row, alternating direction.
const path = useMemo(() => {
const cells: Array<[number, number]> = [];
for (let d = 0; d < DAYS; d++) {
const cols = Array.from({ length: WEEKS }, (_, w) => w);
if (d % 2 === 1) cols.reverse();
for (const w of cols) cells.push([w, d]);
}
return cells;
}, []);
const [head, setHead] = useState(0);
useEffect(() => {
const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (reduce) return;
const id = setInterval(() => setHead((h) => (h + 1) % path.length), 110);
return () => clearInterval(id);
}, [path.length]);
// Map "week-day" → trail intensity (0..TRAIL), 0 = not on snake.
const trail = useMemo(() => {
const map = new Map<string, number>();
for (let i = 0; i < TRAIL; i++) {
const idx = (head - i + path.length) % path.length;
const [w, d] = path[idx];
map.set(`${w}-${d}`, TRAIL - i);
}
return map;
}, [head, path]);
// The cell just ahead of the head — about to be picked up.
const [nextW, nextD] = path[(head + 1) % path.length];
const nextKey = `${nextW}-${nextD}`;
// Fuchsia snake, brightest at the head, so it reads over the muted grid.
const snakeClass = [
"bg-fuchsia-500/30",
"bg-fuchsia-500/45",
"bg-fuchsia-500/60",
"bg-fuchsia-500/80",
"bg-fuchsia-400",
"bg-fuchsia-300",
];
return (
<section className="bg-background">
<div className="mx-auto w-full max-w-4xl px-6 py-20 sm:py-24">
<div className="mb-8">
<h2 className="text-2xl font-semibold tracking-tight text-balance sm:text-3xl">
Always something moving
</h2>
<p className="mt-2 text-muted-foreground">
A little life for an empty state or a footer — decorative only.
</p>
</div>
<div className="overflow-x-auto rounded-xl border border-border/60 bg-card p-5">
<div
className="grid min-w-[640px] gap-[3px]"
style={{
gridTemplateColumns: `repeat(${WEEKS}, minmax(0, 1fr))`,
gridTemplateRows: `repeat(${DAYS}, minmax(0, 1fr))`,
gridAutoFlow: "column",
}}
>
{path.length > 0 &&
Array.from({ length: WEEKS }).flatMap((_, w) =>
Array.from({ length: DAYS }).map((_, d) => {
const key = `${w}-${d}`;
const t = trail.get(key);
const isHead = t === TRAIL;
const isPickup = key === nextKey;
return (
<span
key={key}
style={
isHead
? { boxShadow: "0 0 7px 1px rgba(232,121,249,0.9)" }
: undefined
}
className={cn(
"aspect-square rounded-[2px] transition-colors duration-150",
t
? snakeClass[t]
: isPickup
? "bg-fuchsia-500/25 ring-1 ring-fuchsia-400/60"
: levelClass[baseLevel(w, d)],
)}
/>
);
}),
)}
</div>
</div>
</div>
</section>
);
}






























