Open-source hand-drawn GitHub stats cards for your README.
Doodlebug turns your GitHub activity into hand-drawn SVG cards — every stroke is generated with rough.js and a per-user seed, with real handwriting fonts embedded, so cards render anywhere (including GitHub READMEs) and no two look exactly alike.
A DevsBazaar product — open sourced.
Live site · Docs · Themes · Report a bug
Every README has the same stats card on it. They are competently drawn, identical to each other, and forgettable.
Doodlebug draws yours by hand instead. Nothing is a template: every rectangle, ring, arc and icon is generated stroke by stroke with rough.js from a seed derived from your username, so your card is wobbly in a way nobody else's is. The handwriting fonts are embedded in the SVG rather than linked, which is what lets the result survive GitHub's image proxy.
It is free, it needs no token to get started, and the whole thing — the card engine, the builder, the accounts, the caching — is in this repository. Run it hosted, or self-host the lot.
| Type | What it draws |
|---|---|
stats |
Stars, commits, PRs, issues (+ optional merged/reviews/followers/repos/forks) and a hand-drawn rank ring |
langs |
Top languages as sketched bars, a donut, a pie or a compact strip |
streak |
Total contributions, current streak in a flame ring, longest streak |
activity |
A wobbly contribution heatmap (8–53 weeks) |
graph |
Hand-drawn line chart of daily contributions (7–120 days) |
trophies |
Shields ranked C → SS for stars, commits, PRs, issues, followers, repos, streaks |
repo |
Pin any repository: description, language, stars, forks, topics |
banner |
Wide handwritten header with your name, tagline and doodles |
skills |
Your stack as sketched stickers |
note |
A taped sticky note with handwritten text |
project |
Your own title, description, tags, link and ribbon badge — optionally merged with live repo stats |
achievements |
Hackathon wins, awards, certifications as numbered hand-drawn medals |
link |
A hand-drawn button for portfolio / LinkedIn / email — wrap it in a link |
https://doodlebug.tarinagarwal.in/api/card/<type>?username=<login>&theme=<theme>&…
[](https://github.com/octocat)Themes: paper notebook grid sticky kraft sakura forest ocean candy chalkboard blueprint midnight graphite dracula — or override any colour with bg, ink, accent, accent2, muted (hex without #). Browse them all on the themes page.
theme=auto ships a single card that recolours itself: drawn in the paper palette, swapped to midnight under prefers-color-scheme: dark. Worth knowing that an SVG loaded through <img> follows the reader's browser/OS setting rather than GitHub's own light/dark toggle, so it suits most readers but not every one.
Save a design in the dashboard and it is also served from a fixed address:
https://doodlebug.tarinagarwal.in/c/<saved-card-id>.svg
Paste that into your README once. Restyling the card in the dashboard updates every README using it — you never edit the markdown again. Query params still work and take precedence, so ?theme=midnight previews a variant without saving a second card.
Every parameter is documented on the docs page. The dashboard has a guided builder (sidebar of card types, quick-start presets, live preview, one-click markdown), and every design can be saved and edited later under My cards.
Cards work for any public GitHub user out of the box using GitHub's public API and the public contribution graph. Those endpoints have shared rate limits, so under heavy traffic a card can temporarily show a "rate limited" doodle.
Create a free Doodlebug account, save your GitHub username and (optionally) a personal access token: it is stored AES-256-GCM encrypted, only decrypted in memory to talk to api.github.com, and Doodlebug will use it whenever anyone loads a card for your username. That unlocks the GraphQL API — private-contribution counts, accurate language bytes, review counts and no shared limits.
git clone https://github.com/tarinagarwal/Doodlebug
cd Doodlebug
pnpm install
cp .env.example .env.local # fill in MongoDB, SMTP, secrets
pnpm devpnpm test # card rendering + library unit tests (vitest, no DB or network needed)
pnpm lint # eslint
pnpm typecheck # tsc --noEmit| Variable | Purpose |
|---|---|
MONGODB_URI |
MongoDB connection string (accounts, saved cards) |
JWT_SECRET |
Session signing secret (≥32 chars) |
ENCRYPTION_KEY |
64 hex chars — AES-256-GCM key for stored GitHub tokens |
APP_URL |
Public URL, used in emails and generated snippets |
SMTP_HOST SMTP_PORT SMTP_USER SMTP_PASS MAIL_FROM |
Verification / password-reset email |
GITHUB_TOKEN |
Server-wide fallback token for public fetching. Strongly recommended: a classic PAT with no scopes ticked lifts the rate limit from 60/hr to 5,000/hr and switches every visitor onto the GraphQL path |
UPSTASH_REDIS_REST_URL / UPSTASH_REDIS_REST_TOKEN |
Optional Redis for the GitHub cache and rate-limit buckets. Falls back to MongoDB when unset. Use a regional database in the same region as your deployment, with eviction enabled |
OPENAI_API_KEY |
Optional — only for pnpm gen:assets (illustration generation) |
Deploys to Vercel with zero config.
- Next.js 15 (App Router) + TypeScript + Tailwind v4 — the UI itself is hand-drawn too (wobbly borders, tape, marker highlights).
- rough.js generator running server-side to sketch every rectangle, ring, arc and icon; deterministic per user via seeded randomness.
- Embedded fonts — Patrick Hand, Caveat and Kalam subset to Latin and base64-embedded so SVGs render inside GitHub's image proxy.
- GitHub data — GraphQL when a token is available, REST + the public contribution graph otherwise; results cached in MongoDB with stale-while-revalidate semantics.
- Auth — email + password, SMTP verification, JWT session cookies, bcrypt, per-IP rate limiting. Sessions carry a
tokenVersion, so a password reset or change strands every session issued before it — including one an attacker is holding. - Card hot path — no blocking database work: flood protection is an in-process counter, and render stats are buffered in memory and flushed as one bulk write after the response is sent. The tight limit sits on uncached GitHub lookups, which is where the cost actually is, so a popular README behind GitHub's camo proxy is never throttled for being popular.
- Tests — every card type is rendered against a fixture bundle and checked for well-formed SVG, XML escaping, determinism and degenerate input (empty accounts, zero-width slices, 5,000-character text), plus golden snapshots. CI runs typecheck, lint, tests and a build on every push and PR.
Issues and pull requests are welcome. The card renderers are pure functions of
(bundle, URLSearchParams), so a new card type is one file in src/lib/cards/ plus an entry
in src/lib/cards/meta.ts — and the test suite renders every registered type automatically,
so coverage comes for free.
pnpm test # 93 tests, no database or network needed
pnpm lint
pnpm typecheckPlease report security vulnerabilities privately to tarinagarwal@gmail.com rather than in a public issue.
Questions, ideas or commercial enquiries: tarinagarwal@gmail.com
MIT — use it, fork it, sell it. No licence fee, no attribution required.
Built and open sourced by DevsBazaar