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