{"spec_id":"flamegraph-basic","library":"muix","language":"javascript","code":"// anyplot.ai\n// flamegraph-basic: Flame Graph for Performance Profiling\n// Library: muix 7.29.1 | JavaScript 22.23.2\n// Quality: 96/100 | Created: 2026-08-20\nimport { ChartContainer } from \"@mui/x-charts/ChartContainer\";\nimport { useXScale, useYScale } from \"@mui/x-charts/hooks\";\n\nconst t = window.ANYPLOT_TOKENS;\n\nconst title = \"flamegraph-basic · javascript · muix · anyplot.ai\";\nconst titleFontSize = Math.max(16, Math.round(34 * Math.min(1, 67 / title.length)));\n\n// --- Data: a simulated CPU profile of a web-request handler, expressed as a\n// call tree (function -> children) and fanned out via a fixed-seed LCG into\n// dozens of realistic-looking stack traces -- comfortably inside the spec's\n// 50-500 unique stack traces -- rather than a small illustrative example.\n// Each node's samples equal the sum of its children's, exactly as a real\n// profiler reports it. -------------------------------------------------------\nlet seed = 20260820;\nfunction rand() {\n  seed = (seed * 48271) % 2147483647;\n  return seed / 2147483647;\n}\n\nconst VERB = [\"parse\", \"validate\", \"compute\", \"fetch\", \"serialize\", \"cache\", \"dispatch\", \"format\", \"aggregate\", \"filter\", \"normalize\", \"encode\", \"decode\", \"resolve\", \"persist\", \"merge\"];\nconst NOUN = [\"headers\", \"payload\", \"record\", \"query\", \"response\", \"token\", \"schema\", \"row\", \"buffer\", \"session\", \"event\", \"job\", \"metric\", \"column\", \"batch\", \"socket\"];\n\nconst usedNames = new Set([\"main\", \"parse_request\", \"authenticate_user\", \"handle_business_logic\", \"write_response\"]);\nfunction makeName() {\n  let name;\n  do {\n    name = `${VERB[Math.floor(rand() * VERB.length)]}_${NOUN[Math.floor(rand() * NOUN.length)]}`;\n  } while (usedNames.has(name));\n  usedNames.add(name);\n  return name;\n}\n\n// Recursively split `samples` into 2-3 unevenly-weighted children until\n// `depth` runs out or a subtree is too small to split further, so the\n// resulting traces read as an uneven, realistic profile rather than a\n// perfectly balanced synthetic tree.\nfunction expand(node, depth) {\n  if (depth <= 0 || node.samples < 220) return node;\n  const childCount = 2 + Math.floor(rand() * 2); // 2-3 children\n  const weights = Array.from({ length: childCount }, () => 0.5 + rand());\n  const weightSum = weights.reduce((a, b) => a + b, 0);\n  let remaining = node.samples;\n  node.children = weights.map((w, i) => {\n    const samples = i === childCount - 1 ? remaining : Math.round((w / weightSum) * node.samples);\n    remaining -= samples;\n    return expand({ name: makeName(), samples }, depth - 1);\n  });\n  return node;\n}\n\nconst callTree = {\n  name: \"main\",\n  children: [\n    expand({ name: \"parse_request\", samples: 2100 }, 4),\n    expand({ name: \"authenticate_user\", samples: 1400 }, 4),\n    expand({ name: \"handle_business_logic\", samples: 7700 }, 5),\n    expand({ name: \"write_response\", samples: 2800 }, 4),\n  ],\n};\ncallTree.samples = callTree.children.reduce((sum, c) => sum + c.samples, 0);\nconst TOTAL_SAMPLES = callTree.samples;\n\n// Flatten the tree into positioned frames: x0/width in sample units (so bar\n// width is proportional to samples, per the spec), depth = stack row.\n// Siblings are laid out contiguously left-to-right with no gaps, standard\n// flame-graph (icicle) layout.\nfunction layoutFrames(node, depth, x0, out) {\n  out.push({ name: node.name, depth, x0, width: node.samples, samples: node.samples });\n  let cursor = x0;\n  (node.children ?? []).forEach((child) => {\n    layoutFrames(child, depth + 1, cursor, out);\n    cursor += child.samples;\n  });\n  return out;\n}\nconst frames = layoutFrames(callTree, 0, 0, []);\nconst maxDepth = Math.max(...frames.map((f) => f.depth));\n\n// The dominant caller->callee chain (always descending into the heaviest\n// child) -- the \"hot path\" a profiler reader would chase first.\nfunction dominantChain(node, path) {\n  path.push(node.name);\n  if (!node.children || node.children.length === 0) return path;\n  const hottestChild = node.children.reduce((a, b) => (b.samples > a.samples ? b : a));\n  return dominantChain(hottestChild, path);\n}\nconst HOT_CHAIN = dominantChain(callTree, []);\nconst HOT_PATH_NAMES = new Set(HOT_CHAIN);\nconst hotLeafSamples = (() => {\n  let node = callTree;\n  for (let i = 1; i < HOT_CHAIN.length; i++) node = node.children.find((c) => c.name === HOT_CHAIN[i]);\n  return node.samples;\n})();\nconst hotLeafPct = ((hotLeafSamples / TOTAL_SAMPLES) * 100).toFixed(1);\nconst hotPathCaption =\n  HOT_CHAIN.length <= 4\n    ? `Hot path: ${HOT_CHAIN.join(\" → \")} — ${hotLeafPct}% of total samples`\n    : `Hot path: ${HOT_CHAIN[0]} → ${HOT_CHAIN[1]} → … → ${HOT_CHAIN[HOT_CHAIN.length - 1]} — ${hotLeafPct}% of total samples`;\n\n// --- Color: the spec's Notes call for \"a warm color palette (yellows,\n// oranges, reds) following the conventional flame graph aesthetic\" -- built\n// purely from Imprint anchors (amber/ochre/matte-red), keyed to each frame's\n// share of total samples so hotter (more-sampled) frames read redder. The\n// root is the 100%-baseline and keeps the theme-adaptive neutral treatment\n// instead of joining the gradient. ------------------------------------------\nconst WARM_STOPS = [\n  [221, 204, 119], // #DDCC77 amber\n  [189, 130, 51], // #BD8233 ochre\n  [174, 48, 48], // #AE3030 matte red\n];\nfunction warmColorRgb(u) {\n  const clamped = Math.min(1, Math.max(0, u));\n  const scaled = clamped * (WARM_STOPS.length - 1);\n  const i = Math.min(WARM_STOPS.length - 2, Math.floor(scaled));\n  const frac = scaled - i;\n  return [0, 1, 2].map((c) => Math.round(WARM_STOPS[i][c] + (WARM_STOPS[i + 1][c] - WARM_STOPS[i][c]) * frac));\n}\nfunction relLuminance([r, g, b]) {\n  const srgb = [r, g, b].map((v) => v / 255).map((v) => (v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4)));\n  return 0.2126 * srgb[0] + 0.7152 * srgb[1] + 0.0722 * srgb[2];\n}\nconst nonRootPcts = frames.filter((f) => f.depth > 0).map((f) => f.samples / TOTAL_SAMPLES);\nconst MIN_PCT = Math.min(...nonRootPcts);\nconst MAX_PCT = Math.max(...nonRootPcts);\n\nconst ROW_H = 0.92; // fraction of each depth row's band actually drawn (rest = gap)\nconst LABEL_FONT_SIZE = 14;\nconst CHAR_WIDTH_RATIO = 0.58; // rough average glyph width, in units of font size\nconst MARGIN = { top: 142, right: 40, bottom: 30, left: 110 };\n\n// Each stack frame as a rect, sized/positioned from the layout above. The\n// function name is drawn inside the bar only when it actually fits -- no\n// rotated or truncated text, per the spec's \"wide enough to fit\" rule. A\n// native <title> gives every frame a real (non-fake) hover tooltip. Frames\n// on the dominant hot path get a bolder outline so the reader's eye is\n// drawn straight to it instead of having to compare bar widths by hand.\nfunction FlameFrames() {\n  const xs = useXScale();\n  const ys = useYScale();\n  return (\n    <g>\n      {frames.map((f) => {\n        const xLeft = xs(f.x0);\n        const xRight = xs(f.x0 + f.width);\n        const yTop = ys(f.depth + ROW_H);\n        const yBottom = ys(f.depth);\n        const w = xRight - xLeft;\n        const h = yBottom - yTop;\n        const pct = (f.samples / TOTAL_SAMPLES) * 100;\n        const isRoot = f.depth === 0;\n        const isHot = HOT_PATH_NAMES.has(f.name);\n        const rgb = isRoot ? null : warmColorRgb((pct / 100 - MIN_PCT) / (MAX_PCT - MIN_PCT || 1));\n        const fill = isRoot ? t.ink : `rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`;\n        const labelFill = isRoot ? t.pageBg : relLuminance(rgb) > 0.45 ? \"#1A1A17\" : \"#FAF8F1\";\n        const fits = w - 14 >= f.name.length * LABEL_FONT_SIZE * CHAR_WIDTH_RATIO;\n        return (\n          <g key={f.name}>\n            <rect x={xLeft} y={yTop} width={w} height={h} fill={fill} stroke={isHot ? t.ink : t.pageBg} strokeWidth={isHot ? 3 : 1.5}>\n              <title>{`${f.name}: ${f.samples.toLocaleString()} samples (${pct.toFixed(1)}%)`}</title>\n            </rect>\n            {fits && (\n              <text\n                x={xLeft + w / 2}\n                y={yTop + h / 2}\n                textAnchor=\"middle\"\n                dominantBaseline=\"central\"\n                fontSize={LABEL_FONT_SIZE}\n                fontWeight={600}\n                fill={labelFill}\n                pointerEvents=\"none\"\n              >\n                {f.name}\n              </text>\n            )}\n          </g>\n        );\n      })}\n    </g>\n  );\n}\n\n// Row labels on the left -- the chart has no numeric x-axis (bar width is a\n// proportion, not a metric to read off a scale; x-position is layout-only,\n// not temporal -- see spec), so depth is the only axis worth labeling.\nfunction DepthLabels() {\n  const ys = useYScale();\n  return (\n    <g fontSize={13} fill={t.inkSoft} textAnchor=\"end\">\n      {Array.from({ length: maxDepth + 1 }, (_, d) => (\n        <text key={d} x={MARGIN.left - 14} y={ys(d + ROW_H / 2)} dominantBaseline=\"central\">\n          {d === 0 ? \"Depth 0 · root\" : `Depth ${d}`}\n        </text>\n      ))}\n    </g>\n  );\n}\n\n// Color key: the root's neutral swatch plus the warm amber->ochre->red scale\n// used for every other frame, keyed to each frame's share of total samples.\nfunction HeatLegend() {\n  const FS = 13;\n  const CHAR_W = FS * 0.58;\n  const { width } = window.ANYPLOT_SIZE;\n  const y = 118;\n  const barW = 220;\n  const barH = 14;\n  const rootLabel = \"root · 100% of samples\";\n  const leftLabel = \"fewer samples\";\n  const rightLabel = \"more samples\";\n  const rootSwatchW = 14;\n  const rootBlockW = rootSwatchW + 8 + rootLabel.length * CHAR_W;\n  const leftLabelW = leftLabel.length * CHAR_W;\n  const rightLabelW = rightLabel.length * CHAR_W;\n  const GAP = 16;\n  const SECTION_GAP = 40;\n  const barBlockW = leftLabelW + GAP + barW + GAP + rightLabelW;\n  const totalWidth = rootBlockW + SECTION_GAP + barBlockW;\n\n  let x = width / 2 - totalWidth / 2;\n  const rootSwatchX = x;\n  const rootLabelX = rootSwatchX + rootSwatchW + 8;\n  x += rootBlockW + SECTION_GAP;\n  const leftLabelX = x;\n  x += leftLabelW + GAP;\n  const barX = x;\n  x += barW + GAP;\n  const rightLabelX = x;\n\n  return (\n    <g fontSize={FS} fill={t.inkSoft}>\n      <defs>\n        <linearGradient id=\"flamegraphHeatGradient\" x1=\"0%\" x2=\"100%\" y1=\"0%\" y2=\"0%\">\n          <stop offset=\"0%\" stopColor=\"#DDCC77\" />\n          <stop offset=\"50%\" stopColor=\"#BD8233\" />\n          <stop offset=\"100%\" stopColor=\"#AE3030\" />\n        </linearGradient>\n      </defs>\n      <rect x={rootSwatchX} y={y - rootSwatchW + 2} width={rootSwatchW} height={rootSwatchW} rx={2} fill={t.ink} />\n      <text x={rootLabelX} y={y}>\n        {rootLabel}\n      </text>\n      <text x={leftLabelX} y={y}>\n        {leftLabel}\n      </text>\n      <rect x={barX} y={y - barH + 2} width={barW} height={barH} rx={2} fill=\"url(#flamegraphHeatGradient)\" />\n      <text x={rightLabelX} y={y}>\n        {rightLabel}\n      </text>\n    </g>\n  );\n}\n\n// --- Chart (default-exported component -- the harness mounts it) -------------\nexport default function Chart() {\n  const { width, height } = window.ANYPLOT_SIZE;\n  const subtitle = `Simulated web-request CPU profile · ${TOTAL_SAMPLES.toLocaleString()} samples across ${frames.length} stack frames`;\n\n  return (\n    <ChartContainer\n      width={width}\n      height={height}\n      series={[]}\n      margin={MARGIN}\n      xAxis={[{ scaleType: \"linear\", min: 0, max: TOTAL_SAMPLES, disableLine: true, disableTicks: true, valueFormatter: () => \"\" }]}\n      yAxis={[{ scaleType: \"linear\", min: 0, max: maxDepth + 1, disableLine: true, disableTicks: true, valueFormatter: () => \"\" }]}\n      skipAnimation\n    >\n      <FlameFrames />\n      <DepthLabels />\n      <HeatLegend />\n      <text x={width / 2} y={46} textAnchor=\"middle\" fontSize={titleFontSize} fontWeight={600} fill={t.ink}>\n        {title}\n      </text>\n      <text x={width / 2} y={72} textAnchor=\"middle\" fontSize={15} fill={t.inkSoft}>\n        {subtitle}\n      </text>\n      <text x={width / 2} y={94} textAnchor=\"middle\" fontSize={13} fontStyle=\"italic\" fill={t.inkSoft}>\n        {hotPathCaption}\n      </text>\n    </ChartContainer>\n  );\n}\n"}