Skip to main content
Compendium / Metrics & Telemetry / Gauges / Drift Gauge
#058

Drift Gauge

A radial gauge with a hard needle measuring distance between intent and implementation.

STABLE DE
#svg #gauge #real-content
Live
34% drift WATCH
Spec

Intent

Drift is the silent killer in AI-led codebases. This gauge gives a single, glanceable measure of how far implementation has wandered from spec.

Acceptance Criteria

  • [ ] Needle position maps to drift percentage
  • [ ] Coloured bands: success (low) → attention (mid) → danger (high)
  • [ ] Numeric readout below the needle
  • [ ] Negative: does NOT smooth the needle — neubrutalist hard angle

Constraints

  • Pure SVG, no JS
  • Theme-aware colours
// drift-gauge.astro
---
import type { CompendiumMeta } from '../../../data/types';

export const meta: CompendiumMeta = {
  id: 58,
  slug: 'drift-gauge',
  name: 'Drift Gauge',
  category: 'metrics-telemetry',
  subcategory: 'gauges',
  pillar: 'de',
  description: 'A radial gauge with a hard needle measuring distance between intent and implementation.',
  spec: `## Intent
Drift is the silent killer in AI-led codebases. This gauge gives a single, glanceable measure of how far implementation has wandered from spec.

## Acceptance Criteria
- [ ] Needle position maps to drift percentage
- [ ] Coloured bands: success (low) → attention (mid) → danger (high)
- [ ] Numeric readout below the needle
- [ ] Negative: does NOT smooth the needle — neubrutalist hard angle

## Constraints
- Pure SVG, no JS
- Theme-aware colours`,
  tags: ['svg', 'gauge', 'real-content'],
  status: 'stable',
  health: { ics: 88, a11y: 'aa', themed: true, animated: false },
};

const drift = 34; // percent
const angle = -90 + (drift / 100) * 180;
const rad = (angle * Math.PI) / 180;
const needleX = 100 + Math.cos(rad) * 70;
const needleY = 100 + Math.sin(rad) * 70;
const band = drift < 25 ? 'NOMINAL' : drift < 60 ? 'WATCH' : 'CRITICAL';
---

<div class="w-full bg-paper text-black border-4 border-black p-4 flex flex-col items-center">
  <svg viewBox="0 0 200 130" class="w-full max-w-[280px] block" aria-label={`Drift ${drift}%, ${band}`}>
    <path d="M 30 100 A 70 70 0 0 1 79.3 33.3" stroke="var(--color-success)" stroke-width="16" fill="none" />
    <path d="M 79.3 33.3 A 70 70 0 0 1 166.6 78.4" stroke="var(--color-attention)" stroke-width="16" fill="none" />
    <path d="M 166.6 78.4 A 70 70 0 0 1 170 100" stroke="var(--color-danger)" stroke-width="16" fill="none" />
    <g stroke="var(--color-ink)" stroke-width="2">
      <line x1="30" y1="100" x2="22" y2="100" />
      <line x1="100" y1="30" x2="100" y2="22" />
      <line x1="170" y1="100" x2="178" y2="100" />
    </g>
    <line x1="100" y1="100" x2={needleX} y2={needleY} stroke="var(--color-ink)" stroke-width="4" stroke-linecap="butt" />
    <circle cx="100" cy="100" r="6" fill="var(--color-ink)" />
    <circle cx="100" cy="100" r="2" fill="var(--color-paper)" />
  </svg>
  <div class="mt-1 flex items-baseline gap-3">
    <span class="font-black text-2xl tabular-nums">{drift}<span class="text-sm opacity-60">%</span></span>
    <span class="font-mono text-[10px] uppercase tracking-widest opacity-60">drift</span>
    <span class="font-black text-[11px] uppercase tracking-widest">{band}</span>
  </div>
</div>