{"version":3,"sources":["../packages/core/src/profiler.ts"],"sourcesContent":["// tempus/profiler — a live overlay that shows how a frame is composed.\n//\n// It reads Tempus.inspect() (every Tempus.add() callback + every loop absorbed\n// by Tempus.patch(), in execution order) and lays each one out on a single\n// timeline whose full width is the per-frame budget (1000 / Tempus.targetFps).\n// Each segment's width is that callback's share of the budget, drawn end-to-end\n// so you can see the frame fill up — and overflow — left to right.\n\n// Import the published package entry (not the relative source) so this module\n// shares the ONE Tempus singleton with the host app. A relative import would\n// make tsup inline a second copy whose framerates are always empty.\nimport Tempus from 'tempus'\n\nexport type ProfilerCorner =\n  | 'top-left'\n  | 'top-right'\n  | 'bottom-left'\n  | 'bottom-right'\n\nexport type ProfilerOptions = {\n  // Overlay refresh rate. Kept low so the panel itself stays cheap; the\n  // measurements it shows are unaffected (they come from Tempus.inspect()).\n  fps?: number\n  // Where to pin the panel. Default 'top-left'.\n  corner?: ProfilerCorner\n  // Mount target. Defaults to document.body.\n  container?: HTMLElement\n}\n\nexport type ProfilerHandle = {\n  element: HTMLElement\n  destroy: () => void\n}\n\nconst isClient = typeof window !== 'undefined'\n\n// Our own render callback shows up in inspect() like any other — tag it so we\n// can filter it back out of the timeline.\nconst PROFILER_LABEL = 'tempus:profiler'\n\nconst STYLE_ID = 'tempus-profiler-style'\n\nconst CORNERS: Record<ProfilerCorner, string> = {\n  'top-left': 'top:12px;left:12px;',\n  'top-right': 'top:12px;right:12px;',\n  'bottom-left': 'bottom:12px;left:12px;',\n  'bottom-right': 'bottom:12px;right:12px;',\n}\n\n// Deterministic, readable hue per label so a callback keeps the same colour\n// across frames (identity at a glance, not a rainbow that reshuffles).\nfunction hueFor(label: string) {\n  let h = 0\n  for (let i = 0; i < label.length; i++) {\n    h = (h * 31 + label.charCodeAt(i)) | 0\n  }\n  return Math.abs(h) % 360\n}\n\nfunction colorFor(label: string) {\n  return `hsl(${hueFor(label)} 70% 55%)`\n}\n\nconst CSS = `\n.tempus-profiler {\n  position: fixed;\n  z-index: 2147483647;\n  width: 320px;\n  padding: 10px 12px 12px;\n  border-radius: 10px;\n  background: rgba(12, 12, 14, 0.92);\n  color: #e8e8ea;\n  font: 11px/1.4 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n  font-variant-numeric: tabular-nums;\n  -webkit-backdrop-filter: blur(6px);\n  backdrop-filter: blur(6px);\n  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.45);\n  user-select: none;\n}\n.tempus-profiler-head {\n  display: flex;\n  gap: 10px;\n  align-items: baseline;\n  margin-bottom: 8px;\n  cursor: grab;\n  touch-action: none;\n}\n.tempus-profiler.dragging { cursor: grabbing; }\n.tempus-profiler.dragging .tempus-profiler-head { cursor: grabbing; }\n.tempus-profiler-toggle {\n  flex: none;\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  width: 16px;\n  height: 16px;\n  padding: 0;\n  border: 0;\n  border-radius: 4px;\n  background: rgba(255, 255, 255, 0.1);\n  color: #e8e8ea;\n  font-size: 9px;\n  line-height: 1;\n  cursor: pointer;\n}\n.tempus-profiler-toggle:hover { background: rgba(255, 255, 255, 0.18); }\n.tempus-profiler-toggle.paused { background: rgba(125, 220, 125, 0.22); color: #7ddc7d; }\n.tempus-profiler-title { font-weight: 600; letter-spacing: 0.02em; }\n.tempus-profiler-head .spacer { flex: 1; }\n.tempus-profiler-head b { color: #fff; font-weight: 600; }\n.tempus-profiler-track {\n  position: relative;\n  height: 18px;\n  border-radius: 4px;\n  background: rgba(255, 255, 255, 0.06);\n  overflow: hidden;\n}\n.tempus-profiler-seg {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  min-width: 1px;\n  box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.35);\n}\n.tempus-profiler-seg.throttled {\n  background-image: repeating-linear-gradient(\n    -45deg,\n    rgba(255, 255, 255, 0.18) 0 4px,\n    transparent 4px 8px\n  );\n}\n.tempus-profiler-danger {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  background: rgba(255, 64, 64, 0.22);\n  pointer-events: none;\n}\n.tempus-profiler-budget {\n  position: absolute;\n  top: -2px;\n  bottom: -2px;\n  width: 2px;\n  background: #fff;\n  box-shadow: 0 0 4px rgba(255, 255, 255, 0.6);\n  pointer-events: none;\n}\n.tempus-profiler-scale {\n  display: flex;\n  justify-content: space-between;\n  margin: 3px 1px 8px;\n  color: rgba(232, 232, 234, 0.5);\n}\n.tempus-profiler-list { display: flex; flex-direction: column; gap: 3px; }\n.tempus-profiler-row { display: flex; align-items: center; gap: 7px; }\n.tempus-profiler-order {\n  flex: none;\n  width: 22px;\n  text-align: right;\n  color: rgba(232, 232, 234, 0.45);\n  font-size: 10px;\n}\n.tempus-profiler-dot {\n  width: 8px;\n  height: 8px;\n  border-radius: 2px;\n  flex: none;\n}\n.tempus-profiler-label {\n  flex: 1;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n.tempus-profiler-badge {\n  flex: none;\n  padding: 0 4px;\n  border-radius: 3px;\n  background: rgba(255, 255, 255, 0.1);\n  color: rgba(232, 232, 234, 0.7);\n  font-size: 9px;\n}\n.tempus-profiler-ms { flex: none; color: #fff; }\n.tempus-profiler-pct { flex: none; width: 40px; text-align: right; }\n.tempus-profiler.collapsed .tempus-profiler-track,\n.tempus-profiler.collapsed .tempus-profiler-scale,\n.tempus-profiler.collapsed .tempus-profiler-list { display: none; }\n`\n\nfunction injectStyle() {\n  if (document.getElementById(STYLE_ID)) return\n  const style = document.createElement('style')\n  style.id = STYLE_ID\n  style.textContent = CSS\n  document.head.appendChild(style)\n}\n\n// Mean over a callback's sample window. Throttled buckets only push a sample on\n// the frames they actually run, so this is the average \"cost when it runs\".\nfunction average(samples: number[]) {\n  if (!samples.length) return 0\n  let sum = 0\n  for (const s of samples) sum += s\n  return sum / samples.length\n}\n\nfunction pctColor(pct: number) {\n  if (pct > 66) return '#ff5b5b'\n  if (pct > 33) return '#ffb000'\n  return '#7ddc7d'\n}\n\n// Compact, readable `order` for the legend gutter. ±Infinity (used to force a\n// callback first/last) shows as ±∞ rather than a giant number.\nfunction formatOrder(order: number) {\n  if (order === Number.POSITIVE_INFINITY) return '∞'\n  if (order === Number.NEGATIVE_INFINITY) return '-∞'\n  return String(order)\n}\n\nexport function profiler(options: ProfilerOptions = {}): ProfilerHandle {\n  if (!isClient) {\n    // SSR-safe no-op so callers don't have to guard.\n    return { element: null as unknown as HTMLElement, destroy() {} }\n  }\n\n  // Refresh twice a second by default: the panel shows a rolling average, so a\n  // faster cadence just makes the numbers flicker without telling you more.\n  const { fps = 5, corner = 'top-left', container = document.body } = options\n\n  injectStyle()\n\n  const root = document.createElement('div')\n  root.className = 'tempus-profiler'\n  root.style.cssText = CORNERS[corner]\n  root.innerHTML = `\n    <div class=\"tempus-profiler-head\">\n      <button class=\"tempus-profiler-toggle\" data-toggle type=\"button\"></button>\n      <span class=\"tempus-profiler-title\">tempus</span>\n      <span class=\"spacer\"></span>\n      <span class=\"tempus-profiler-stat\" data-fps></span>\n      <span class=\"tempus-profiler-stat\" data-usage></span>\n    </div>\n    <div class=\"tempus-profiler-track\" data-track></div>\n    <div class=\"tempus-profiler-scale\">\n      <span>0</span>\n      <span data-budget></span>\n    </div>\n    <div class=\"tempus-profiler-list\" data-list></div>\n  `\n  container.appendChild(root)\n\n  const head = root.querySelector('.tempus-profiler-head') as HTMLElement\n  const toggleEl = root.querySelector('[data-toggle]') as HTMLButtonElement\n  const fpsEl = root.querySelector('[data-fps]') as HTMLElement\n  const usageEl = root.querySelector('[data-usage]') as HTMLElement\n  const trackEl = root.querySelector('[data-track]') as HTMLElement\n  const budgetEl = root.querySelector('[data-budget]') as HTMLElement\n  const listEl = root.querySelector('[data-list]') as HTMLElement\n\n  // Drag the panel by its header. We switch to top/left positioning on first\n  // grab (the panel starts pinned to a corner via right/bottom), clamp to the\n  // viewport, and treat a press that never moves past a few px as a tap —\n  // which toggles collapse, preserving the old click-to-collapse behaviour.\n  const DRAG_THRESHOLD = 4 // px before a press counts as a drag, not a tap\n  let dragging = false\n  let moved = false\n  let startX = 0\n  let startY = 0\n  let originLeft = 0\n  let originTop = 0\n\n  const onPointerDown = (e: PointerEvent) => {\n    if (e.button !== 0) return\n    const rect = root.getBoundingClientRect()\n    // Pin via left/top from here on so right/bottom corners don't fight us.\n    originLeft = rect.left\n    originTop = rect.top\n    startX = e.clientX\n    startY = e.clientY\n    dragging = true\n    moved = false\n    head.setPointerCapture(e.pointerId)\n  }\n\n  const onPointerMove = (e: PointerEvent) => {\n    if (!dragging) return\n    const dx = e.clientX - startX\n    const dy = e.clientY - startY\n    if (!moved && Math.hypot(dx, dy) < DRAG_THRESHOLD) return\n    if (!moved) {\n      moved = true\n      root.classList.add('dragging')\n      root.style.right = 'auto'\n      root.style.bottom = 'auto'\n    }\n    // Clamp so the panel can't be dragged fully off-screen.\n    const maxLeft = window.innerWidth - root.offsetWidth\n    const maxTop = window.innerHeight - root.offsetHeight\n    const left = Math.min(Math.max(originLeft + dx, 0), Math.max(0, maxLeft))\n    const top = Math.min(Math.max(originTop + dy, 0), Math.max(0, maxTop))\n    root.style.left = `${left}px`\n    root.style.top = `${top}px`\n  }\n\n  const onPointerUp = (e: PointerEvent) => {\n    if (!dragging) return\n    dragging = false\n    root.classList.remove('dragging')\n    if (head.hasPointerCapture(e.pointerId)) head.releasePointerCapture(e.pointerId)\n    // A press that never crossed the threshold is a tap → toggle collapse.\n    if (!moved) root.classList.toggle('collapsed')\n  }\n\n  head.addEventListener('pointerdown', onPointerDown)\n  head.addEventListener('pointermove', onPointerMove)\n  head.addEventListener('pointerup', onPointerUp)\n  head.addEventListener('pointercancel', onPointerUp)\n\n  // Start/stop the whole Tempus loop. Reflect the live state on every render\n  // tick too, so the button stays correct if play/pause happens elsewhere.\n  const syncToggle = () => {\n    const playing = Tempus.isPlaying\n    toggleEl.textContent = playing ? '⏸' : '▶'\n    toggleEl.classList.toggle('paused', !playing)\n    toggleEl.setAttribute('aria-label', playing ? 'Stop the loop' : 'Start the loop')\n  }\n  toggleEl.addEventListener('click', (e) => {\n    e.stopPropagation()\n    if (Tempus.isPlaying) Tempus.pause()\n    else Tempus.play()\n    // render() is part of the loop, so it won't fire while paused — update now.\n    syncToggle()\n  })\n  // Keep button presses from starting a header drag / collapse toggle.\n  toggleEl.addEventListener('pointerdown', (e) => e.stopPropagation())\n  syncToggle()\n\n  const render = () => {\n    syncToggle()\n    const budget = Tempus.frameBudget\n\n    const entries = Tempus.inspect()\n      .filter((entry) => entry.label !== PROFILER_LABEL)\n      .map((entry) => {\n        // Rolling average over the sample window (~1s at 60fps) rather than the\n        // last frame, so the once-a-second readout stays stable instead of\n        // latching onto a single spiky frame.\n        const duration = average(entry.samples)\n        return {\n          label: entry.source === 'patch' ? `${entry.label} ⟳` : entry.label,\n          duration,\n          order: entry.order,\n          throttled: entry.fps !== Number.POSITIVE_INFINITY,\n          fps: entry.fps,\n          color: colorFor(entry.label),\n        }\n      })\n\n    const total = entries.reduce((acc, e) => acc + e.duration, 0)\n    // The timeline spans at least one budget; if the frame blew through it,\n    // grow the span so the overflow stays visible and the budget marker slides\n    // left to mark where the limit was.\n    const span = Math.max(budget, total) || budget\n    const budgetLeft = (budget / span) * 100\n\n    // Header\n    fpsEl.innerHTML = `<b>${Math.round(Tempus.fps ?? 0)}</b> fps`\n    const usagePct = Math.round((total / budget) * 100)\n    usageEl.innerHTML = `<b style=\"color:${pctColor(usagePct)}\">${usagePct}%</b> budget`\n    budgetEl.textContent = `${budget.toFixed(1)}ms`\n\n    // Timeline: each callback as a segment, laid end-to-end.\n    let offset = 0\n    let segHTML = ''\n    for (const e of entries) {\n      const left = (offset / span) * 100\n      const width = (e.duration / span) * 100\n      offset += e.duration\n      segHTML += `<div class=\"tempus-profiler-seg${\n        e.throttled ? ' throttled' : ''\n      }\" style=\"left:${left}%;width:${width}%;background:${e.color}\" title=\"${\n        e.label\n      }: ${e.duration.toFixed(2)}ms\"></div>`\n    }\n    // Over-budget region + budget marker.\n    if (total > budget) {\n      segHTML += `<div class=\"tempus-profiler-danger\" style=\"left:${budgetLeft}%;width:${\n        100 - budgetLeft\n      }%\"></div>`\n    }\n    segHTML += `<div class=\"tempus-profiler-budget\" style=\"left:${budgetLeft}%\"></div>`\n    trackEl.innerHTML = segHTML\n\n    // Legend / detail list, ordered by `order` (low → high, i.e. the order\n    // callbacks run). The timeline above keeps true execution order.\n    listEl.innerHTML = [...entries]\n      .sort((a, b) => a.order - b.order)\n      .map((e) => {\n        const pct = (e.duration / budget) * 100\n        return `<div class=\"tempus-profiler-row\">\n          <span class=\"tempus-profiler-order\" title=\"order ${formatOrder(\n            e.order\n          )}\">${formatOrder(e.order)}</span>\n          <span class=\"tempus-profiler-dot\" style=\"background:${e.color}\"></span>\n          <span class=\"tempus-profiler-label\">${e.label}</span>\n          ${\n            e.throttled\n              ? `<span class=\"tempus-profiler-badge\">${e.fps}${\n                  typeof e.fps === 'number' ? 'fps' : ''\n                }</span>`\n              : ''\n          }\n          <span class=\"tempus-profiler-ms\">${e.duration.toFixed(2)}ms</span>\n          <span class=\"tempus-profiler-pct\" style=\"color:${pctColor(pct)}\">${pct.toFixed(\n            0\n          )}%</span>\n        </div>`\n      })\n      .join('')\n  }\n\n  // Run last (order Infinity) so we snapshot after every other callback has\n  // executed this frame. Throttled to keep the panel cheap.\n  const unsubscribe = Tempus.add(render, {\n    fps,\n    order: Number.POSITIVE_INFINITY,\n    label: PROFILER_LABEL,\n  })\n\n  return {\n    element: root,\n    destroy() {\n      unsubscribe?.()\n      root.remove()\n    },\n  }\n}\n"],"mappings":"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","names":[]}