Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
1f78991
fix(supabase): keep-alive migration + paused-DB error UX
Jun 21, 2026
a43ab0f
feat(analytics): Plausible + search-console verification meta
Jun 21, 2026
82626be
fix(empty-states): convert Arena/Board dead states into CTAs
Jun 21, 2026
de7a22e
feat(homepage): visible value prop, H1, and feature cards
Jun 21, 2026
d091132
feat(navbar): swap 'Sign in' for 'Save progress' after a finished test
Jun 21, 2026
b203915
feat(seo): per-route dynamic OG images via Next.js ImageResponse
Jun 21, 2026
9105529
feat(seo): Indonesian landing pages + hreflang signals
Jun 21, 2026
ed01205
feat(viral): shareable /r/[slug] result pages + extra share buttons
Jun 21, 2026
6622cff
chore(styling): bump untyped char contrast + add idle caret
Jun 21, 2026
a454ab3
docs: GitHub repo metadata + launch readiness playbook
Jun 21, 2026
2a4d60d
feat(marketing): newsletter signup via hosted-form endpoint
Jun 21, 2026
c68459b
Merge: fix/supabase-keepalive — Supabase auto-pause defense
irham3 Jun 21, 2026
815800c
Merge: feat/analytics-tracking — Plausible + GSC/Bing verification
irham3 Jun 21, 2026
27074ad
Merge: fix/empty-states-conversion — Arena/Board CTA upgrade
irham3 Jun 21, 2026
a44fa90
Merge: feat/homepage-value-prop — visible H1 + value prop + cards
irham3 Jun 21, 2026
f5bf628
Merge: fix/signin-to-save-progress — contextual Sign in → Save progress
irham3 Jun 21, 2026
483f282
Merge: feat/dynamic-og-images — per-route Satori OG cards
irham3 Jun 21, 2026
dc8b00c
Merge: feat/indonesian-seo-hreflang — /id + hreflang signals
irham3 Jun 21, 2026
0011bc8
Merge: feat/social-share-wpm — viral result sharing
irham3 Jun 21, 2026
1d79762
Merge: chore/styling-polish — contrast + caret indicator
irham3 Jun 21, 2026
91d0c18
Merge: docs/launch-readiness — repo metadata + launch playbook
irham3 Jun 21, 2026
61078b5
Merge: feat/newsletter-capture — newsletter signup
Jun 21, 2026
04974dd
fix(typing): import isTyping into scope for idle caret check
Jun 21, 2026
ce6875f
fix(supabase): defensive client init — fail loud at startup, not in c…
Jun 21, 2026
fa1ab7c
feat(ui): full UX/UI redesign — distinctive typography, minimal landing
Jun 21, 2026
400e4e5
Merge branch 'master' into staging
irham3 Aug 10, 2026
7f65e5d
test: fix explicit any in pool contracts
irham3 Aug 10, 2026
ac1d9e7
feat(overdrive): implement competitive multiplayer and state transitions
irham3 Aug 10, 2026
199b5f4
fix(overdrive): resolve duplicate key warning in hud component
irham3 Aug 10, 2026
8e33480
feat(overdrive): add stage progression logic, visual assets, and scor…
irham3 Aug 10, 2026
e14fd1f
feat(overdrive): implement run input handling and update engine types
irham3 Aug 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/repository.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: "Typecade — Free Typing Speed Test & WPM Tracker"
description: "A minimalist typing platform with real-time multiplayer races, a 5-module touch-typing curriculum, and global WPM leaderboards. Built with Next.js 16, Supabase, Tailwind v4."
topics:
- typing-test
- wpm
- typing-speed
- multiplayer
- realtime
- nextjs
- tailwindcss
- supabase
- typescript
- framer-motion
- educational
- productivity
- gamification
- zustand
homepage: "https://typecade.com"
social_preview: "public/opengraph-image.png"
26 changes: 26 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: CI

on:
push:
branches: [master, staging]
pull_request:

permissions:
contents: read

jobs:
validate:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run lint -- --ignore-pattern test.js
- run: npx tsc --noEmit
- run: npm test
- run: npm run build
- run: npm run build:worker
77 changes: 77 additions & 0 deletions ANALYTICS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Analytics & Search Console Setup

Typecade currently ships with **no analytics** — we are flying blind. This
guide walks through wiring up privacy-friendly analytics and submitting the
site to search engines so we can measure and grow.

## Layer 1 — Plausible Analytics (in-app)

Privacy-friendly, <1 KB script, no cookies, no consent banner needed,
GDPR/CCPA compliant out of the box. Free for sites under 10K monthly
pageviews.

1. Sign up at https://plausible.io (or self-host with their docker image).
2. Add a site with domain `typecade.com`.
3. Optional: in `.env.local` set
```
NEXT_PUBLIC_PLAUSIBLE_DOMAIN=typecade.com
```
(or your self-hosted API host via `NEXT_PUBLIC_PLAUSIBLE_API_HOST`).
4. The `<PlausibleAnalytics />` component in `app/layout.tsx` loads the
script automatically. No code change needed beyond step 3.
5. Verify: open the site in an incognito window — the Plausible dashboard
"Realtime" view should show a visitor within ~5 seconds.

## Layer 2 — Google Search Console

Without this, Google will eventually crawl you, but you cannot see
impressions, click-through, indexing errors, or mobile-usability issues.

1. Sign in at https://search.google.com/search-console with the Google
account that owns typecade.com.
2. **Add property → URL prefix** → enter `https://typecade.com`.
3. **Verification → HTML tag** — copy the `content="..."` value (a long
random string).
4. Add it to `.env.local`:
```
NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION=paste-the-content-here
```
5. Deploy. Verify in Search Console.
6. Once verified, **Sitemaps → Add sitemap** → submit `https://typecade.com/sitemap.xml`.
7. **URL Inspection → paste `https://typecade.com`** → **Request indexing**.
Repeat for `/arena`, `/learn`, `/board`, `/about`, and at least 3 learn
lessons.

## Layer 3 — Bing Webmaster Tools

Bing drives ~10–15% of search in many markets and indexes faster than
Google for new domains. Worth 5 minutes.

1. Sign in at https://www.bing.com/webmasters with a Microsoft account.
2. **Add site** → `https://typecade.com`.
3. **Verify → HTML meta tag** — copy the `content="..."` value.
4. Add to `.env.local`:
```
NEXT_PUBLIC_BING_SITE_VERIFICATION=paste-the-content-here
```
5. Deploy, verify, then submit the sitemap and request indexing.

## What to monitor weekly

After 2–3 weeks of data, check:

- **Plausible → Top pages** — which routes get organic traffic
- **Plausible → Top sources** — where visitors come from
- **GSC → Performance → Queries** — which keywords trigger impressions
- **GSC → Coverage → Excluded** — pages Google chose not to index (fix or 410)
- **GSC → Mobile Usability** — fix any flagged issues

If impressions > 0 but clicks ≈ 0 → title/description isn't compelling.
If impressions = 0 for everything → indexing is the bottleneck.

## Optional — upgrade later

When monthly traffic exceeds Plausible's free 10K tier (~$9/mo for 100K),
migrate to self-hosted Plausible or to a paid plan. GA4 is *not*
recommended for an indie product — the consent banner friction costs more
than the data quality difference at our scale.
151 changes: 151 additions & 0 deletions LAUNCH.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Launch playbook

This is a checklist for getting Typecade in front of people. We are
optimising for **qualified traffic** (people who actually try the app),
not vanity metrics. The order matters — do them roughly in sequence.

## 0. Pre-flight (do this BEFORE anything else)

- [ ] Production deploy is up at https://typecade.com
- [ ] All routes return 200 (`/` `/arena` `/learn` `/board` `/about` `/id` `/id/about`)
- [ ] Plausible is tracking pageviews (check dashboard Realtime tab)
- [ ] Google Search Console verified + sitemap submitted + 6 key URLs requested for indexing
- [ ] Bing Webmaster Tools verified + sitemap submitted
- [ ] Supabase keep-alive migration applied (`supabase/README.md`)
- [ ] UptimeRobot monitor live
- [ ] No 404s, no console errors on the homepage
- [ ] Tested in incognito: typing → result → share → click shared link → works end-to-end

## 1. GitHub repo polish (1 hour)

The repo's GitHub presence is one of the first things devs look at. Do all of this in one sitting.

- [ ] Set repository description (one-liner from `.github/repository.yml`)
- [ ] Set website URL to `https://typecade.com`
- [ ] Add topics: `typing-test`, `wpm`, `multiplayer`, `nextjs`, `tailwindcss`, `supabase`, `typescript`, `framer-motion`, `zustand`
- [ ] Pin this repo to your GitHub profile
- [ ] Add 3-5 useful Issues with the `good first issue` label — gives visitors something to click
- [ ] Turn on Discussions
- [ ] Add a project board (optional)

## 2. Product Hunt launch (when ready, time it carefully)

Product Hunt rewards launches that hit the front page. The algorithm
favours engagement in the first 24h.

**Best launch windows:** Tuesday–Thursday, 12:01 AM Pacific. Avoid US
holidays and major tech announcements.

**Pre-launch (1 week before):**
- [ ] Reserve the launch date on Product Hunt ("Coming Soon" page)
- [ ] Post a teaser on Twitter/X with a 15-second screen recording
- [ ] Email 10-20 friendly dev/typing people asking them to commit to upvoting on launch day

**Launch day:**
- [ ] Publish the Product Hunt page at 12:01 AM Pacific
- [ ] Title: "Typecade — Free minimalist typing test with multiplayer races"
- [ ] Tagline (60 chars): "Minimalist typing test with multiplayer races, no signup."
- [ ] First comment (from maker account): brief story, what makes it different, ask for feedback
- [ ] Reply to EVERY comment within the first 4 hours
- [ ] Share the PH link on Twitter, LinkedIn, indiehackers

**Topics:** `Productivity`, `Education`, `Developer Tools`, `Games`

## 3. Hacker News (Show HN)

HN is harder and more skeptical, but the upside is real if your post
gets traction.

- [ ] Write the post from a personal angle: "Show HN: I built a typing test because I was tired of [specific pain]"
- [ ] Include 2-3 screenshots and a screen recording link
- [ ] Be ready to defend technical choices in comments for 6+ hours
- [ ] Do NOT cross-post from PH same day (HN hates that)
- [ ] Best window: Tuesday/Wednesday 8-10 AM Eastern

## 4. Reddit

Authenticity matters more than reach. Spam gets you banned.

**Subreddits worth one targeted post each:**
- r/typing (1.2k members, very engaged)
- r/InternetIsBeautiful (showcase, gets upvotes for craft)
- r/webdev (technical angle — "How I built X")
- r/nextjs (framework-specific)
- r/Indonesia (if you're Indonesian or have Indonesian content — `/id` page is perfect)
- r/productivity (general appeal)

**Rules of thumb:**
- Wait until you have something interesting to show, not "I just launched"
- Don't post to more than 2-3 subreddits in a week
- Reply to every comment

## 5. Indie Hackers

- [ ] Post in the "Milestones" channel when you hit 100 / 1k / 10k tests taken
- [ ] Monthly progress update in "Building a typing app" thread
- [ ] Search for "typing test" threads and answer helpfully

## 6. Directory submissions (one-time)

Each takes 5 minutes, links help SEO and discoverability:

- [ ] alternativeto.net (page for Typecade as alternative to Monkeytype)
- [ ] saashub.com
- [ ] producthunt.com (separate from launch — just a listing)
- [ ] betaList.com (if still in beta)
- [ ] crunchbase.com (basic company profile)

## 7. Twitter / X

Build in public. It compounds.

- [ ] Set up `@typecade` account with the logo and the bio: "Free typing test with multiplayer races. Built by @yourhandle."
- [ ] Post once/week: dev progress, user milestones, typing tips
- [ ] Engage with @monkeytyper, @keybrcom, @typingcom — not promotion, real discussion
- [ ] Every major change → tweet a 15s screen recording

## 8. SEO compounding (long game)

SEO doesn't spike, it compounds. Keep doing these even after launch:

- [ ] Publish 1 blog post per week targeting long-tail keywords:
- "How to type faster" (info intent)
- "Best typing test for programmers" (comparison intent)
- "Touch typing lessons" (learn intent)
- "Tes mengetik online" (Indonesian)
- Use the Learn module structure for content ideas
- [ ] Submit any new routes to GSC for indexing
- [ ] Check Search Console → Performance weekly; iterate on title/description for pages with impressions but low CTR

## 9. Track everything

Set up a weekly 15-minute review:

1. Plausible dashboard: traffic sources, top pages, top sources
2. GSC: clicks, impressions, average position by query
3. Supabase: total tests taken (this is the metric that matters)
4. Product Hunt page (if launched): upvotes, comments

If a single traffic source is >70% of total visits within the first month,
diversify. You don't want to depend on one channel.

## 10. Common pitfalls

- **Don't launch before the empty-state CTAs work.** First-time visitors
will judge Typecade in 5 seconds. A "No active arenas" screen with
zero context loses them.
- **Don't over-promise multiplayer.** If there are 0 active rooms, the
page should invite the visitor to host one, not pretend people are
playing.
- **Don't add features to fix growth.** Add analytics + the basics
first. 80% of growth comes from distribution, not product.
- **Don't hide the typing area.** The product IS the page. SEO +
design + share loops get people there; the typing area gets them
to stay.

---

If you follow this for 90 days consistently, you should be at 1k+
DAUs and a non-zero organic search position for "typing test".

— typecade team
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,17 @@ Supabase-backed screens also read these public variables:

```dotenv
NEXT_PUBLIC_SUPABASE_URL=your-project-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=your-publishable-key
# Server-only; never expose this in a NEXT_PUBLIC_ variable.
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
NEXT_PUBLIC_OVERDRIVE_COMPETITIVE=false
OVERDRIVE_DAILY_SECRET=server-only-daily-secret
```

Apply the checked-in SQL migrations in `supabase/migrations/` before enabling
competitive mode. Keep `NEXT_PUBLIC_OVERDRIVE_COMPETITIVE=false` until the
server submission and replay verification gates are enabled.

Start the development server:

```bash
Expand Down
Loading
Loading