Skip to content

hett-patell/ShardPet

Snorlax sleepingPikachuPsyduckGengarMewtwo

ShardPet

Release License: MIT Chrome Web Store Stars

ShardPass

A team of tiny, judgy Pokémon who live in your browser, watch you scroll, and stage a fullscreen intervention when you've been on Reddit for forty-five minutes.


You ever wish your browser had a small friend? You ever wish that small friend had Strong Opinions about your YouTube rabbit holes? Congratulations — you wished a thing into existence and now it's a Chromium extension.

ShardPet drops 1–5 animated Gen 5 Pokémon onto every web page you visit. They wander. They hop. They occasionally stop to think about their life. You can click one to swap it for another. They are pixelated, they are emotionally unavailable, and they will not stop you from opening Twitter.

But the other thing they do — that's where it gets unhinged. Add a productivity threshold. Add an allowlist of sites that "count as work" (a generous fiction we are all in on). The moment you spend too long anywhere else, two dozen of your cached Pokémon materialise across your screen at once, in a glorious pixel-art fullscreen "GET BACK TO WORK!" overlay. They are everywhere. They are watching. They will not leave until you click "Dismiss" and admit you have a problem.

It is also, somehow, designed to use less CPU than your desktop wallpaper.


Screenshots

Pets, vibing, doing their little walk:

ShardPet wandering Pokémon along the bottom of a webpage

Pets, no longer vibing, staging an intervention:

Get back to work overlay with all cached Pokémon scattered across the screen

What this thing actually does

Slowpoke

  • 1–5 wandering Pokémon that walk, idle, and occasionally hop. Click one to reroll it. They have free will. Mostly.
  • Highly customisable: count, size (24–128 px — yes you can make them huge), bottom offset, speed (slow / normal / fast / "Slowpoke is sprinting"), per-host blacklist for sites where you'd rather not be perceived.
  • The Productivity Nag™: per-hostname cumulative timer (1–120 min, default 15 min), allowlist for sites that don't count, and a 5-minute cooldown after each dismiss because we're not monsters.
  • Live timer pill (optional) — a tiny top-right HUD that judges you in real time. reddit.com • 4m37s / 5m00s is a deeply uncomfortable string.
  • Toolbar popup for all settings. No cursed options page. Click the icon, fiddle, leave.
  • Reduced-motion aware — auto-detects prefers-reduced-motion so it doesn't enrage your vestibular system.
  • Shadow-DOM isolated — page CSS can't touch our Pokémon, our Pokémon can't touch page CSS. Diplomatic immunity.
  • All 649 Gen 1–5 Pokémon included by default — every species the PokéAPI animated BW sprite set covers, fetched once and cached locally forever (or until you hit Resync).

Why your laptop won't catch fire

ShardPet is engineered to be invisible on a CPU profile. Genuinely.

  • One requestAnimationFrame loop, frame-skipped to ~30 FPS. That's it. There is no other loop.
  • Movement is transform: translate3d only — pure GPU compositor, zero layout, zero paint. Your browser doesn't even notice.
  • Animation fully suspends when the tab is hidden. Background tabs cost zero. Less than zero, even, in spirit.
  • The work timer also pauses on hidden tabs. We are not psychopaths.
  • chrome.storage.local writes are throttled to once every ~30 seconds (with forced flushes when something actually matters), so 17 open tabs don't all fight to write the same number.
  • The work-timer interval doesn't even start if you've turned the nag off. We respect your toggles.
  • All 649 Gen 1–5 sprites fetched once at install with bounded concurrency (~16 in flight) so we don't hammer GitHub's CDN. Total cache lands around 5–9 MB on disk; the extension declares unlimitedStorage to keep it comfortably under quota. Hand-on-heart, the extension code itself is still smaller than the GIF you sent in chat earlier.
  • DOM only re-spawns when visual settings actually change. Nudging the offset slider patches CSS variables in place, like a civilised codebase.

Ditto

Install (developer mode)

Mozilla Add-ons / Chrome Web Store listing TBD. For now it's BYO-build.

Option A — download the release:

  1. Grab the latest shardpet-vX.Y.Z.zip from Releases and unzip it. (v2.0.0 is the current full roster; v1.0.0 is the original 24-Pokémon minimal build if you want a smaller footprint.)
  2. Open chrome://extensions (or whatever your Chromium flavour calls it — Helium, Brave, Edge, Arc, the new one your friend told you about last week).
  3. Flip on Developer mode (top right corner, you've got this).
  4. Click Load unpacked → pick the unzipped folder.
  5. Pin the extension. Watch a Pikachu appear. Cry a little.

Option B — build from source like a normal person:

git clone https://github.com/hett-patell/ShardPet.git
cd ShardPet
npm install
npm run build
# now load `dist/` via "Load unpacked" as above

On first install the extension fetches a curated set of Gen 5 Black/White animated sprites from PokéAPI's public sprite CDN. After that, it could survive on a desert island (with internet for, uh, browsing).

Configure

Click the ShardPet toolbar icon. A 340px popup falls out. Two sections.

Pokémon controls

  • Enable / disable the whole show
  • Count (1–5), size (24–128 px), bottom offset
  • Speed: slow / normal / fast
  • Reduced motion: auto (follow OS) / off / on
  • Blacklist — hostnames where Pokémon won't appear (one per line; subdomains match). Useful for mail.example.com, banking sites, your therapist's intake form.

Productivity nag

  • Enable / disable the "Get back to work!" overlay
  • Trigger threshold: 1–120 minutes of cumulative time on a non-allowlisted hostname (default 15 min)
  • Allowlist — sites you're allowed to use without being yelled at (one per line; subdomains match). Standard inclusions: github.com, linear.app, notion.so, your company's Jira, the docs page you're definitely going to read this time.
  • Show live timer pill — top-right HUD. Recommended for the first day so you can debug your own brain.
  • Reset timers — nukes per-hostname accumulators and any active cooldown. For when you've earned a clean slate or want to test the overlay without sitting through five minutes of suspense.
  • Resync sprites — re-fetches the cache from PokéAPI. Run this if you ever feel your pets are getting stale.

When the overlay fires: title in pixel-art font, two dozen Pokémon (sampled fresh from the cache each time) scattered across the screen via grid-jitter placement — each gets its own distinct zone, no clumping, no overlap. Dismiss with the button, click outside the title card, or hit Esc. That starts a 5-minute cooldown and zeroes the dismissed hostname's counter, so the next nag is also a full threshold away. Mercy.

Alakazam

Develop

npm install         # install deps
npm run dev         # Vite dev (popup HMR)
npm run build       # production build → dist/
npm test            # unit tests (Vitest, all green)
npm run typecheck   # strict TS, no `any`s, no excuses

Code layout

src/
  background.ts       # MV3 service worker: fetch + cache sprites once
  content.ts          # injected into every page; mounts lane, timer, overlay
  overlay.ts          # "Get back to work!" overlay (shadow-DOM, scattered)
  overlay.css         # pixel-art title font, scatter animations
  popup/
    index.html        # 340px Game Boy-styled settings panel
    popup.ts          # bound form ↔ chrome.storage + live preview lane
  storage.ts          # typed chrome.storage.local accessors + defaults
  styles.css          # lane + sprite styles (loaded as ?raw into shadow)
  sprite-fetcher.ts   # PokéAPI fetch + base64 (no FileReader; MV3-safe)
  pokemon-list.ts     # curated list of IDs + sprite URL helper
  wander.ts           # pure walk/idle/hop state machine (unit-tested)
  work-timer.ts       # pure cumulative timer + cooldown state (unit-tested)

icons/                # 16/32/48/128 PNGs for the toolbar + Chrome menus
tests/                # Vitest specs for the four pure modules

The pure modules (wander.ts, work-timer.ts, storage.ts, sprite-fetcher.ts) have zero DOM dependencies and are tested independently. Everything stateful and DOM-y in content.ts is a thin shell over them. Refactor with confidence.

FAQ

Q: Why does it ask permission for a pokeapi/sprites URL? A: That's the GitHub raw URL where the animated GIFs live. The extension hits it exactly once on install — and again only if you click Resync sprites. After that it's offline forever.

Q: Does it slow down web pages? A: On a typical laptop the wander loop costs well under 1% CPU. The work timer wakes once every 5 seconds while the tab is visible. Hidden tabs do exactly zero work. Memory: a few hundred KB for the cached sprite data URLs plus up to five <img> elements. Your browser eats more for breakfast.

Q: Will it leak its styles into the pages I visit? A: No. Both the lane and the overlay live in closed shadow roots, and the host elements use all: initial. Your CSS-in-JS library can rest easy.

Q: My Pokémon is stuck. A: Click them. They reroll. If they're all stuck (i.e. the loop is dead), open a new tab — content scripts are per-page.

Q: It triggered immediately after I dismissed it. Bug? A: Fixed in v1.0.0. applyDismiss now resets the dismissed hostname's accumulator so the next nag also requires a fresh threshold's worth of time. You can resume your descent into Twitter responsibly.

Q: What's different in v2? A: Three things, mostly: (1) all 649 Gen 1–5 Pokémon (v1 shipped 24 starters); (2) sprite cache now refreshes every 90 days so you pick up upstream fixes; (3) several quiet correctness/perf fixes — the storage-event suppression race is gone, allowlist hits no longer leave dead keys behind, the per-hostname history is capped at 100 entries to stop unbounded growth, the latin1 TextDecoder replaced a chunked base64 hot-path, and the default focus threshold is now 15 min instead of an aggressive 5. v1 is preserved as the "minimal" build if you want the lighter cache.

Q: What's new in v2.1? A: A bit of polish and a bit of plumbing. The popup got a full Game Boy-themed pixel-art rewrite — chunky borders, segmented controls instead of dropdowns, a real live preview lane so you can see your settings before saving, and a proper bundled toolbar icon (no more generic puzzle piece). Pet count now goes up to 5 instead of 3. The "Get back to work" overlay caps at 24 sprites instead of dumping all 649 on the page — same vibe, far less melted GPU. Plus several lifecycle fixes: the overlay can no longer become undismissable if you disable the extension mid-nag, hostnames are now case-insensitive (so GitHub.com in your allowlist actually matches github.com), the popup threshold slider goes to 120 like the docs always claimed, and pages restored from bfcache no longer leak a stale rAF loop into detached DOM nodes.

Q: Can I add my own Pokémon list? A: Yes — edit src/pokemon-list.ts, rebuild, and click Resync sprites. Mythical / legendary Pokémon are excellent candidates for "shame me extra hard."

Q: Does this work in Firefox? A: Not currently — it's a Manifest V3 Chromium extension. Firefox MV3 support is technically there but the manifest fields differ slightly. PRs welcome from someone braver than me.

Q: Will Nintendo sue me? A: They're going to sue me, not you. You're fine.

Contributing

PRs welcome. Issues welcomer. Bugs are inevitable; the absence of tests is unforgivable. If you add a feature, add a test for the pure logic. If you change UI, please rebuild and confirm nothing flies into low-earth orbit.

Licensing

Source code: MIT — see LICENSE. Do whatever you want, just don't blame me when your Snorlax gets sentient.

Pokémon names and sprite imagery are © Nintendo / Game Freak / Creatures Inc. Sprites are not redistributed in this repository — they are fetched at runtime from PokéAPI's public sprite CDN. This is an unofficial, non-commercial fan project, not affiliated with or endorsed by Nintendo, Game Freak, Creatures Inc., or The Pokémon Company. Please don't sue us, we just wanted a small friend in our browser.


The Shard ecosystem

Repo What it does
ShardLure SSH honeypot + threat-intel dashboard
ShardC2 Red-team C2 framework in Go
ShardFlow Layer-2 LAN workbench (ARP, drop, throttle)
ShardShell PHP post-exploitation shell
ShardPass Minimal TOTP authenticator (Chrome MV3)
ShardPet Pixel-Pokémon browser extension

Mew

Built with one requestAnimationFrame, three regrets, and six hundred and forty-nine Pokémon.