Skip to main content
Compendium / Maturity & Process / Indicators / Process Cadence Pulse
#444

Process Cadence Pulse

Tick-grid of recent process beats — daily standups, weekly reviews — showing cadence health at a glance.

STABLE DE
#chart #real-content #dark-mode-tested #responsive
Live
// cadence · 14 beats 86%
  1. ×
  2. ×
hits12
missed2
streak5
Spec

Intent

Cadence is the metronome of a mature process. This indicator plots the last N expected beats; struck ticks are filled, missed ticks are hollow with a danger mark. Drift is visible without a number.

Acceptance Criteria

  • [ ] 14-cell grid of recent beats
  • [ ] Hit cells filled with pillar token; missed cells flagged
  • [ ] Hit-rate readout in tabular-nums
  • [ ] Negative: does NOT animate by default

Constraints

  • Pure CSS
  • Theme-aware
// process-cadence-pulse.astro
---
import type { CompendiumMeta } from '../../../data/types';

export const meta: CompendiumMeta = {
  id: 444,
  slug: 'process-cadence-pulse',
  name: 'Process Cadence Pulse',
  category: 'maturity-process',
  subcategory: 'indicators',
  pillar: 'de',
  description: 'Tick-grid of recent process beats — daily standups, weekly reviews — showing cadence health at a glance.',
  spec: `## Intent
Cadence is the metronome of a mature process. This indicator plots the last N expected beats; struck ticks are filled, missed ticks are hollow with a danger mark. Drift is visible without a number.

## Acceptance Criteria
- [ ] 14-cell grid of recent beats
- [ ] Hit cells filled with pillar token; missed cells flagged
- [ ] Hit-rate readout in tabular-nums
- [ ] Negative: does NOT animate by default

## Constraints
- Pure CSS
- Theme-aware`,
  tags: ['chart', 'real-content', 'dark-mode-tested', 'responsive'],
  status: 'stable',
  health: { ics: 87, a11y: 'aa', themed: true, animated: false },
};

const beats = [1,1,1,0,1,1,1,1,0,1,1,1,1,1];
const hits = beats.filter((b) => b).length;
const rate = Math.round((hits / beats.length) * 100);
---

<div data-this-component class="w-full bg-paper text-black border-4 border-black overflow-hidden">
  <header class="flex items-baseline justify-between px-3 py-2 border-b-2 border-black">
    <span class="font-mono text-[10px] uppercase tracking-widest opacity-60">// cadence · 14 beats</span>
    <span class="font-mono text-[10px] uppercase tracking-widest tabular-nums">{rate}%</span>
  </header>
  <div class="p-3">
    <ol class="grid grid-cols-7 gap-1.5" aria-label="Recent cadence beats">
      {beats.map((b, i) => (
        <li
          class:list={[
            'aspect-square border-2 border-black flex items-center justify-center font-black text-[10px]',
            b ? 'bg-de text-black' : 'bg-paper text-danger',
          ]}
          aria-label={b ? `Beat ${i + 1} hit` : `Beat ${i + 1} missed`}
        >{b ? '' : '×'}</li>
      ))}
    </ol>
    <div class="mt-3 pt-3 border-t-2 border-black grid grid-cols-3 gap-2 font-mono text-[9px] uppercase tracking-widest">
      <div class="min-w-0"><span class="opacity-60 block">hits</span><span class="font-black text-[11px] tabular-nums">{hits}</span></div>
      <div class="min-w-0"><span class="opacity-60 block">missed</span><span class="font-black text-[11px] tabular-nums">{beats.length - hits}</span></div>
      <div class="min-w-0 text-end"><span class="opacity-60 block">streak</span><span class="font-black text-[11px] tabular-nums">5</span></div>
    </div>
  </div>
</div>
</content>
</invoke>