Skip to content

Repository files navigation

HERO FILE

HERO FILE

Your GitHub has a secret identity.

Six Infinity Stones scored from real public signals. One locked identity, its inverse villain, and a card that evolves with every commit.

CI License: MIT Stars TanStack Start Tailwind CSS v4 No API key

The HERO FILE landing page: the headline 'Your code has a secret identity' beside a wall of procedurally generated power emblems


What it does

Drop in a GitHub handle. HERO FILE reads the public profile, scores six stones from named signals, matches the result against a hand-tuned roster of 70 characters, and stages the answer as a dossier.

Every number is traceable. Every piece of art is generated from code — there is not a single character image in this repository.

A generated dossier card: Iron Man at OVR 73, with an arc-reactor emblem, six stone scores, signature powers and an evolution path

Three modes, three stages

Hitting Reveal opens a dedicated page whose entire theme changes with the mode — and every backdrop is live, never a static gradient.

Mode The stage
Single Composed and cinematic. Drifting auras, swaying light shafts, a slow panning grid.
Versus An arena. The two profiles' colors collide at a flaring seam with shockwave rings and rising embers. The winner scales up and glows; the loser is desaturated and dimmed.
Team A super-team. Six stone-colored auroras on independent orbits, sweeping hero beams, and a breathing glow behind every member card.

Results live at a shareable URL — /reveal?u=torvalds,gaearon&mode=versus — so a duel can be linked, refreshed, or posted.

The six stones

Each stone is scored 0–99 from one real, named signal. The formulas are generated from the same declarations that compute the score, so what the app prints can never drift from what it actually ran.

Stone Signal Scored from Curve
🟣 Power Impact Stars on repos you own (forks excluded) log, 99 at ~24k stars
🔵 Space Reach Forks, public orgs, distinct topics log, 99 at ~4.8k forks
🔴 Reality Output Public repos and recent push cadence log, 99 at ~4.8k repos
🟡 Mind Breadth Distinct languages, wiki, docs linear, 99 at 15 langs
🟢 Time Endurance Account age, maintained 3+ year repos linear, 99 at 20 years
🟠 Soul Community Followers, PRs opened on repos you don't own log, 99 at ~11k followers

Every stone follows one shape, and the formula printed in the app is generated from the same declaration that computes it:

round( 99 × ln(1 + Σ curveTerms) / ln(1 + cap)  +  Σ linearTerms )    clamped 0–99

All six are clamped to 99. Hold all six at 70+ and you unlock Infinity-Class — and past that the milestone ladder never ends, because there is always a next target.

Numbers you can check by hand: stoneBreakdown() in src/lib/stones.ts returns the formula with your own values substituted, plus the pre-clamp total.

Why a logarithmic curve?

Because every GitHub signal worth scoring is power-law distributed. The median account has single-digit stars; the top of the field has six figures. Under a square root, 44 stars already scored a full 99 — a weekend project and the Linux kernel were indistinguishable, every well-known account rated 98–99 overall, and the "your card levels up" premise topped out in week one.

A log curve spends its resolution where people actually live. Power reads 10 stars → 23, 100 → 45, 1k → 68, 10k → 90: real movement at every scale, and a ceiling that stays out of reach.

Linear terms are kept for signals with a natural limit — a language learned, a year survived. There's no long tail to compress.

The reasoning behind the original model is preserved in docs/hero-file-spec-2.md.

How your identity is chosen

Three scored dimensions, combined 50/30/20:

  • Domain fit — your language and topic mix against the character's domains, scored as a balanced F-measure. Not cosine: a character's domains are a set of things they are, not a distribution, so plain cosine handed single-domain characters a perfect score and punished breadth as if it were dilution.
  • Stone shape fitwhich of your stones lead relative to your own average, not how high they are. This is what lets a brand-new account match meaningfully: shape survives when magnitude is near zero.
  • Power tier fit — how close the character's scale is to yours. Scored, not filtered. A hard tier filter meant the ~7 tier-2 heroes were the only candidates for most real profiles.

A light fame weight (fame^0.35, about a 1.3× spread end to end) breaks genuine ties toward recognizable characters without overruling a better fit.

Similar people get similar identities by design — that's what makes the match mean anything. A team on one shared stack will cluster; a group spanning different stacks won't.

The bug this replaced

The first version collapsed roughly 90% of profiles onto Iron Man. Four causes compounded:

  1. Substring keyword matching. "data-science" matched the ci keyword and scored as tech; "blockchain" matched ai and scored as cosmic.
  2. Unequal keyword lists. tech had 15 entries against monarch's 6, and since the vector is normalized by its own maximum, tech won by volume.
  3. Absolute stone values in one long vector. A small account's six near-zero stones contributed nothing, so the domain half decided alone.
  4. Fame as a raw multiplier. An A-lister at 1.0 beat a much better-fitting deep cut at 0.45 nearly every time.

Iron Man and Wasp were the only two pure-tech heroes on the roster, so every technical profile landed on one of them — and fame picked Iron Man.

Fixing those four exposed a fifth, which produced the same collapse onto Spider-Man instead. Power tier was a hard filter (|tier − bracket| <= 1), and real profiles cluster at OVR 30–55 — bracket 1–2. That left only the 7 tier-2 heroes as candidates, and Spider-Man is both the most famous of them and tagged [street, tech], the most common profile shape. Making tier a scored dimension rather than a gate opened the whole roster back up.

Art is code

Every character emblem is deterministic procedural SVG, seeded by character id — no network requests, no missing-image states, nothing to license.

The rule: draw the power, never the face. An arc reactor for Iron Man, the spider itself for Spider-Man, Mjolnir for Thor, the Infinity Gauntlet for Thanos (with all six gems in their real stone colors), three adamantium claws for Wolverine. 70 characters, 70 emblems, one file: src/components/Emblem.tsx.

Quick start

git clone https://github.com/DanielHashmi/herofile.git
cd herofile
npm install
npm run dev

Open http://localhost:3000. There is no .env, no API key, and no database — the app talks to the public GitHub REST API straight from the browser.

Note

Unauthenticated GitHub API calls are limited to 60 per hour per IP. If you're iterating hard on the analysis code you will hit it; the app surfaces it as a normal error message.

Scripts

Script What it does
npm run dev Vite dev server on port 3000
npm run build Production build into .output/
npm run preview Serve the production build locally
npm run typecheck tsc --noEmit
npm run lint ESLint (Prettier runs as a rule)
npm run format Write Prettier formatting
npm run assets Regenerate the favicon set from scripts/generate-icons.mjs
npm run check Typecheck + lint + build — what CI runs

How it fits together

src/
├─ routes/
│  ├─ __root.tsx        Document shell, head metadata, providers
│  ├─ index.tsx         Landing page: hero, forge, protocol, arsenal, roster
│  └─ reveal.tsx        The dedicated dossier page + the three live stages
├─ components/
│  ├─ Emblem.tsx        70 procedural power emblems (the art engine)
│  ├─ HeroCard.tsx      The shareable card — GSAP charge-up, PNG export
│  └─ GithubStarButton.tsx
├─ lib/
│  ├─ github.ts         Public GitHub REST → RawStats (paginated)
│  ├─ stones.ts         The scoring model, and the printed formulas it generates
│  ├─ matching.ts       Cosine similarity + fame weighting → identity
│  ├─ characters.ts     The 70-character roster
│  ├─ abilities.ts      Signal-triggered signature powers
│  ├─ analyze.ts        The shared pipeline both routes call
│  ├─ identity.ts       localStorage identity lock
│  └─ theme.tsx         Light/dark context
└─ styles.css           Design system + every keyframe on the reveal stage

The scoring pipeline, end to end:

handle → github.ts ──→ RawStats
                         ├─→ stones.ts  → six scores + OVR + rarity tier
                         └─→ stones.ts  → domain vector
                                            ↓
                         matching.ts (cosine × fame) → locked identity
                                            ↓
                         abilities.ts → signature powers → HeroCard

Once matched, the identity is locked in localStorage and stays put on future visits — it only re-rolls if the profile's domain mix genuinely shifts by more than 40%. Your hero doesn't change because you pushed a different language on a Tuesday.

Tech stack

Twelve runtime dependencies, total. Every animation respects prefers-reduced-motion.

Deployment

Deploys to Vercel with zero configuration — TanStack Start and Nitro are auto-detected. Any Node host works: run npm run build and serve .output/.

Contributing

Contributions are very welcome — especially new characters and their emblems. See CONTRIBUTING.md for the roster walkthrough and the three rules that keep the project coherent:

  1. Every score must be traceable.
  2. Art is code, not assets.
  3. Draw the power, never the face.

License & attribution

MIT.

HERO FILE is an unofficial, non-commercial fan project. Marvel character names are used descriptively to identify the archetypes a profile is matched against. All artwork here is original and generated from code. Not affiliated with, endorsed by, or sponsored by Marvel Entertainment or Disney.

Report a bug · Suggest a character · Discussions

If you had fun with it, a ⭐ helps other people find it.

About

Drop in a GitHub handle. HERO FILE reads the public profile, scores six stones from named signals, matches the result against a hand-tuned roster of 70 characters, and stages the answer as a dossier.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages