{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "flame-graph",
  "type": "registry:component",
  "title": "Flame graph",
  "description": "Where the time went in one run. Sample data: one agent run of 8.4 s, plan, research and answer, coloured by model, tool, retrieval and wait.",
  "registryDependencies": [
    "@chartory/core",
    "@chartory/plot-flame"
  ],
  "files": [
    {
      "path": "registry/chartory/components/flame-graph.tsx",
      "type": "registry:component",
      "target": "components/chartory/flame-graph.tsx",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// Flame graph (Chartory chart 074): 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/flame-graph\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/074-flame-graph/data\"\nimport { def } from \"@/lib/chartory/charts/types/074-flame-graph/layout\"\n\nregisterChart(def, sample)\n\nexport type FlameGraphData = typeof sample\nexport type FlameGraphProps = Omit<ChartViewProps, \"def\" | \"data\" | \"states\"> & {\n  /** the data to draw (default: the sample) */\n  data?: FlameGraphData\n  /** further data states: the chart morphs to them (update) or ticks through them (live, with interval) */\n  states?: FlameGraphData[]\n}\n\nexport function FlameGraph(props: FlameGraphProps) {\n  return <ChartView def={def} {...props} />\n}\n"
    },
    {
      "path": "registry/chartory/charts/types/074-flame-graph/data.ts",
      "type": "registry:lib",
      "target": "lib/chartory/charts/types/074-flame-graph/data.ts",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// 074 Flame graph · sample data (Figma chart/074-flame-agent-trace, AI: one agent run of 8.4 s by span and depth).\nimport type { FlameData } from \"../../plots/flame\";\n\nexport const data: FlameData = {\n  total: 8.4,\n  xt: [[0, \"0 s\"], [2, \"2 s\"], [4, \"4 s\"], [6, \"6 s\"], [8.4, \"8.4 s\"]],\n  spans: [\n    { label: \"agent.run\", d: 0, s: 0, e: 8.4, tok: \"data/primary\" },\n    { label: \"plan\", d: 1, s: 0, e: 1.1, tok: \"data/primary\" },\n    { label: \"research\", d: 1, s: 1.1, e: 5.6, tok: \"data/cat-2\" },\n    { label: \"answer\", d: 1, s: 5.6, e: 8.4, tok: \"data/primary\" },\n    { label: \"web.search\", d: 2, s: 1.2, e: 4.3, tok: \"data/cat-2\" },\n    { label: \"docs.query\", d: 2, s: 4.3, e: 5.5, tok: \"data/cat-3\" },\n    { label: \"draft\", d: 2, s: 5.7, e: 7.6, tok: \"data/primary\" },\n    { label: \"check\", d: 2, s: 7.6, e: 8.3, tok: \"data/primary\" },\n    { label: \"fetch ×6\", d: 3, s: 1.3, e: 3.4, tok: \"data/cat-2\" },\n    { label: \"queue\", d: 3, s: 3.4, e: 4.2, tok: \"data/cat-5\" },\n    { label: \"rerank\", d: 3, s: 4.6, e: 5.4, tok: \"data/cat-3\" },\n    { label: \"cite\", d: 3, s: 6.5, e: 7.5, tok: \"data/cat-3\" },\n    { label: \"parse\", d: 4, s: 1.4, e: 2.6, tok: \"data/cat-2\" },\n  ],\n};\n"
    },
    {
      "path": "registry/chartory/charts/types/074-flame-graph/layout.ts",
      "type": "registry:lib",
      "target": "lib/chartory/charts/types/074-flame-graph/layout.ts",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// 074 Flame graph (Figma chart/074-flame-agent-trace): C.flame on one agent run; the legend names the span kinds.\nimport { buildVariant, type ChartDef, type Size, type TooltipSpec } from \"../../core/shell\";\nimport { flame } from \"../../plots/flame\";\nimport { data } from \"./data\";\n\nconst legend: [string, string][] = [[\"data/primary\", \"Model\"], [\"data/cat-2\", \"Tool\"], [\"data/cat-3\", \"Retrieval\"], [\"data/cat-5\", \"Wait\"]];\nconst kind = (tok: string) => legend.find((l) => l[0] === tok)![1];\nconst sec = (v: number) => v.toFixed(1) + \" s\";\nconst search = data.spans.find((s) => s.label === \"web.search\")!;\n\n/** The marks a variant draws, texts named by their own characters counted by kind only (their content may change). */\nconst marks = (d: unknown, s: Size, lg: boolean) =>\n  buildVariant(def, s, lg, d).marks.map((m) => m.kind + \"|\" + (m.kind === \"text\" && m.name === m.text.slice(0, 40) ? \"\" : m.name)).join(\"\\n\");\n/** True when b draws the same marks as a at every size, legend on and off (labels shown by width stay). */\nconst sameMarks = (a: unknown, b: unknown) => ([\"xs\", \"s\", \"m\", \"l\"] as Size[]).every((s) => [true, false].every((lg) => marks(a, s, lg) === marks(b, s, lg)));\n\n// tooltip: one span (group = span index): start, end and duration, swatch = the span's kind colour\nconst tip = (o: typeof data, g: number): TooltipSpec | null => {\n  const s = o.spans[g];\n  if (!s) return null;\n  const k = legend.find((l) => l[0] === s.tok)?.[1];\n  return {\n    kind: \"range\",\n    caps: s.label.toUpperCase() + (k ? \" · \" + k.toUpperCase() : \"\") + \" · DEPTH \" + s.d,\n    rows: [{ label: \"Start\", value: sec(s.s), swatch: s.tok }, { label: \"End\", value: sec(s.e), swatch: s.tok }, { label: \"Duration\", value: sec(s.e - s.s), swatch: s.tok }],\n  };\n};\n\nexport const def: ChartDef = {\n  no: 74,\n  slug: \"flame-graph\",\n  legend,\n  plot: (K, p, w, d) => flame(K, p, w, (d as typeof data | undefined) ?? data),\n  tip: (d, g) => tip(d as typeof data, g),\n  // the next run of the same agent: span edges move by a smooth time warp over one stretch of the run (monotonic, the\n  // stretch's ends fixed), so every span stays inside its parent and siblings stay end to end; per step a different\n  // stretch: research runs faster, planning runs longer, the draft runs longer. A span's label shows by its width, so\n  // the first warp (this step's, then the others, then at half strength) that shows the same labels at every size is taken.\n  update: (d, step) => {\n    const o = d as typeof data;\n    const warps: [number, number, number][] = [[1.1, o.total, -0.2], [0, 5.6, 0.15], [5.6, o.total, 0.3]];\n    const at = ([t0, t1, a]: [number, number, number]) => {\n      const T = (t: number) => (t <= t0 || t >= t1 ? t : Math.round((t + a * Math.sin((Math.PI * (t - t0)) / (t1 - t0))) * 10) / 10);\n      return { ...o, spans: o.spans.map((s) => ({ ...s, s: T(s.s), e: T(s.e) })) };\n    };\n    const k = (step - 1) % 3, order = [...warps.slice(k), ...warps.slice(0, k)];\n    return [...order, ...order.map(([t0, t1, a]) => [t0, t1, a / 2] as [number, number, number])].map(at).find((c) => sameMarks(o, c)) ?? o;\n  },\n  describe: {\n    title: \"Agent trace\",\n    summary: `One agent run of ${sec(data.total)} in ${data.spans.length} spans over ${Math.max(...data.spans.map((s) => s.d)) + 1} levels; web.search takes ${sec(search.e - search.s)}.`,\n    table: {\n      head: [\"Span\", \"Depth\", \"Start\", \"End\", \"Duration\", \"Kind\"],\n      rows: data.spans.map((s) => [s.label, s.d, sec(s.s), sec(s.e), sec(s.e - s.s), kind(s.tok)]),\n    },\n  },\n};\n"
    }
  ],
  "categories": [
    "charts",
    "part-of-a-whole"
  ],
  "meta": {
    "access": "free",
    "no": 74,
    "family": "Part of a whole"
  }
}
