Tool Check
A BuzzFeed-style personality quiz that matches students to one of 8 trade tools based on their answers to 12 questions. Designed as a low-friction entry point into VESL -- no performance pressure, shareable results, and career nudges embedded in outcomes.
Game Flow
Intro → Quiz (12 questions) → Reveal Animation → Result Card
- Intro: Animated tool icons, "How It Works" steps, start button
- Quiz: One question at a time, 4 answers each. Answer order is shuffled per session. Keyboard shortcuts (1-4, A-D) supported.
- Reveal: Slot-machine-style animation cycling through tools before landing on the result
- Result: Tool identity card with personality description, career nudge, sharing options, and optional compatibility comparison (if opened via a friend's share link)
Shared Result Flow
When a user opens a share link (?r={toolId}&ref={encryptedToken}), they see the sharer's result first with a "Take the Quiz" CTA. After completing, their result shows a compatibility card comparing the two tools.
Tools (8 outcomes)
| Tool | Group | Tagline |
|---|---|---|
| Drill | Doer | Efficient. Relentless. Gets it done. |
| Hammer | Doer | Bold. Decisive. Takes action. |
| Level | Thinker | Balanced. Precise. The voice of reason. |
| Tape Measure | Thinker | Detail-oriented. Analytical. Always exact. |
| Safety Goggles | Thinker | Cautious. Protective. Always looking out. |
| Wrench | Connector | Adaptable. Flexible. Problem-solver. |
| Pliers | Connector | Collaborative. Reliable. Gets a grip. |
| Saw | Creator | Creative. Independent. Cuts through the noise. |
Tools are organized into 4 personality groups (doer, thinker, connector, creator) used for compatibility comparisons between friends.
Scoring
Final Score = (Base + Referral Bonuses) x School Rally Multiplier
Base Score: 1000 pts
Awarded on first quiz completion. Retakes do not generate additional base scores.
First Mover Bonus
Added to the base score for the first 3 students at a school to complete:
| Position | Bonus |
|---|---|
| 1st | +200 |
| 2nd | +100 |
| 3rd | +50 |
| 4th+ | +0 |
Referral Bonus: +50 per same-school completion (uncapped)
When a student shares their result link and a same-school student completes the quiz via that link, the sharer earns +50. No artificial cap -- the natural constraint is school size. Referral dedup prevents the same referee from being counted twice.
Share URLs include an encrypted referral token (AES-256-GCM via @/lib/services/referral-token). User IDs are never exposed in URLs.
School Rally Multiplier
Based on the percentage of VESL students at the school who have completed the quiz:
| Participation % | Multiplier |
|---|---|
| 0-9% | 1.0x |
| 10-24% | 1.15x |
| 25-49% | 1.35x |
| 50-74% | 1.75x |
| 75-89% | 2.25x |
| 90-99% | 2.75x |
| 100% | 3.0x |
"VESL student" = user.roleId = 'student' at the same user.schoolId.
The steep curve at the top makes the last 25% of participation disproportionately valuable, incentivizing peer pressure to get every student to participate.
Retroactive updates: When a new completion crosses a multiplier tier threshold, all previous completers at that school receive updated score rows with the new multiplier. The leaderboard uses MAX(score * multiplier), so the better row is picked automatically.
Fairness: Small vs. Large Schools
The multiplier system intentionally advantages small schools:
- A school with 4 students needs 4 completions for 3.0x
- A school with 100 students needs 100 completions for 3.0x (nearly impossible)
- A solo student automatically gets 100% participation (3.0x) for a score of 3600
This compensates for small schools having fewer referral opportunities.
Example Scores
| School Size | Completions | Referrals | Score |
|---|---|---|---|
| 1 student | 1/1 (100%) | 0 | (1000+200) x 3.0 = 3600 |
| 4 students | 4/4 (100%) | 3 | (1000+200+150) x 3.0 = 4050 |
| 25 students | 15/25 (60%) | 10 | (1000+200+500) x 1.75 = 2975 |
| 100 students | 30/100 (30%) | 25 | (1000+200+1250) x 1.35 = 3307 |
Technical Architecture
Key Files
| Area | File | Purpose |
|---|---|---|
| Types | games/tool-check/types.ts | QuizPhase, ToolDefinition, ToolCheckSaveData |
| Config | games/tool-check/config.ts | 8 tool definitions, compatibility matrix, constants |
| Content | games/tool-check/content.ts | 12 quiz questions with answer-to-tool mappings |
| Engine | games/tool-check/store.ts | Zustand store: phases, answers, shuffle map, result calculation |
| Scoring | games/tool-check/scoring.ts | BASE_SCORE, REFERRAL_BONUS, multiplier tiers, first-mover bonuses |
| Actions | games/tool-check/actions.ts | processQuizCompletion server action (orchestrates all scoring) |
| Hook | games/tool-check/hooks/use-game-actions.ts | saveResult, getPreviousResult |
| Sounds | games/tool-check/sounds.ts | Web Audio API: tap and celebration sounds |
Components
| Component | Purpose |
|---|---|
tool-check-client.tsx | Root client component, phase orchestrator |
quiz-intro.tsx | Intro screen with animated tools and start button |
question-card.tsx | Question display with progress bar and answer selection |
result-reveal.tsx | Slot-machine reveal animation + save/score trigger |
result-card.tsx | Result display with sharing, compatibility, career links |
shared-result.tsx | Friend's result view with "Take the Quiz" CTA |
comparison-card.tsx | Compatibility comparison between two tools |
tools-gallery.tsx | Grid of all 8 tools |
Persistence
- Save state (
user_content.data):{ toolResult, answers, completedAt, myReferralToken } - Score (
scoretable): Base + referral bonuses inscorecolumn, school multiplier inmultipliercolumn - Guest mode: Falls back to localStorage via
useGameActionsBase
Share URL Format
/tool-check?r={toolId}&ref={encryptedToken}
r: The sharer's tool result (used for OG image and compatibility comparison)ref: Encrypted referral token (AES-256-GCM, resolves to sharer's userId server-side)
Anti-Gaming
- Self-referral: Blocked by checking
referrerId !== currentUserId - Cross-school referral: Blocked by verifying both users share the same
schoolId - Duplicate referral: Blocked by querying
score.datafor existing referral pairs - Fake students: Prevented by requiring
roleId = 'student'(admin-verified) - Token tampering: AES-256-GCM authentication tag causes tampered tokens to fail silently