New in v1.2.0: the Holter monitor β a 24-hour tape of
when you actually code, with a diagnosis stamp: NOCTURNAL, EARLY BIRD,
ARRHYTHMIC⦠and a SUSPECTED SLEEP window inferred from your quiet hours.
A living EKG card for your GitHub README. One username in, a beating heart out β it beats faster when you ship, dims when you rest, flatlines when you vanish, and revives when you come back.
Unlike every static stats card, your pulse card is generated at the moment someone views it. Time actually passes on it.
[](https://github-pulse-topaz.vercel.app)- A real EKG waveform β one beat per day for your last 14 days; beat height = contributions that day. Zero-commit days stay flat. The waveform's P/T-waves and jitter are seeded from your username, so no two hearts look alike.
- BPM β derived from your weekly contribution count.
- Life state β
RADIANT β STEADY β FADING β CRITICAL β FLATLINE, computed from time since your last contribution. Come back after a 14-day flatline and the card stampsβ‘ REVIVEDfor 48 hours. - Blood type β your top language, typed (
TS+,PY-,RS+β¦). The sign is live:+if you shipped this week. - Streak, yearly beats, stars β and a
β beating nowindicator when your last beat was today.
The card decays in real time and earns its way back:
RADIANT β STEADY β FADING β CRITICAL β FLATLINE β β‘ REVIVED
<24h β€3d β€7d <14d β₯14d first beat after
Go quiet for two weeks and your card literally dies in public β time of death
printed on it. Your first commit after a flatline stamps β‘ REVIVED on the card.
Preview any state without waiting to die: ?state=radiant|steady|fading|critical|flatline|revived.
Add ?size=<name> to fit your README layout:
| size | dimensions | good for |
|---|---|---|
card (default) |
520Γ190 | next to other stat cards |
monitor |
830Γ260 | the full vitals monitor β three traces + numbers column |
wide |
830Γ150 | full-width banner across the README |
compact |
340Γ130 | sidebars, small profiles |
badge |
260Γ70 | one-liners, project READMEs, bios |
Add ?theme=<name>:
| theme | vibe |
|---|---|
aura (default) |
violetβcyanβmagenta gradient glow |
phosphor |
classic green hospital monitor |
cyber |
ice-cyan |
ember |
burning amber |
rose |
hot magenta |
github |
matches the contribution graph |
mono |
white on black |
paper |
printed ECG strip (light) |
dracula |
matches the Dracula editor theme |
tokyonight |
matches Tokyo Night |
catppuccin |
matches Catppuccin Mocha |
nord |
matches Nord |
gruvbox |
matches Gruvbox |
β See all 13 themes in the gallery
Can't pick? ?theme=random deals you a theme that stays stable all day and
reshuffles every UTC midnight β a different look every morning. Or let the
calendar decide with ?theme=season: frosty nord winters, warm ember
summers, gruvbox autumns β and dracula takes over for halloween week.
(Samples above are snapshots committed to this repo β your embed is generated live.)
Every color is overridable with hex query params (no #):
/u/username?color=ff2d95&bg=141021&text=ffffff&accent=ff2d95&muted=8888aa
| param | controls |
|---|---|
color |
the EKG trace |
bg |
card background (bg=transparent works too) |
text |
primary text |
accent |
state pill highlights |
muted |
secondary text |
border |
card border (border=0 hides it) |
And shape/behavior params:
| param | values | default |
|---|---|---|
size |
card monitor wide compact badge |
card |
w |
rendered width: 200β1600 px, or full to stretch to your README's width |
native |
radius |
corner rounding 0β24 |
12 |
grid |
0 hides the ECG grid |
1 |
glow |
0 disables the glow filter |
1 |
days |
beat window 7β30 |
14 |
label |
custom header text (max 32 chars) | @username |
labels |
rename state pills: radiant:ON FIRE,flatline:RIP (16 chars each) |
medical |
goal |
daily contribution target 1β999: dashed line on the wave + hit-rate |
β |
record |
1 shows chart history: β flatlinesβ revivalsβ‘ best-streak (persists in Redis when UPSTASH_REDIS_REST_URL/TOKEN are set) |
0 |
wall |
1 opts this card into the public Wall of Hearts gallery |
0 |
flip |
1 mirrors the wave β newest beat on the left, for RTL READMEs |
0 |
lang |
status strings in en fa de es ja (pair fa with flip=1) |
en |
blink |
1 blinks the LED dot at your actual heart rate on every alive card |
0 |
hide |
comma list: pill bpm stats status header pacemaker milestone |
β |
anim |
0 renders a fully static card |
1 |
scanlines |
1 adds a CRT scanline overlay (pairs well with theme=phosphor) |
0 |
font |
serif, sans, or any installed family (font=Courier New) |
mono |
gradient |
custom trace gradient, 2β3 hex stops: gradient=8B5CF6,2FD4EE,F26DB8 |
theme |
speed |
animation speed 0.25β3 |
1 |
state |
preview a life state (see above) | live |
wave |
ecg heartbeat, smooth aura wave, bars equalizer |
ecg |
tz |
UTC offset in hours (e.g. 3.5) so late-night commits count to your local day |
0 |
Params compose with a theme: start from ?theme=phosphor and override just bg.
Iterating on params and seeing a stale card? Caching is deliberately hard
(default 24h at the CDN, plus GitHub's camo proxy on top). Append &v=2 β any
value you haven't used before β to mint a fresh URL and skip every cache layer.
Bump it again whenever you want an instant refresh.
Want it edge-to-edge? Profile READMEs are wider than the default card. Use the wide banner and let it stretch:
Any repository has a heartbeat too β commit activity on the default branch:
Same params as user cards. Stats map to the repo: β stars, open PRs/issues, blood type = primary language, beats/yr = commits in the last year.
A whole organization on one monitor β the wave is org-wide push activity from recent public events, β totals its repos' stars, blood type is the org's dominant language:
Two hearts, one monitor β you and a friend (or rival) on the same trace, with a rhythm sync score: how often your active days overlap.
Trace A gets the theme color, trace B the accent. size=card and size=wide.
Your whole team in one ICU β 2 to 6 patients stacked on a single monitor, sorted into triage order (highest bpm first), each trace colored by its owner's life state:
The pill counts survivors (4/5 ALIVE). Perfect for org READMEs β nothing
motivates a team like a coworker visibly flatlining.
Want just a tiny badge instead of a full card? The pulse speaks the shields.io endpoint schema:
Renders as pulse | 180 bpm Β· radiant, colored by life state.
The annual checkup β your whole year as one printed chart: a 365-day EKG strip, total beats, active days, longest streak, longest flatline (dated), busiest day, weekend load:
All themes and layout params apply β theme=paper makes it look like the
real thing. Post yours at the end of December.
The 24-hour tape. Every card so far asks how much you ship β this one asks
when. It buckets your recent public activity by hour of day and hands down
a diagnosis: NOCTURNAL, EARLY BIRD, DAYWALKER, AFTER HOURS, or β for
rhythms with no pattern at all β ARRHYTHMIC:
GitHub timestamps are UTC, so tell the monitor where your body actually is β
tz=3.5, tz=-8 β or the diagnosis lands on the wrong hours. It also finds
your longest quiet stretch and prints it as SUSPECTED SLEEP; if you have
none, it prints not observed, which is its own diagnosis.
Want to post the verdict? https://github-pulse-topaz.vercel.app/s/YOU/holter
unfurls on Twitter/Discord/Slack with your histogram and diagnosis stamped on it.
Watch anyone; get pinged when they flatline β or rise again. Point it at a Discord or Slack webhook:
curl -X POST https://github-pulse-topaz.vercel.app/api/watch \
-H 'Content-Type: application/json' \
-d '{"login":"YOUR_FRIEND","url":"https://discord.com/api/webhooks/β¦"}'A daily sweep compares every watched pulse against yesterday's and fires on
the two transitions that matter: π€ flatlined and β‘ revived. Up to 3
watchers per login; DELETE the same body to unsubscribe; watcher URLs are
never exposed.
Don't want to be watchable at all? Opt out β it removes existing watches on
you and refuses new ones (DELETE the same body to opt back in):
curl -X POST https://github-pulse-topaz.vercel.app/api/watch/block \
-H 'Content-Type: application/json' -d '{"login":"YOUR_USERNAME"}'
``` Self-hosters: set `CRON_SECRET` to lock the sweep, and
`PULSE_WEBHOOK_ALLOW_ANY=1` to allow webhook targets beyond Discord/Slack
(the shared instance restricts hosts so it can't be used to POST at
arbitrary servers).
## Share pages
Cards are SVG, which chat apps and social sites won't unfurl β so every user
also gets a share link with a PNG preview baked in:
https://github-pulse-topaz.vercel.app/s/YOUR_USERNAME
Drop it in Slack, Discord, or a tweet and it unfurls into a vitals snapshot.
There's also a **[Wall of Hearts](https://github-pulse-topaz.vercel.app/wall)** β
a live gallery of recently beating cards. It's strictly opt-in: add `wall=1`
to your own embed and your card joins the wall. Rendering someone else's card
never puts them on it.
And when someone's share page shows a critical or flatlined heart, it grows a
**defibrillator**: charge the paddles, yell CLEAR!, and broadcast a prefilled
code blue to shame them back to shipping. Preview yours before you die:
`/s/YOU?state=flatline`.
## JSON API
Everything the card knows, as data β build your own visualizations, bots, or
status widgets on top of the pulse engine:
```bash
curl https://github-pulse-topaz.vercel.app/api/u/YOUR_USERNAME
curl https://github-pulse-topaz.vercel.app/api/r/OWNER/REPO
Returns the full vitals object: state, bpm, streak, bloodType, beats
(normalized wave), dayCounts (raw), pacemaker, and more. CORS is open
(Access-Control-Allow-Origin: *), responses cache like the cards. days= and
tz= params apply.
The pulse, in your terminal β zero install, zero dependencies:
npx github-pulse-cli torvaldsβ @torvalds Β· RADIANT Β· 90 bpm Β· C+
βββββ
ββββββββ
β 14d
streak 34d Β· 2.4k beats/yr Β· β
190k
Works for repos too (npx github-pulse-cli owner/repo), colors by life state,
respects NO_COLOR. --json dumps the raw vitals, --host points it at your
own deploy. Source lives in packages/cli.
GitHub READMEs support the <picture> element, so your pulse can match the
viewer's theme β one card for dark mode, another for light:
<picture>
<source media="(prefers-color-scheme: dark)"
srcset="https://github-pulse-topaz.vercel.app/u/YOU?theme=aura">
<img alt="GitHub Pulse"
src="https://github-pulse-topaz.vercel.app/u/YOU?theme=paper">
</picture>The site's builder has an adaptive toggle that generates this snippet for you.
Don't want to depend on anyone's server β including ours? Let your own repo's
Actions regenerate the card on a schedule. No token setup at all: the workflow's
built-in GITHUB_TOKEN is used automatically.
Add .github/workflows/pulse.yml to your profile repo (the one named after you):
name: pulse
on:
schedule:
- cron: "23 */6 * * *" # every 6 hours
workflow_dispatch:
permissions:
contents: write
jobs:
pulse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pouyashahrdami/github-pulse@v1
with:
username: YOUR_USERNAME # or repo: owner/repo Β· org: my-org Β· duet: you,friend
# or ward: a,b,c Β· report: username Β· holter: username
theme: aura # optional
size: card # optional
params: "tz=3.5" # optional: any URL param
- name: Commit the card
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add pulse.svg
git diff --cached --quiet || git commit -m "pulse: update"
git pushThen embed it with a relative path:
Honest trade-off: this mode is a snapshot refreshed on your cron, so decay and
β beating now are only as fresh as the last run. The bot commits are authored by
github-actions[bot], so they don't touch your own contribution graph. For
real-time decay, use the URL endpoint instead.
- Fork this repo.
- Import it into Vercel β zero config, the defaults work.
- (Recommended) Add a
GITHUB_TOKENenv var β a classic token with no scopes (create one). With it you get the full 365-day contribution calendar via GraphQL at 5,000 req/h. Without it, the card falls back to recent public events at 60 req/h. - Your card lives at
https://<your-app>.vercel.app/u/<username>.
pnpm install
pnpm devOpen http://localhost:3000, or hit http://localhost:3000/u/<username> directly.
GitHub proxies README images through camo and strips scripts, so all animation is pure CSS inside the SVG β the sweep, the thumping heart, the blinking dot.
Cards refresh once per PULSE_CACHE_SECONDS (default 24 hours), which keeps a
single no-scope token comfortably serving a very large user base: one API call per
unique user per day. Deployments that want livelier decay can set the env var
lower (e.g. 21600 for 6h) β the trade is API calls for freshness.
Private contributions count only if you've enabled Include private contributions on your GitHub profile β same rule as every other stats card.
MIT