Acceptance criteria only matter when shown working. This dial reports how many of the cycle's criteria have been demonstrated end-to-end, separating "done" from "claimed done".
Acceptance Criteria
[ ] 180-degree arc with demonstrated/total ratio
[ ] Bands by completion: danger under 50, attention 50-79, success 80+
[ ] Ratio readout in tabular numerals
[ ] Negative: does NOT require JS
Constraints
Pure SVG, no runtime
Theme-aware via tokens
// demonstration-completion-meter.astro
---
import type { CompendiumMeta } from '../../../data/types';
export const meta: CompendiumMeta = {
id: 484,
slug: 'demonstration-completion-meter',
name: 'Demonstration Completion Meter',
category: 'maturity-process',
subcategory: 'instruments',
pillar: 'de',
description: 'Half-circle gauge showing the fraction of acceptance criteria demonstrated this cycle.',
spec: `## Intent
Acceptance criteria only matter when shown working. This dial reports how many of the cycle's criteria have been demonstrated end-to-end, separating "done" from "claimed done".
## Acceptance Criteria
- [ ] 180-degree arc with demonstrated/total ratio
- [ ] Bands by completion: danger under 50, attention 50-79, success 80+
- [ ] Ratio readout in tabular numerals
- [ ] Negative: does NOT require JS
## Constraints
- Pure SVG, no runtime
- Theme-aware via tokens`,
tags: ['svg', 'gauge', 'animated', 'reduced-motion', 'real-content', 'dark-mode-tested'],
status: 'stable',
health: { ics: 88, a11y: 'aa', themed: true, animated: true },
};
const demonstrated = 17;
const total = 24;
const pct = Math.round((demonstrated / total) * 100);
const fill = pct >= 80 ? 'var(--color-success)' : pct >= 50 ? 'var(--color-attention)' : 'var(--color-danger)';
const band = pct >= 80 ? 'SHIPPABLE' : pct >= 50 ? 'IN PROGRESS' : 'EARLY';
const r = 90;
const arcTotal = Math.PI * r;
const dashOffset = arcTotal * (1 - pct / 100);
---
<div data-this-component class="w-full bg-paper text-ink border-4 border-ink p-4 flex flex-col items-center overflow-hidden">
<svg viewBox="0 0 200 120" class="w-full max-w-[280px] block" role="img" aria-label={`Demonstration ${demonstrated} of ${total} complete, ${band}`}>
<path d="M 10 100 A 90 90 0 0 1 190 100" stroke="var(--color-ink)" stroke-width="14" fill="none" opacity="0.12" />
<path
d="M 10 100 A 90 90 0 0 1 190 100"
stroke={fill}
stroke-width="14"
fill="none"
stroke-dasharray={arcTotal}
stroke-dashoffset={dashOffset}
style="transition: stroke-dashoffset 800ms cubic-bezier(0.2,0,0.13,1.4)"
/>
<text x="100" y="84" text-anchor="middle" font-family="Inter, sans-serif" font-weight="900" font-size="32" fill="var(--color-ink)" class="tabular-nums">{demonstrated}/{total}</text>
<text x="100" y="104" text-anchor="middle" font-family="JetBrains Mono, monospace" font-size="9" letter-spacing="2" fill="var(--color-ink)" opacity="0.6">{pct}% demonstrated</text>
</svg>
<div class="mt-1 flex items-baseline gap-2">
<span class="font-mono text-[10px] uppercase tracking-widest opacity-60">demos</span>
<span class="font-black text-[11px] uppercase tracking-widest">{band}</span>
</div>
</div>