/**
 * Immutable semantic recipes for Orby.
 *
 * A sprite is intentionally data, not a baked animation. Renderers combine its
 * glyph silhouette, field stack, switching operator, transition contract, and
 * interaction mappings. This keeps the catalogue portable across Canvas 2D,
 * WebGL, SVG exporters, sprite-sheet bakers, and reduced-motion renderers.
 */

const deepFreeze = (value, seen = new WeakSet()) => {
  if (
    value === null ||
    (typeof value !== "object" && typeof value !== "function") ||
    seen.has(value)
  ) {
    return value;
  }
  seen.add(value);
  for (const child of Object.values(value)) deepFreeze(child, seen);
  return Object.freeze(value);
};

export const FIELD_IDS = Object.freeze([
  "fbm",
  "ridged",
  "domain-warp",
  "curl",
  "flow",
  "worley",
  "voronoi",
  "plasma",
  "interference",
  "vortex",
  "metaballs",
  "caustics",
  "strata",
  "radar",
  "constellation",
  "liquid",
  "electric",
  "ripple",
  "kaleidoscope",
]);

const FIELD_ID_SET = new Set(FIELD_IDS);

const PALETTE_SOURCE = {
  neutral: {
    name: "neutral",
    background: "#07090c",
    shadow: "#1b222b",
    ink: "#eef3f8",
    accent: "#93cfff",
  },
  info: {
    name: "info",
    background: "#071019",
    shadow: "#15344a",
    ink: "#edf8ff",
    accent: "#4fc3ff",
  },
  success: {
    name: "success",
    background: "#07110e",
    shadow: "#16392d",
    ink: "#f0fff9",
    accent: "#54d99b",
  },
  warning: {
    name: "warning",
    background: "#151006",
    shadow: "#493514",
    ink: "#fff9e9",
    accent: "#f5b94c",
  },
  danger: {
    name: "danger",
    background: "#15090b",
    shadow: "#4c1c25",
    ink: "#fff2f4",
    accent: "#ff647c",
  },
  celebration: {
    name: "celebration",
    background: "#100a19",
    shadow: "#352052",
    ink: "#fff7ff",
    accent: "#cf86ff",
  },
};

export const PALETTES = deepFreeze(PALETTE_SOURCE);

function layer(field, weight, scale, blend = "add", options = {}) {
  if (!FIELD_ID_SET.has(field)) {
    throw new TypeError(`Unknown field "${field}" in built-in sprite recipe.`);
  }
  return {
    field,
    weight,
    scale,
    blend,
    ...(Number.isFinite(options.segments)
      ? { segments: Math.round(options.segments) }
      : {}),
    phase: options.phase ?? 0,
    speed: options.speed ?? 1,
    contrast: options.contrast ?? 1,
    warp: options.warp ?? 0,
  };
}

const defaultPointer = {
  enabled: true,
  minSize: 20,
  effect: "steer-light",
  strength: 0.16,
  reducedMotion: false,
};

const defaultPress = {
  enabled: true,
  effect: "spring-compress",
  strength: 0.07,
  durationMs: 180,
};

function defineSprite({
  id,
  category,
  meaning,
  glyph,
  field,
  fieldMix,
  composition = {},
  palette = "neutral",
  threshold = 0.5,
  density = 0.72,
  speed = 1,
  pixelShape = "rounded-square",
  pixelGap = 0.12,
  pixelScale = 0.94,
  silhouetteFloor = 0.38,
  pixelSwitch = {},
  timeline = {},
  transition = {},
  interactions = {},
  reducedMotion = {},
  labels,
  terminal = false,
  urgency = "normal",
}) {
  if (!FIELD_ID_SET.has(field)) {
    throw new TypeError(`Unknown primary field "${field}" for "${id}".`);
  }
  if (!labels?.default) {
    throw new TypeError(`Sprite "${id}" must define labels.default.`);
  }

  const mix = fieldMix?.length
    ? fieldMix
    : [layer(field, 1, 1, "replace")];
  const totalWeight = mix.reduce((sum, item) => sum + item.weight, 0);
  const compositionConfig =
    typeof composition === "string"
      ? { mode: composition }
      : composition && typeof composition === "object"
        ? composition
        : {};

  const recipe = {
    schemaVersion: 1,
    id,
    semantic: {
      category,
      meaning,
      terminal,
      urgency,
      announce: labels.live ?? (urgency === "high" ? "assertive" : "polite"),
      decorativeCanvas: true,
      monochromeSafe: true,
      minimumReadableSize: 16,
    },
    glyph,
    field,
    composition: {
      mode: "glyph",
      ...compositionConfig,
    },
    fieldMix: mix.map((item) => ({
      ...item,
      weight: totalWeight > 0 ? item.weight / totalWeight : 0,
    })),
    palette: PALETTES[palette] ?? PALETTES.neutral,
    threshold,
    density,
    speed,
    pixel: {
      shape: pixelShape,
      gap: pixelGap,
      scale: pixelScale,
      quantize: "1bit",
      silhouetteFloor,
    },
    pixelSwitch: {
      mode: pixelSwitch.mode ?? "threshold-hysteresis",
      dither: pixelSwitch.dither ?? "bayer8",
      hysteresis: pixelSwitch.hysteresis ?? 0.055,
      temporalRate: pixelSwitch.temporalRate ?? speed,
      neighborhood: pixelSwitch.neighborhood ?? 0,
      direction: pixelSwitch.direction ?? "field",
      monotonic: pixelSwitch.monotonic ?? false,
      maxContrastFlashesPerSecond:
        pixelSwitch.maxContrastFlashesPerSecond ?? 3,
    },
    timeline: {
      mode: timeline.mode ?? "loop",
      durationMs: timeline.durationMs ?? Math.round(1000 / Math.max(speed, 0.01)),
      macroCycleMs: timeline.macroCycleMs ?? null,
      holdMs: timeline.holdMs ?? 0,
      replay: timeline.replay ?? "continuous",
      next: timeline.next ?? null,
    },
    transition: {
      enter: transition.enter ?? "field-morph",
      exit: transition.exit ?? "field-morph",
      durationMs: transition.durationMs ?? 360,
      exitDurationMs:
        transition.exitDurationMs ?? transition.durationMs ?? 360,
      preservePhase: transition.preservePhase ?? true,
      preserveBuffer: transition.preserveBuffer ?? false,
      interruptible: transition.interruptible ?? true,
    },
    interactions: {
      pointer: {
        ...defaultPointer,
        ...(interactions.pointer ?? {}),
      },
      press: {
        ...defaultPress,
        ...(interactions.press ?? {}),
      },
      signals: interactions.signals ?? [],
    },
    reducedMotion: {
      mode: reducedMotion.mode ?? "representative-phase",
      phase: reducedMotion.phase ?? 0.25,
      speed: 0,
      transition: reducedMotion.transition ?? "crossfade",
      transitionMs: reducedMotion.transitionMs ?? 120,
      pointer: false,
      spatialMotion: false,
      representation:
        reducedMotion.representation ?? `static ${labels.default.toLowerCase()} glyph`,
      dataUpdates: reducedMotion.dataUpdates ?? "discrete",
    },
    labels: {
      default: labels.default,
      aria: labels.aria ?? labels.default,
      live: labels.live ?? (urgency === "high" ? "assertive" : "polite"),
      value: labels.value ?? null,
      variants: labels.variants ?? null,
    },
  };

  return deepFreeze(recipe);
}

const RECIPES = [
  defineSprite({
    id: "ai.idle",
    category: "presence",
    meaning: "ready and available",
    glyph: "idle",
    field: "fbm",
    composition: {
      gestaltBoundary: true,
      gestaltOpenness: 0.58,
    },
    fieldMix: [
      layer("fbm", 0.72, 1.15, "replace", { speed: 0.2, contrast: 0.9 }),
      layer("caustics", 0.28, 1.7, "soft-light", {
        speed: -0.09,
        phase: 0.19,
      }),
    ],
    palette: "neutral",
    threshold: 0.51,
    density: 0.68,
    speed: 0.14,
    pixelShape: "rounded-square",
    pixelSwitch: {
      mode: "ordered-dither",
      dither: "bayer8",
      hysteresis: 0.045,
      temporalRate: 0.1,
      direction: "field",
    },
    timeline: {
      durationMs: 7200,
      macroCycleMs: 14400,
      replay: "continuous",
    },
    transition: {
      enter: "field-morph",
      exit: "field-morph",
      durationMs: 520,
      preservePhase: true,
    },
    interactions: {
      pointer: { effect: "steer-highlight", strength: 0.14 },
      press: { effect: "spring-compress", strength: 0.055 },
    },
    reducedMotion: {
      phase: 0.18,
      representation: "static side-lit lunar sphere with a persistent rim",
    },
    labels: { default: "Ready", live: "polite" },
  }),

  defineSprite({
    id: "ai.ambient-idle",
    category: "ambient",
    meaning: "calm field-only presence",
    glyph: "idle",
    field: "fbm",
    composition: {
      mode: "field-orb",
      gestaltBoundary: true,
      gestaltOpenness: 0.46,
      lighting: "crescent",
      radius: 0.88,
      fieldContrast: 1.26,
      fieldDetail: 0.86,
      lightOrbit: 0.1,
      breathe: 0.045,
      rim: 0.055,
    },
    fieldMix: [
      layer("fbm", 0.62, 1.14, "replace", {
        speed: 0.18,
        contrast: 1.24,
      }),
      layer("caustics", 0.38, 2.05, "soft-light", {
        speed: -0.11,
        contrast: 1.08,
        phase: 0.31,
      }),
    ],
    palette: "neutral",
    threshold: 0.49,
    density: 0.76,
    speed: 0.22,
    pixelShape: "rounded-square",
    pixelScale: 0.9,
    pixelSwitch: {
      mode: "ordered-dither",
      dither: "bayer8",
      hysteresis: 0.045,
      temporalRate: 0.18,
      direction: "surface-drift",
    },
    timeline: {
      durationMs: 7200,
      macroCycleMs: 14400,
      replay: "continuous",
    },
    transition: {
      enter: "field-morph",
      exit: "field-morph",
      durationMs: 520,
      preservePhase: true,
    },
    interactions: {
      pointer: { effect: "steer-light", strength: 0.18 },
      press: { effect: "surface-ripple", strength: 0.09 },
    },
    reducedMotion: {
      phase: 0.18,
      representation: "static side-lit dithered field orb",
    },
    labels: { default: "Ambient ready", live: "polite" },
  }),

  defineSprite({
    id: "ai.ambient-thinking",
    category: "ambient",
    meaning: "reasoning expressed only through an animated field",
    glyph: "thinking",
    field: "domain-warp",
    composition: {
      mode: "field-orb",
      gestaltBoundary: true,
      gestaltOpenness: 0.62,
      lighting: "sphere",
      radius: 0.84,
      fieldContrast: 1.48,
      fieldDetail: 0.96,
      lightOrbit: 0.2,
      breathe: 0.09,
      rim: 0.045,
    },
    fieldMix: [
      layer("domain-warp", 0.46, 1.08, "replace", {
        speed: 0.52,
        contrast: 1.34,
        warp: 0.7,
      }),
      layer("curl", 0.32, 1.52, "add", {
        speed: -0.38,
        contrast: 1.22,
      }),
      layer("ridged", 0.22, 2.18, "soft-light", {
        speed: 0.24,
        contrast: 1.36,
      }),
    ],
    palette: "info",
    threshold: 0.5,
    density: 0.8,
    speed: 0.72,
    pixelShape: "rounded-square",
    pixelScale: 0.89,
    pixelSwitch: {
      mode: "temporal-blue-noise",
      dither: "blue-noise64",
      hysteresis: 0.048,
      temporalRate: 0.68,
      direction: "counter-flow",
    },
    timeline: {
      durationMs: 4600,
      macroCycleMs: 9200,
      replay: "continuous",
    },
    transition: {
      enter: "radial-cascade",
      exit: "field-morph",
      durationMs: 460,
      preservePhase: true,
    },
    interactions: {
      pointer: { effect: "bend-flow-and-light", strength: 0.16 },
      press: { effect: "damped-vortex", strength: 0.18, durationMs: 460 },
      signals: [
        { name: "reasoning.depth", mapsTo: "shellEnergy", range: [0, 1] },
      ],
    },
    reducedMotion: {
      phase: 0.34,
      representation: "static front-lit dithered reasoning field",
    },
    labels: { default: "Ambient thinking", live: "polite" },
  }),

  defineSprite({
    id: "ai.ambient-thinking-symmetric",
    category: "ambient",
    meaning: "reasoning expressed through a clean, symmetrical animated field",
    glyph: "thinking",
    field: "kaleidoscope",
    composition: {
      mode: "field-orb",
      lighting: "flat",
      radius: 0.87,
      fieldContrast: 1.32,
      fieldDetail: 0.84,
      lightOrbit: 0,
      breathe: 0.045,
      rim: 0.04,
    },
    fieldMix: [
      layer("kaleidoscope", 0.74, 0.82, "replace", {
        segments: 8,
        speed: 0.2,
        contrast: 1.25,
      }),
      layer("kaleidoscope", 0.26, 1.42, "soft-light", {
        segments: 8,
        speed: -0.12,
        contrast: 1.08,
      }),
    ],
    palette: "info",
    threshold: 0.5,
    density: 0.78,
    speed: 0.5,
    pixelShape: "square",
    pixelGap: 0.14,
    pixelScale: 0.9,
    pixelSwitch: {
      mode: "threshold-hysteresis",
      dither: "bayer8",
      hysteresis: 0.058,
      temporalRate: 0.34,
      direction: "radial",
    },
    timeline: {
      durationMs: 6400,
      macroCycleMs: 12800,
      replay: "continuous",
    },
    transition: {
      enter: "radial-cascade",
      exit: "field-morph",
      durationMs: 500,
      preservePhase: true,
    },
    interactions: {
      pointer: { enabled: false },
      press: { enabled: false },
      signals: [
        { name: "reasoning.depth", mapsTo: "shellEnergy", range: [0, 1] },
      ],
    },
    reducedMotion: {
      phase: 0.25,
      representation: "static symmetrical reasoning field",
    },
    labels: { default: "Ambient thinking — symmetric", live: "polite" },
  }),

  defineSprite({
    id: "ai.ambient-speaking",
    category: "ambient",
    meaning: "voice output expressed only through an animated field",
    glyph: "speaking",
    field: "interference",
    composition: {
      mode: "field-orb",
      gestaltBoundary: true,
      gestaltOpenness: 0.5,
      lighting: "gibbous",
      radius: 0.87,
      fieldContrast: 1.38,
      fieldDetail: 0.92,
      lightOrbit: 0.13,
      breathe: 0.065,
      voice: 0.2,
      rim: 0.05,
    },
    fieldMix: [
      layer("interference", 0.46, 1.26, "replace", {
        speed: 1.05,
        contrast: 1.28,
      }),
      layer("plasma", 0.34, 1.7, "screen", {
        speed: -0.72,
        contrast: 1.18,
      }),
      layer("ripple", 0.2, 1.12, "add", {
        speed: 0.82,
        contrast: 1.24,
      }),
    ],
    palette: "info",
    threshold: 0.48,
    density: 0.82,
    speed: 1.02,
    pixelShape: "circle",
    pixelScale: 0.9,
    pixelSwitch: {
      mode: "ordered-dither",
      dither: "bayer8",
      hysteresis: 0.042,
      temporalRate: 0.96,
      direction: "audio-surface",
    },
    timeline: {
      mode: "signal-reactive",
      durationMs: 1900,
      macroCycleMs: 5700,
    },
    transition: {
      enter: "radial-cascade",
      exit: "field-morph",
      durationMs: 300,
      preservePhase: true,
    },
    interactions: {
      pointer: { effect: "steer-light", strength: 0.13 },
      press: { enabled: false },
      signals: [
        {
          name: "audio.level",
          mapsTo: "envelope",
          range: [0, 1],
          decayMs: 220,
        },
        { name: "audio.syllable", mapsTo: "bandEnergy", range: [0, 1] },
      ],
    },
    reducedMotion: {
      mode: "data-step",
      phase: 0.38,
      representation: "static gibbous field with discrete audio levels",
      dataUpdates: "three-level-step",
    },
    labels: { default: "Ambient speaking", live: "polite" },
  }),

  defineSprite({
    id: "ai.listening",
    category: "activity",
    meaning: "capturing voice or input",
    glyph: "listening",
    field: "interference",
    fieldMix: [
      layer("interference", 0.46, 1.4, "replace", {
        speed: 0.68,
        contrast: 1.18,
      }),
      layer("radar", 0.32, 1.05, "add", { speed: -0.46 }),
      layer("liquid", 0.22, 1.8, "soft-light", { speed: 0.3 }),
    ],
    palette: "info",
    threshold: 0.48,
    density: 0.77,
    speed: 0.78,
    pixelShape: "circle",
    pixelSwitch: {
      mode: "radial-cascade",
      dither: "bayer8",
      hysteresis: 0.05,
      direction: "inward",
    },
    timeline: { durationMs: 2400, macroCycleMs: 4800 },
    transition: {
      enter: "sdf-wavefront",
      exit: "radial-cascade",
      durationMs: 340,
      preservePhase: true,
    },
    interactions: {
      pointer: { effect: "ripple-bias", strength: 0.12 },
      press: { effect: "emit-inbound-ripple", strength: 0.18 },
      signals: [
        { name: "audio.level", mapsTo: "energy", range: [0, 1], decayMs: 90 },
        { name: "input.pulse", mapsTo: "ripple", range: [0, 1] },
      ],
    },
    reducedMotion: {
      phase: 0.36,
      representation: "static listening ring with discrete level steps",
      dataUpdates: "three-level-step",
    },
    labels: { default: "Listening", live: "polite" },
  }),

  defineSprite({
    id: "ai.thinking",
    category: "activity",
    meaning: "reasoning",
    glyph: "thinking",
    field: "flow",
    fieldMix: [
      layer("flow", 0.47, 1.35, "replace", {
        speed: 0.82,
        contrast: 1.08,
      }),
      layer("vortex", 0.35, 1.05, "add", { speed: -0.62, warp: 0.22 }),
      layer("fbm", 0.18, 2.1, "soft-light", { speed: 0.25 }),
    ],
    palette: "info",
    threshold: 0.5,
    density: 0.74,
    speed: 0.92,
    pixelShape: "rounded-square",
    pixelSwitch: {
      mode: "temporal-blue-noise",
      dither: "blue-noise64",
      hysteresis: 0.062,
      temporalRate: 0.82,
    },
    timeline: { durationMs: 3100, macroCycleMs: 6200 },
    transition: {
      enter: "field-morph",
      exit: "field-morph",
      durationMs: 430,
      preservePhase: true,
    },
    interactions: {
      pointer: { effect: "bend-flow", strength: 0.13 },
      press: { effect: "damped-vortex", strength: 0.2, durationMs: 460 },
    },
    reducedMotion: {
      phase: 0.3,
      representation: "static faceted spiral",
    },
    labels: { default: "Thinking", live: "polite" },
  }),

  defineSprite({
    id: "ai.thinking-deep",
    category: "activity",
    meaning: "deliberate extended reasoning",
    glyph: "thinking-deep",
    field: "domain-warp",
    fieldMix: [
      layer("domain-warp", 0.46, 0.95, "replace", {
        speed: 0.34,
        warp: 0.48,
      }),
      layer("ridged", 0.31, 1.8, "multiply", {
        speed: 0.18,
        contrast: 1.24,
      }),
      layer("vortex", 0.23, 0.72, "add", { speed: -0.27 }),
    ],
    palette: "info",
    threshold: 0.52,
    density: 0.79,
    speed: 0.38,
    pixelShape: "diamond",
    pixelGap: 0.1,
    pixelSwitch: {
      mode: "neighbor-propagation",
      dither: "bayer8",
      hysteresis: 0.07,
      temporalRate: 0.36,
      neighborhood: 8,
      direction: "shell-to-shell",
    },
    timeline: {
      durationMs: 9600,
      macroCycleMs: 19200,
      replay: "continuous",
    },
    transition: {
      enter: "field-morph",
      exit: "field-morph",
      durationMs: 680,
      preservePhase: true,
    },
    interactions: {
      pointer: { effect: "separate-shells", strength: 0.09 },
      press: { effect: "pinch-core", strength: 0.16, durationMs: 520 },
      signals: [
        {
          name: "reasoning.depth",
          mapsTo: "shellEnergy",
          range: [0, 1],
        },
      ],
    },
    reducedMotion: {
      phase: 0.42,
      representation: "static nested rings with a brighter inner core",
    },
    labels: { default: "Reasoning deeply", live: "polite" },
  }),

  defineSprite({
    id: "ai.still-working",
    category: "activity",
    meaning: "work is taking longer than expected",
    glyph: "still-working",
    field: "strata",
    fieldMix: [
      layer("strata", 0.44, 1.2, "replace", {
        speed: 0.21,
        contrast: 1.08,
      }),
      layer("radar", 0.34, 0.82, "add", { speed: 0.17 }),
      layer("flow", 0.22, 1.55, "soft-light", { speed: 0.18 }),
    ],
    palette: "neutral",
    threshold: 0.5,
    density: 0.71,
    speed: 0.24,
    pixelShape: "rounded-square",
    pixelSwitch: {
      mode: "radial-cascade",
      dither: "bayer8",
      hysteresis: 0.055,
      temporalRate: 0.62,
      direction: "outward-beacon",
    },
    timeline: {
      durationMs: 3200,
      macroCycleMs: 3200,
      replay: "continuous",
    },
    transition: {
      enter: "field-morph",
      exit: "field-morph",
      durationMs: 560,
      preservePhase: false,
    },
    interactions: {
      pointer: { effect: "expand-beacon", strength: 0.1 },
      press: { effect: "host-action", strength: 0.05 },
      signals: [
        { name: "latency.elapsed", mapsTo: "beaconEnergy", range: [0, 1] },
      ],
    },
    reducedMotion: {
      phase: 0.46,
      representation: "upright hourglass with settled sand and flip guides",
    },
    labels: { default: "Still working", live: "polite" },
  }),

  defineSprite({
    id: "ai.loading",
    category: "activity",
    meaning: "indeterminate startup or wait",
    glyph: "loading",
    field: "plasma",
    fieldMix: [
      layer("plasma", 0.58, 1.15, "replace", {
        speed: 1.15,
        contrast: 1.16,
      }),
      layer("flow", 0.42, 1.65, "add", { speed: 0.88 }),
    ],
    palette: "info",
    threshold: 0.52,
    density: 0.7,
    speed: 1.38,
    pixelShape: "square",
    pixelSwitch: {
      mode: "ordered-dither",
      dither: "bayer8",
      hysteresis: 0.052,
      temporalRate: 1.3,
      direction: "radial-tail",
    },
    timeline: { durationMs: 1440, macroCycleMs: 5760 },
    transition: {
      enter: "radial-cascade",
      exit: "field-morph",
      durationMs: 280,
      preservePhase: true,
    },
    interactions: {
      pointer: { effect: "steer-highlight", strength: 0.08 },
      press: { enabled: false },
    },
    reducedMotion: {
      phase: 0.63,
      representation: "static segmented loading ring",
    },
    labels: { default: "Loading", live: "polite" },
  }),

  defineSprite({
    id: "ai.progress",
    category: "activity",
    meaning: "determinate completion progress",
    glyph: "progress",
    field: "strata",
    fieldMix: [
      layer("strata", 0.54, 1.25, "replace", {
        speed: 0.25,
        contrast: 1.1,
      }),
      layer("constellation", 0.46, 1.9, "add", {
        speed: 0.1,
        phase: 0.37,
      }),
    ],
    palette: "info",
    threshold: 0.47,
    density: 0.84,
    speed: 0.32,
    pixelShape: "circle",
    pixelSwitch: {
      mode: "temporal-blue-noise",
      dither: "blue-noise64",
      hysteresis: 0.045,
      temporalRate: 0.28,
      direction: "contour-forward",
      monotonic: true,
    },
    timeline: { mode: "data-driven", durationMs: 240, replay: "on-update" },
    transition: {
      enter: "contour-trace",
      exit: "path-draw",
      durationMs: 320,
      preservePhase: true,
    },
    interactions: {
      pointer: { effect: "reveal-value", strength: 0 },
      press: { effect: "spring-compress", strength: 0.045 },
      signals: [
        {
          name: "progress",
          mapsTo: "progress",
          range: [0, 1],
          monotonic: true,
        },
      ],
    },
    reducedMotion: {
      mode: "data-step",
      phase: 0,
      representation: "static progress contour updated from data",
      dataUpdates: "discrete-monotonic",
    },
    labels: {
      default: "In progress",
      value: "{percent}% complete",
      live: "polite",
    },
  }),

  defineSprite({
    id: "ai.generating",
    category: "activity",
    meaning: "producing content",
    glyph: "generating",
    field: "electric",
    fieldMix: [
      layer("electric", 0.4, 1.75, "replace", {
        speed: 0.84,
        contrast: 1.23,
      }),
      layer("metaballs", 0.34, 1.1, "add", {
        speed: 0.54,
        warp: 0.18,
      }),
      layer("constellation", 0.26, 2.05, "screen", {
        speed: 0.38,
      }),
    ],
    palette: "info",
    threshold: 0.5,
    density: 0.78,
    speed: 0.88,
    pixelShape: "diamond",
    pixelSwitch: {
      mode: "curl-advect",
      dither: "blue-noise64",
      hysteresis: 0.058,
      temporalRate: 0.8,
      neighborhood: 4,
      direction: "core-to-target",
    },
    timeline: {
      mode: "signal-reactive",
      durationMs: 3600,
      macroCycleMs: 7200,
    },
    transition: {
      enter: "seeded-dissolve",
      exit: "field-morph",
      durationMs: 460,
      preservePhase: true,
    },
    interactions: {
      pointer: { effect: "attract-unlocked-pixels", strength: 0.11 },
      press: { effect: "core-pulse", strength: 0.08 },
      signals: [
        { name: "token", mapsTo: "spark", range: [0, 1], bounded: true },
        { name: "chunk", mapsTo: "spark", range: [0, 1], bounded: true },
        { name: "frame", mapsTo: "spark", range: [0, 1], bounded: true },
        { name: "stream.energy", mapsTo: "activity", range: [0, 1] },
      ],
    },
    reducedMotion: {
      mode: "data-step",
      phase: 0.72,
      representation: "target glyph filled in non-moving chunks",
      dataUpdates: "chunked-fill",
    },
    labels: { default: "Generating", live: "polite" },
  }),

  defineSprite({
    id: "ai.searching",
    category: "activity",
    meaning: "searching or retrieving information",
    glyph: "searching",
    field: "radar",
    fieldMix: [
      layer("radar", 0.53, 0.95, "replace", {
        speed: 0.72,
        contrast: 1.18,
      }),
      layer("worley", 0.29, 1.62, "add", { speed: 0.2 }),
      layer("caustics", 0.18, 2.1, "screen", { speed: 0.16 }),
    ],
    palette: "info",
    threshold: 0.49,
    density: 0.73,
    speed: 0.74,
    pixelShape: "circle",
    pixelSwitch: {
      mode: "sdf-wavefront",
      dither: "bayer8",
      hysteresis: 0.057,
      temporalRate: 0.72,
      direction: "radar-sweep",
    },
    timeline: { durationMs: 3300, macroCycleMs: 6600 },
    transition: {
      enter: "radial-cascade",
      exit: "field-morph",
      durationMs: 380,
      preservePhase: true,
    },
    interactions: {
      pointer: { effect: "bias-decorative-beam", strength: 0.1 },
      press: { enabled: false },
      signals: [
        {
          name: "search.hit",
          mapsTo: "worleyBloom",
          range: [0, 1],
          decayMs: 620,
        },
        { name: "search.results", mapsTo: "hitCount", range: [0, 8] },
      ],
    },
    reducedMotion: {
      phase: 0.2,
      representation: "static magnifier with discrete result dots",
      dataUpdates: "result-dot",
    },
    labels: { default: "Searching", live: "polite" },
  }),

  defineSprite({
    id: "ai.tool-use",
    category: "activity",
    meaning: "executing a tool or action",
    glyph: "tool-use",
    field: "strata",
    fieldMix: [
      layer("strata", 0.43, 1.3, "replace", {
        speed: 0.46,
        contrast: 1.12,
      }),
      layer("electric", 0.34, 1.8, "add", { speed: 0.68 }),
      layer("voronoi", 0.23, 1.05, "multiply", { speed: 0.22 }),
    ],
    palette: "neutral",
    threshold: 0.52,
    density: 0.8,
    speed: 0.68,
    pixelShape: "square",
    pixelSwitch: {
      mode: "neighbor-propagation",
      dither: "bayer8",
      hysteresis: 0.062,
      temporalRate: 0.62,
      neighborhood: 6,
      direction: "gear-step",
    },
    timeline: {
      mode: "signal-reactive",
      durationMs: 2400,
      macroCycleMs: 7200,
    },
    transition: {
      enter: "axis-flip",
      exit: "field-morph",
      durationMs: 420,
      preservePhase: true,
    },
    interactions: {
      pointer: { effect: "tilt-light", strength: 0.13 },
      press: { effect: "mechanism-compress", strength: 0.09 },
      signals: [
        { name: "tool.step", mapsTo: "toothPulse", range: [0, 1] },
        { name: "tool.wait", mapsTo: "stepHold", range: [0, 1] },
        { name: "tool.result", mapsTo: "coreState", range: [0, 1] },
      ],
    },
    reducedMotion: {
      phase: 0.125,
      representation: "static gear with data-driven step dots",
      dataUpdates: "step-dot",
    },
    labels: { default: "Using a tool", live: "polite" },
  }),

  defineSprite({
    id: "ai.speaking",
    category: "activity",
    meaning: "producing voice output",
    glyph: "speaking",
    field: "interference",
    fieldMix: [
      layer("interference", 0.44, 1.2, "replace", {
        speed: 1.05,
        contrast: 1.16,
      }),
      layer("plasma", 0.33, 1.62, "add", { speed: 0.74 }),
      layer("liquid", 0.23, 0.92, "soft-light", {
        speed: 0.55,
        warp: 0.2,
      }),
    ],
    palette: "info",
    threshold: 0.47,
    density: 0.81,
    speed: 1.08,
    pixelShape: "circle",
    pixelSwitch: {
      mode: "radial-cascade",
      dither: "bayer8",
      hysteresis: 0.05,
      temporalRate: 1.02,
      direction: "outward-audio",
    },
    timeline: {
      mode: "signal-reactive",
      durationMs: 1900,
      macroCycleMs: 5700,
    },
    transition: {
      enter: "sdf-wavefront",
      exit: "radial-cascade",
      durationMs: 260,
      preservePhase: true,
    },
    interactions: {
      pointer: { effect: "steer-light", strength: 0.11 },
      press: { enabled: false },
      signals: [
        {
          name: "audio.level",
          mapsTo: "envelope",
          range: [0, 1],
          decayMs: 240,
        },
        { name: "audio.syllable", mapsTo: "bandEnergy", range: [0, 1] },
      ],
    },
    reducedMotion: {
      mode: "data-step",
      phase: 0.38,
      representation: "static speaker with three discrete level states",
      dataUpdates: "three-level-step",
    },
    labels: { default: "Speaking", live: "polite" },
  }),

  defineSprite({
    id: "ai.awaiting-input",
    category: "activity",
    meaning: "user action is required",
    glyph: "awaiting-input",
    field: "fbm",
    fieldMix: [
      layer("fbm", 0.72, 0.92, "replace", {
        speed: 0.18,
        contrast: 0.94,
      }),
      layer("caustics", 0.28, 1.55, "soft-light", {
        speed: 0.1,
        contrast: 0.9,
      }),
    ],
    palette: "info",
    threshold: 0.48,
    density: 0.8,
    speed: 0.22,
    pixelShape: "rounded-square",
    pixelSwitch: {
      mode: "threshold-hysteresis",
      dither: "bayer8",
      hysteresis: 0.052,
      temporalRate: 0.08,
      direction: "focus",
    },
    timeline: {
      mode: "hold",
      durationMs: 1800,
      macroCycleMs: 10800,
      replay: "two-pulses-then-hold",
    },
    transition: {
      enter: "radial-cascade",
      exit: "field-morph",
      durationMs: 420,
      preservePhase: false,
    },
    interactions: {
      pointer: { effect: "turn-aperture", strength: 0.1 },
      press: {
        effect: "acknowledge",
        strength: 0.06,
        durationMs: 160,
        emits: "activate",
      },
      signals: [{ name: "activate", mapsTo: "acknowledgement", range: [0, 1] }],
    },
    reducedMotion: {
      phase: 0.44,
      representation: "static question mark inside a firefly focus ring",
    },
    labels: { default: "Your input is needed", live: "polite" },
  }),

  defineSprite({
    id: "status.success",
    category: "status",
    meaning: "completed successfully",
    glyph: "success",
    field: "caustics",
    fieldMix: [
      layer("caustics", 0.57, 1.3, "replace", {
        speed: 0.72,
        contrast: 1.15,
      }),
      layer("constellation", 0.43, 1.75, "screen", { speed: 0.35 }),
    ],
    palette: "success",
    threshold: 0.46,
    density: 0.9,
    speed: 0.82,
    pixelShape: "rounded-square",
    pixelSwitch: {
      mode: "path-draw",
      dither: "blue-noise64",
      hysteresis: 0.042,
      temporalRate: 1,
      direction: "tail-to-head",
      monotonic: false,
    },
    timeline: {
      mode: "one-shot",
      durationMs: 500,
      holdMs: 800,
      replay: "on-enter",
    },
    transition: {
      enter: "path-draw",
      exit: "field-morph",
      durationMs: 500,
      exitDurationMs: 300,
      preservePhase: false,
    },
    interactions: {
      pointer: { effect: "edge-sparkle", strength: 0.04 },
      press: { enabled: false },
    },
    reducedMotion: {
      mode: "static",
      phase: 1,
      representation: "static checkmark",
      transitionMs: 120,
    },
    labels: { default: "Completed", aria: "Completed successfully", live: "polite" },
    terminal: true,
  }),

  defineSprite({
    id: "status.warning",
    category: "status",
    meaning: "attention is needed for a nonfatal issue",
    glyph: "warning",
    field: "strata",
    fieldMix: [
      layer("strata", 0.58, 1.18, "replace", {
        speed: 0.38,
        contrast: 1.22,
      }),
      layer("interference", 0.42, 1.55, "add", { speed: 0.33 }),
    ],
    palette: "warning",
    threshold: 0.49,
    density: 0.86,
    speed: 0.42,
    pixelShape: "diamond",
    pixelSwitch: {
      mode: "contour-trace",
      dither: "bayer8",
      hysteresis: 0.065,
      temporalRate: 0.38,
      direction: "bottom-to-contour",
    },
    timeline: {
      mode: "one-shot-hold",
      durationMs: 1100,
      holdMs: 1600,
      replay: "two-pulses-then-hold",
    },
    transition: {
      enter: "sdf-wavefront",
      exit: "field-morph",
      durationMs: 430,
      preservePhase: false,
    },
    interactions: {
      pointer: { effect: "lean-highlight", strength: 0.08 },
      press: { effect: "contained-ripple", strength: 0.08 },
    },
    reducedMotion: {
      mode: "static",
      phase: 1,
      representation: "static outlined triangle and exclamation",
    },
    labels: { default: "Warning", live: "polite" },
    urgency: "medium",
  }),

  defineSprite({
    id: "status.error",
    category: "status",
    meaning: "operation failed",
    glyph: "error",
    field: "electric",
    fieldMix: [
      layer("electric", 0.61, 1.4, "replace", {
        speed: 0.82,
        contrast: 1.3,
      }),
      layer("ridged", 0.39, 1.85, "multiply", {
        speed: 0.35,
        contrast: 1.22,
      }),
    ],
    palette: "danger",
    threshold: 0.51,
    density: 0.88,
    speed: 0.78,
    pixelShape: "square",
    pixelSwitch: {
      mode: "axis-flip",
      dither: "bayer8",
      hysteresis: 0.055,
      temporalRate: 0.9,
      direction: "diagonal-fracture",
    },
    timeline: {
      mode: "one-shot-hold",
      durationMs: 410,
      holdMs: 1200,
      replay: "on-enter",
    },
    transition: {
      enter: "axis-flip",
      exit: "seeded-dissolve",
      durationMs: 410,
      preservePhase: false,
    },
    interactions: {
      pointer: { effect: "edge-repel", strength: 0.055 },
      press: { enabled: false },
    },
    reducedMotion: {
      mode: "static",
      phase: 1,
      representation: "static X",
      transitionMs: 100,
    },
    labels: { default: "Error", aria: "Operation failed", live: "assertive" },
    terminal: true,
    urgency: "high",
  }),

  defineSprite({
    id: "status.paused",
    category: "status",
    meaning: "work is suspended and can resume",
    glyph: "paused",
    field: "fbm",
    fieldMix: [
      layer("fbm", 0.55, 1.1, "replace", { speed: 0 }),
      layer("strata", 0.45, 1.4, "multiply", { speed: 0 }),
    ],
    palette: "neutral",
    threshold: 0.5,
    density: 0.9,
    speed: 0,
    pixelShape: "rounded-square",
    pixelSwitch: {
      mode: "axis-flip",
      dither: "bayer8",
      hysteresis: 0.08,
      temporalRate: 0,
      direction: "columns",
    },
    timeline: {
      mode: "hold",
      durationMs: 1,
      replay: "resume-reversible",
    },
    transition: {
      enter: "axis-flip",
      exit: "axis-flip",
      durationMs: 280,
      preservePhase: true,
      preserveBuffer: true,
    },
    interactions: {
      pointer: { effect: "steer-light-only", strength: 0.06 },
      press: { effect: "bar-squeeze", strength: 0.045 },
      signals: [{ name: "resume", mapsTo: "reverseTransition", range: [0, 1] }],
    },
    reducedMotion: {
      mode: "static",
      phase: 1,
      representation: "static pause bars",
    },
    labels: { default: "Paused", live: "polite" },
  }),

  defineSprite({
    id: "status.cancelled",
    category: "status",
    meaning: "operation was stopped",
    glyph: "cancelled",
    field: "vortex",
    fieldMix: [
      layer("vortex", 0.57, 0.88, "replace", {
        speed: -0.68,
        contrast: 1.12,
      }),
      layer("metaballs", 0.43, 1.25, "add", { speed: -0.42 }),
    ],
    palette: "neutral",
    threshold: 0.52,
    density: 0.85,
    speed: 0.62,
    pixelShape: "square",
    pixelSwitch: {
      mode: "seeded-dissolve",
      dither: "blue-noise64",
      hysteresis: 0.065,
      temporalRate: 0.72,
      direction: "reverse-to-center",
    },
    timeline: {
      mode: "one-shot-hold",
      durationMs: 360,
      holdMs: 900,
      replay: "on-enter",
    },
    transition: {
      enter: "seeded-dissolve",
      exit: "seeded-dissolve",
      durationMs: 360,
      preservePhase: false,
    },
    interactions: {
      pointer: { enabled: false },
      press: { effect: "spring-compress", strength: 0.035 },
    },
    reducedMotion: {
      mode: "static",
      phase: 1,
      representation: "static stop square",
    },
    labels: { default: "Cancelled", live: "polite" },
    terminal: true,
  }),

  defineSprite({
    id: "status.offline",
    category: "status",
    meaning: "disconnected or unavailable",
    glyph: "offline",
    field: "radar",
    fieldMix: [
      layer("radar", 0.56, 0.72, "replace", {
        speed: 0.16,
        contrast: 1.16,
      }),
      layer("electric", 0.44, 1.55, "add", { speed: 0.11 }),
    ],
    palette: "neutral",
    threshold: 0.53,
    density: 0.72,
    speed: 0.18,
    pixelShape: "rounded-square",
    pixelSwitch: {
      mode: "path-draw",
      dither: "bayer8",
      hysteresis: 0.075,
      temporalRate: 0.16,
      direction: "bridge-and-retreat",
    },
    timeline: {
      mode: "signal-reactive",
      durationMs: 4200,
      macroCycleMs: 8400,
      replay: "continuous",
    },
    transition: {
      enter: "contour-trace",
      exit: "field-morph",
      durationMs: 480,
      preservePhase: true,
    },
    interactions: {
      pointer: { effect: "weak-echo", strength: 0.045 },
      press: { effect: "host-retry", strength: 0.04 },
      signals: [
        { name: "network.retry", mapsTo: "retryEnergy", range: [0, 1] },
        { name: "network.strength", mapsTo: "signalStrength", range: [0, 1] },
      ],
    },
    reducedMotion: {
      phase: 0.31,
      representation: "static broken ring with a diagonal disconnect mark",
      dataUpdates: "retry-dot",
    },
    labels: { default: "Offline", live: "polite" },
    urgency: "medium",
  }),

  defineSprite({
    id: "transfer.active",
    category: "workflow",
    meaning: "uploading, downloading, or synchronizing data",
    glyph: "transfer",
    field: "flow",
    fieldMix: [
      layer("flow", 0.46, 1.15, "replace", {
        speed: 0.88,
        contrast: 1.14,
      }),
      layer("liquid", 0.31, 1.55, "add", { speed: 0.65 }),
      layer("strata", 0.23, 1.9, "multiply", { speed: 0.44 }),
    ],
    palette: "info",
    threshold: 0.48,
    density: 0.79,
    speed: 0.9,
    pixelShape: "square",
    pixelSwitch: {
      mode: "axis-flip",
      dither: "blue-noise64",
      hysteresis: 0.052,
      temporalRate: 0.85,
      direction: "data-direction",
      monotonic: false,
    },
    timeline: {
      mode: "data-or-loop",
      durationMs: 2200,
      macroCycleMs: 6600,
    },
    transition: {
      enter: "axis-flip",
      exit: "field-morph",
      durationMs: 380,
      preservePhase: true,
    },
    interactions: {
      pointer: { effect: "lateral-wind", strength: 0.07, minSize: 28 },
      press: { effect: "spring-compress", strength: 0.045 },
      signals: [
        {
          name: "progress",
          mapsTo: "progress",
          range: [0, 1],
          monotonic: true,
        },
        {
          name: "direction",
          mapsTo: "direction",
          values: ["up", "down", "sync"],
        },
      ],
    },
    reducedMotion: {
      mode: "data-step",
      phase: 0.5,
      representation: "static directional arrow with data-driven fill",
      dataUpdates: "discrete-monotonic",
    },
    labels: {
      default: "Transferring",
      live: "polite",
      value: "{percent}% transferred",
      variants: {
        up: "Uploading",
        down: "Downloading",
        sync: "Syncing",
      },
    },
  }),

  defineSprite({
    id: "workflow.handoff",
    category: "workflow",
    meaning: "passing work to another agent or person",
    glyph: "handoff",
    field: "flow",
    fieldMix: [
      layer("flow", 0.44, 1.02, "replace", {
        speed: 0.66,
        contrast: 1.1,
      }),
      layer("constellation", 0.34, 1.6, "screen", { speed: 0.31 }),
      layer("metaballs", 0.22, 0.85, "add", { speed: 0.38 }),
    ],
    palette: "info",
    threshold: 0.49,
    density: 0.77,
    speed: 0.68,
    pixelShape: "circle",
    pixelSwitch: {
      mode: "path-draw",
      dither: "blue-noise64",
      hysteresis: 0.055,
      temporalRate: 0.62,
      direction: "source-to-destination",
    },
    timeline: {
      mode: "signal-reactive",
      durationMs: 3000,
      macroCycleMs: 6000,
      replay: "loop-until-accepted",
    },
    transition: {
      enter: "field-morph",
      exit: "path-draw",
      durationMs: 460,
      preservePhase: true,
    },
    interactions: {
      pointer: { effect: "bend-path-midpoint", strength: 0.09 },
      press: { enabled: false },
      signals: [
        {
          name: "handoff.accepted",
          mapsTo: "accepted",
          range: [0, 1],
          latches: true,
        },
      ],
    },
    reducedMotion: {
      phase: 0.58,
      representation: "two static nodes joined by a directional arrow",
      dataUpdates: "destination-highlight",
    },
    labels: { default: "Handing off", live: "polite" },
  }),

  defineSprite({
    id: "status.celebration",
    category: "status",
    meaning: "a milestone or high-value success",
    glyph: "celebration",
    field: "constellation",
    fieldMix: [
      layer("constellation", 0.45, 1.45, "replace", {
        speed: 0.92,
        contrast: 1.2,
      }),
      layer("caustics", 0.31, 1.9, "screen", { speed: 0.62 }),
      layer("electric", 0.24, 2.2, "add", { speed: 0.74 }),
    ],
    palette: "celebration",
    threshold: 0.45,
    density: 0.88,
    speed: 1,
    pixelShape: "diamond",
    pixelSwitch: {
      mode: "radial-cascade",
      dither: "blue-noise64",
      hysteresis: 0.045,
      temporalRate: 1.1,
      direction: "bounded-burst",
    },
    timeline: {
      mode: "one-shot",
      durationMs: 700,
      holdMs: 900,
      replay: "on-enter-once",
      next: "status.success",
    },
    transition: {
      enter: "radial-cascade",
      exit: "field-morph",
      durationMs: 700,
      preservePhase: false,
    },
    interactions: {
      pointer: { effect: "push-fragments", strength: 0.06, minSize: 32 },
      press: { enabled: false },
    },
    reducedMotion: {
      mode: "static",
      phase: 1,
      representation: "static star with a central success mark",
      transitionMs: 120,
    },
    labels: {
      default: "Milestone completed",
      aria: "Milestone completed successfully",
      live: "polite",
    },
    terminal: true,
  }),
];

export const SPRITES = deepFreeze(
  Object.fromEntries(RECIPES.map((recipe) => [recipe.id, recipe])),
);

export const SPRITE_IDS = Object.freeze(RECIPES.map((recipe) => recipe.id));
const SPRITE_LIST = Object.freeze([...RECIPES]);

export const SPRITE_ALIASES = Object.freeze({
  idle: "ai.idle",
  ready: "ai.idle",
  ambient: "ai.ambient-idle",
  "ambient-idle": "ai.ambient-idle",
  "field-idle": "ai.ambient-idle",
  "ambient-thinking": "ai.ambient-thinking",
  "field-thinking": "ai.ambient-thinking",
  "ambient-thinking-symmetric": "ai.ambient-thinking-symmetric",
  "field-thinking-symmetric": "ai.ambient-thinking-symmetric",
  "symmetric-thinking": "ai.ambient-thinking-symmetric",
  "ambient-speaking": "ai.ambient-speaking",
  "field-speaking": "ai.ambient-speaking",
  listening: "ai.listening",
  thinking: "ai.thinking",
  "thinking-deep": "ai.thinking-deep",
  "deep-thinking": "ai.thinking-deep",
  "still-working": "ai.still-working",
  working: "ai.still-working",
  loading: "ai.loading",
  progress: "ai.progress",
  generating: "ai.generating",
  searching: "ai.searching",
  "tool-use": "ai.tool-use",
  tool: "ai.tool-use",
  speaking: "ai.speaking",
  "awaiting-input": "ai.awaiting-input",
  prompt: "ai.awaiting-input",
  success: "status.success",
  warning: "status.warning",
  error: "status.error",
  paused: "status.paused",
  cancelled: "status.cancelled",
  offline: "status.offline",
  transfer: "transfer.active",
  upload: "transfer.active",
  download: "transfer.active",
  sync: "transfer.active",
  handoff: "workflow.handoff",
  celebration: "status.celebration",
});

export function resolveSpriteId(id) {
  const normalized = String(id ?? "").trim().toLowerCase();
  if (Object.prototype.hasOwnProperty.call(SPRITES, normalized)) {
    return normalized;
  }
  return SPRITE_ALIASES[normalized];
}

export function getSprite(id) {
  const resolved = resolveSpriteId(id);
  return resolved ? SPRITES[resolved] : undefined;
}

export function listSprites() {
  return SPRITE_LIST;
}

export function hasSprite(id) {
  return resolveSpriteId(id) !== undefined;
}

export default SPRITES;
