Easy-to-manage touch screens
Free, open-source touch screens. Guided USB setup, a drag-and-drop editor and local control. Made for Home Assistant.
Birthday Side Quests: find birthday freebies near you and online. Type your city and pick your birthday month. Nothing is stored on our servers.
LifestyleTypeScript · CSSGitHub @raksharakyanOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Cute, privacy-first finder for birthday freebies & side quests near you 🎂
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Free birthday treats near you, turned into tiny adventures. Type in your city and pick your birthday month. You get a map and a list of birthday side quests: cafés, dessert shops, beauty brands, fashion stores and experiences near you that give birthday freebies or discounts, each with exactly what you get and how to claim it. Online-only deals have their own tab, covering every country.Read the full README ↗
Free birthday treats near you, turned into tiny adventures.
Live: https://raksharakyan.github.io/birthday-side-quests/
Type in your city and pick your birthday month. You get a map and a list of birthday side quests: cafés, dessert shops, beauty brands, fashion stores and experiences near you that give birthday freebies or discounts, each with exactly what you get and how to claim it. Online-only deals have their own tab, covering every country.
| Mobile | Claimed |
|---|---|
prefers-reduced-motion.We don't store anything on our servers. Your search stays in this browser tab and clears when you close it (one small sessionStorage record, removable with Clear search). There are no accounts, cookies, analytics, localStorage or IndexedDB, and no geolocation prompt. See PRIVACY.md.
Offer facts come only from public/offers.json. Every entry was researched by reading the brand's official rewards or terms page (research notes), and each one records its sourceUrl and lastVerified date. If we couldn't confirm an offer from an official page, it shows "Check with store". Entries older than 6 months show a "May be outdated" badge. A weekly GitHub Action checks every sourceUrl and opens an issue when a link breaks. AI is never used as a source of offer facts.
| Piece | What it does | Why |
|---|---|---|
| Vite | Bundles the app into a few small static files | Fast builds, output any free host can serve |
| TypeScript (vanilla, no framework) | All app logic | Tiny bundle, fewer dependencies, easier to audit for XSS |
| Leaflet | The interactive map | Free, no API key, works with OpenStreetMap |
| Fontsource (Bricolage Grotesque, Plus Jakarta Sans) | Self-hosted fonts | No third-party font requests, so no tracking |
| Plain CSS with design tokens | The plum "Soft Premium" look | One source of truth in src/styles/tokens.css, see DESIGN.md |
The app has only three runtime dependencies: Leaflet and two font packages.
| Service | Used for |
|---|---|
| Photon by komoot | City suggestions as you type |
| Nominatim | Turning a typed city into a location (max 1 request per second) |
| Overpass API | Finding nearby branches of brands with birthday offers |
| OpenStreetMap tiles | The map images |
| Google Maps links | "Get directions" is a plain URL, so it needs no key |
public/offers.json is a hand-researched list of 102 offers across 11 countries. It uses no database. Every entry comes from the brand's official page and records:
sourceUrl, the official page it came from;lastVerified, the date it was last checked;AI is never used as a source of offer facts.
| Piece | Role |
|---|---|
| GitHub Pages | Hosts the live site for free |
| GitHub Actions | On every push: audit, typecheck, unit and e2e tests, Lighthouse, then deploy. A weekly job checks that every offer link still works. |
| Dependabot, secret scanning, push protection | Supply-chain and secret safety. Every Action is pinned to a commit SHA. |
| Vitest | About 890 unit tests: data rules, filters, sorting, security checks |
| Playwright | About 130 browser tests on desktop and Pixel 7, with all network calls mocked. Any XSS, CSP violation or unexpected request fails the test. |
| axe-core | Accessibility checks, with 0 violations required |
| Lighthouse CI | Performance ≥ 0.9, Accessibility and Best Practices ≥ 0.95 (currently 0.99 / 1.0 / 1.0) |
| Cloudflare Worker + Tavily (optional, not deployed yet) | Live "Found online" search. It only receives month and country. |
sessionStorage record keeps your search across a refresh and clears when the tab closes.Details are in SECURITY.md (STRIDE threat model) and PRIVACY.md.
This project was built with Claude Code as a lead orchestrator coordinating specialist AI subagents. Each subagent is a separate Claude instance with its own brief and the same tools: files, terminal, web and a real browser.
| Agent | Responsibility |
|---|---|
| Orchestrator | Plans the work, writes the briefs, reviews results, spot-checks facts, resolves conflicts, opens PRs, merges, and checks the live site |
| Full-Stack Developer | Builds features: search, map, filters, sorting, session restore, the Worker, CI/CD |
| UI/UX Designer | Design prototypes and the plum redesign, contrast, accessibility and motion |
| Offer Researchers (India and global, in parallel) | Read official brand pages and write offer data with exact claim steps |
| Security Engineer | Reviews every PR for XSS, privacy leaks and supply-chain risk, and fixes what it finds |
| QA Tester | Writes unit and browser tests, hunts bugs, runs live smoke tests, and re-checks offer classifications |
Workflow for every feature
main, which deploys it. The orchestrator then tests the live site.Shared memory between agents
docs/PLAN.md: tasks and owners.docs/DECISIONS.md: numbered decisions with reasons.docs/HANDOFFS.md: what each agent finished, plus sign-offs.CLAUDE.md and DESIGN.md: the rules and the design system for future sessions.When agents disagree: Security wins on safety, UI/UX wins on visuals, and the orchestrator records the decision. That's how bugs like a toast blocking taps on mobile, a regex performance risk, and offers wrongly labelled "Free" were caught before release.
You need Node 22 or later.
git clone https://github.com/raksharakyan/birthday-side-quests.git
cd birthday-side-quests
npm ci
npm run dev # http://localhost:5173/birthday-side-quests/
| Command | What it does |
|---|---|
npm run build | Typechecks the app, configs and Worker, then builds dist/ |
npm test | Unit tests (Vitest), including the Worker |
npx playwright install chromium && npm run test:e2e | E2E on desktop and mobile, with all network calls mocked |
npm run lhci | Lighthouse CI (Performance ≥ 90, Accessibility ≥ 95, Best Practices ≥ 95) |
npm run audit | npm audit --audit-level=high |
Copy .env.example to .env.local to set VITE_BASE or VITE_WORKER_URL.
main runs ci-deploy.yml: audit → typecheck → unit tests → build → Playwright → Lighthouse → deploy to GitHub Pages. In repo settings, Pages must be set to Source: GitHub Actions.wrangler login, then wrangler secret put TAVILY_API_KEY, then wrangler deploy. Then set the repo variable VITE_WORKER_URL to the Worker's https URL and re-run the workflow. Until you do, the tab stays hidden.public/_headers adds the full security headers that GitHub Pages can't send.public/offers.json:
{
"id": "brand-in",
"brand": "Brand",
"category": "cafe",
"offer": "Free birthday drink for app members",
"howToClaim": "Join the app and add your birthday at least 7 days before",
"countries": ["IN"],
"channel": "in-store",
"claimWindow": "day",
"sourceUrl": "https://brand.example/rewards",
"lastVerified": "2026-10-02",
"verified": true,
"rewardType": "free",
"needsPastSpend": false,
"osm": { "wikidata": "Q123", "nameRegex": "brand" }
}
category: cafe | dessert | restaurant | beauty | fashion | retail | onlinechannel: in-store | online | bothclaimWindow: day | week | month | variescountries: ISO-2 codes, or ["*"]rewardType (required): free for a free item, gift, treat or entry with nothing to buy beyond joining a free programme; discount for money or percent off, a cash-value voucher, buy one get one, bonus points, or a free item that needs a purchase.needsPastSpend (required): true when you only qualify after spending before (a tier reached by spend or points, a purchase in a past window, a paid membership, a yearly spend); false when anyone can join for free and get it. When unsure, pick discount and true. See docs/OFFER_CLASSIFICATION.md.osm is optional. Use wikidata for the brand's brand:wikidata tag; nameRegex allows only letters, digits, spaces and '’&.-|()?^$.venues is optional and is for single-location destinations (theme parks, water parks): 1 to 20 { "name", "lat", "lng", "exact"? }. The offer shows in Nearby only when a venue is within 150 km of the searched city. Use "exact": false for approximate coordinates (no map pin, directions by name). Use venues instead of osm and set channel to in-store.CLAUDE.md · DESIGN.md · SECURITY.md · PRIVACY.md · CONTRIBUTING.md · docs/PLAN.md · docs/DECISIONS.md · docs/HANDOFFS.md
Map data © OpenStreetMap contributors. Geocoding by Nominatim, branch search by the Overpass API. Please be kind to these free services.
MIT © 2026 raksharakyan
npm test. The schema test rejects non-https URLs, unknown categories, a missing rewardType or needsPastSpend, overlong text and hidden Unicode tricks.