{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "seed-emblem",
  "type": "registry:component",
  "title": "SeedEmblem",
  "description": "A unique animated SVG 'system' generated deterministically from any string. Same seed, same emblem. Server-renderable, no canvas.",
  "dependencies": [],
  "registryDependencies": [],
  "tier": "free",
  "note": "Requires the @keyframes ge-spin / ge-pulse and .ge-spin / .ge-pulse rules from globals.css — copy them in, or the emblem renders static.",
  "files": [
    {
      "path": "components/prism/SeedEmblem.tsx",
      "content": "import { rngFrom, hashStr } from \"@/lib/seed\";\n\n/**\n * SeedEmblem — a deterministic, animated SVG \"system\" (orbiting rings, nodes,\n * a glowing core) generated entirely from a seed string. Same string ⇒ same\n * emblem, every time. Pure/server-renderable. Ported from Sky's GenEmblem.\n *\n * Use it for unique-but-consistent avatars, project marks, or entity glyphs.\n */\nexport function SeedEmblem({\n  seed,\n  hue = \"#8b5cff\",\n  label,\n  size = 56,\n}: {\n  seed: string;\n  hue?: string;\n  label?: string;\n  size?: number;\n}) {\n  const rng = rngFrom(seed);\n  const id = hashStr(seed).toString(36);\n  // Round derived values so server- and client-rendered SVG attributes serialize\n  // identically (trig last-ULP differences would otherwise trip hydration).\n  const r3 = (n: number) => Math.round(n * 1000) / 1000;\n\n  const rings = Array.from({ length: 3 }, (_, i) => {\n    const rx = r3(30 + i * 8 + rng() * 6);\n    const ry = r3(rx * (0.48 + rng() * 0.36));\n    const rot = Math.floor(rng() * 360);\n    const dur = r3(20 + i * 9 + rng() * 12);\n    return { rx, ry, rot, dur, rev: i % 2 === 1, op: 0.42 - i * 0.1 };\n  });\n\n  const nodeCount = 4 + Math.floor(rng() * 4);\n  const nodes = Array.from({ length: nodeCount }, () => {\n    const a = rng() * Math.PI * 2;\n    const r = 22 + rng() * 24;\n    return {\n      x: r3(60 + Math.cos(a) * r),\n      y: r3(60 + Math.sin(a) * r * 0.72),\n      rr: r3(1.3 + rng() * 1.8),\n    };\n  });\n\n  const coreR = r3(7 + rng() * 5);\n\n  return (\n    <svg viewBox=\"0 0 120 120\" width={size} height={size} role=\"img\" aria-hidden>\n      <defs>\n        <radialGradient id={`glow-${id}`}>\n          <stop offset=\"0%\" stopColor={hue} stopOpacity=\"0.95\" />\n          <stop offset=\"45%\" stopColor={hue} stopOpacity=\"0.45\" />\n          <stop offset=\"100%\" stopColor={hue} stopOpacity=\"0\" />\n        </radialGradient>\n      </defs>\n      {nodes.map((n, i) => (\n        <line key={`l${i}`} x1=\"60\" y1=\"60\" x2={n.x} y2={n.y} stroke={hue} strokeOpacity=\"0.12\" strokeWidth=\"0.6\" />\n      ))}\n      {rings.map((r, i) => (\n        <ellipse\n          key={`r${i}`}\n          className=\"ge-spin\"\n          style={{\n            animationDuration: `${r.dur}s`,\n            animationDirection: r.rev ? \"reverse\" : \"normal\",\n            animationDelay: `${-(r.rot / 360) * r.dur}s`,\n          }}\n          cx=\"60\"\n          cy=\"60\"\n          rx={r.rx}\n          ry={r.ry}\n          fill=\"none\"\n          stroke={hue}\n          strokeOpacity={r.op}\n          strokeWidth=\"0.8\"\n        />\n      ))}\n      {nodes.map((n, i) => (\n        <circle key={`n${i}`} cx={n.x} cy={n.y} r={n.rr} fill={hue} fillOpacity=\"0.85\" />\n      ))}\n      <circle className=\"ge-pulse\" cx=\"60\" cy=\"60\" r={coreR * 1.9} fill={`url(#glow-${id})`} />\n      <circle cx=\"60\" cy=\"60\" r={coreR} fill={hue} fillOpacity=\"0.92\" />\n      {label ? (\n        <text x=\"60\" y=\"67\" textAnchor=\"middle\" fontSize=\"20\" fontWeight=\"600\" fill=\"#08080c\">\n          {label}\n        </text>\n      ) : (\n        <circle cx=\"60\" cy=\"60\" r={coreR * 0.42} fill=\"#ffffff\" fillOpacity=\"0.85\" />\n      )}\n    </svg>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/prism/SeedEmblem.tsx"
    },
    {
      "path": "lib/seed.ts",
      "content": "// Tiny deterministic PRNG so generative visuals are stable per seed string.\n// Ported from Sky — the seed→visual pipeline is one of the most reusable tools.\n\nexport function hashStr(s: string): number {\n  let h = 1779033703 ^ s.length;\n  for (let i = 0; i < s.length; i++) {\n    h = Math.imul(h ^ s.charCodeAt(i), 3432918353);\n    h = (h << 13) | (h >>> 19);\n  }\n  h ^= h >>> 16;\n  return h >>> 0;\n}\n\nexport function mulberry32(seed: number): () => number {\n  let a = seed >>> 0;\n  return function () {\n    a |= 0;\n    a = (a + 0x6d2b79f5) | 0;\n    let t = Math.imul(a ^ (a >>> 15), 1 | a);\n    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n  };\n}\n\nexport function rngFrom(s: string): () => number {\n  return mulberry32(hashStr(s));\n}\n",
      "type": "registry:lib",
      "target": "lib/seed.ts"
    }
  ]
}