{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "sunburst",
  "type": "registry:component",
  "title": "Sunburst",
  "description": "Parts and their sub-parts, in rings. Sample data: $48.2K spend this month by team, research $20.2K, agents $3.0K.",
  "registryDependencies": [
    "@chartory/core",
    "@chartory/plot-sunburst"
  ],
  "files": [
    {
      "path": "registry/chartory/components/sunburst.tsx",
      "type": "registry:component",
      "target": "components/chartory/sunburst.tsx",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// Sunburst (Chartory chart 022): sizes xs | s | m | l, laid out again from the data at each\n// size; collection \"hearth\" (default) or \"signal\" (with @chartory/signal, Code and Complete). Data in the type's shape (default: the sample). Docs:\n// https://usechartory.com/docs/charts/sunburst\nimport { ChartView, type ChartViewProps } from \"@/lib/chartory/charts/chart-view\"\nimport { registerChart } from \"@/lib/chartory/charts/defs\"\nimport { data as sample } from \"@/lib/chartory/charts/types/022-sunburst/data\"\nimport { def } from \"@/lib/chartory/charts/types/022-sunburst/layout\"\n\nregisterChart(def, sample)\n\nexport type SunburstData = typeof sample\nexport type SunburstProps = Omit<ChartViewProps, \"def\" | \"data\" | \"states\"> & {\n  /** the data to draw (default: the sample) */\n  data?: SunburstData\n  /** further data states: the chart morphs to them (update) or ticks through them (live, with interval) */\n  states?: SunburstData[]\n}\n\nexport function Sunburst(props: SunburstProps) {\n  return <ChartView def={def} {...props} />\n}\n"
    },
    {
      "path": "registry/chartory/charts/types/022-sunburst/data.ts",
      "type": "registry:lib",
      "target": "lib/chartory/charts/types/022-sunburst/data.ts",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// 022 Sunburst · sample data (Figma chart/022, AI: token spend by team › model, October month to date, in $100s).\nimport type { SunburstData } from \"../../plots/sunburst\";\n\nexport const data: SunburstData = {\n  center: { value: \"$48.2K\", caps: \"THIS MONTH\" },\n  groups: [\n    {  label: \"Research\", tok: \"data/cat-1\", items: [[\"Atlas 3\", 138], [\"Orion XL\", 64]]  },\n    {  label: \"Support\", tok: \"data/cat-2\", items: [[\"Kite 2 Pro\", 96], [\"Pico 2\", 41], [\"Nova Mini\", 22]]  },\n    {  label: \"Search\", tok: \"data/cat-3\", items: [[\"Vega 1.5\", 58], [\"Lumen 4\", 33]]  },\n    {  label: \"Agents\", tok: \"data/cat-5\", items: [[\"Atlas 3\", 21], [\"Sable 7B\", 9]]  },\n  ],\n};\n"
    },
    {
      "path": "registry/chartory/charts/types/022-sunburst/layout.ts",
      "type": "registry:lib",
      "target": "lib/chartory/charts/types/022-sunburst/layout.ts",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// 022 Sunburst (Figma chart/022, \"Token spend by team\"): C.sunburst, teams inside, models outside, team list beside.\nimport type { ChartDef, TooltipSpec } from \"../../core/shell\";\nimport { sunburst } from \"../../plots/sunburst\";\nimport { data } from \"./data\";\nimport { frame, type Frame, type Text } from \"../../core/node\";\n\n/** Deterministic wave in [-1, 1] per index and update step (no randomness: the same step gives the same period). */\nconst wave = (i: number, step: number, f = 1.7) => Math.sin(step * 2.3 + i * f + 0.5);\n/** A text is named by its characters, so an update state takes the sample's text names (same order): its value\n *  labels then stay the same marks and morph in place instead of reading as new ones. */\nfunction keepNames(pl: Frame, ref: Frame): Frame {\n  const texts = (f: Frame): Text[] => f.children.flatMap((c) => (c.removed ? [] : c.kind === \"text\" ? [c] : c.kind === \"frame\" ? texts(c) : []));\n  const a = texts(pl), b = texts(ref);\n  if (a.length === b.length) a.forEach((t, i) => { if (t.name === t.text.slice(0, 40)) t.name = b[i].name; });\n  return pl;\n}\n\nconst k = (v: number) => \"$\" + (v / 10).toFixed(1) + \"K\";\nconst team = (g: (typeof data.groups)[number]) => g.items.reduce((s, i) => s + i[1], 0);\n\n/** Hover tooltip: one team (inner ring and its models), a row per model and the team total. */\nconst tip = (d: unknown, g: number): TooltipSpec => {\n  const t = (d as typeof data).groups[g];\n  return {\n    kind: \"series\",\n    caps: t.label.toUpperCase() + \" · TOKEN SPEND\",\n    rows: t.items.map(([n, v]) => ({ label: n, value: k(v), swatch: t.tok })),\n    total: { label: \"Total\", value: k(team(t)) },\n  };\n};\n\nexport const def: ChartDef = {\n  no: 22,\n  slug: \"sunburst\",\n  legend: null,\n  plot: (K, p, w, d) => {\n    const o = (d as typeof data | undefined) ?? data;\n    const pl = sunburst(K, p, w, o);\n    return o === data ? pl : keepNames(pl, sunburst(K, frame(null, \"sample\"), w, data));\n  },\n  tip,\n  update: (d, step) => {\n    const o = d as typeof data;\n    // later in the month: each model's spend moves ±12 % ($100s); the centre total follows (team totals: the plot)\n    const groups = o.groups.map((g, gi) => ({ ...g, items: g.items.map(([n, v], k) => [n, Math.max(1, Math.round(v * (1 + 0.12 * wave(gi * 3 + k, step))))] as [string, number]) }));\n    const tot = groups.reduce((a, g) => a + g.items.reduce((s, i) => s + i[1], 0), 0);\n    return { ...o, groups, center: { ...o.center, value: \"$\" + (tot / 10).toFixed(1) + \"K\" } };\n  },\n  describe: {\n    title: \"Token spend by team and model\",\n    summary: `Token spend of $48.2K this month by team: ${data.groups.map((g) => g.label + \" \" + k(team(g))).join(\", \")}; the largest single model is Research's Atlas 3 at ${k(138)}.`,\n    table: { head: [\"Team\", \"Model\", \"Spend\"], rows: data.groups.flatMap((g) => g.items.map((i) => [g.label, i[0], k(i[1])])) },\n  },\n};\n"
    }
  ],
  "categories": [
    "charts",
    "part-of-a-whole"
  ],
  "meta": {
    "access": "free",
    "no": 22,
    "family": "Part of a whole"
  }
}
