แบบทดสอบหาเฉดสีการเมืองไทย - มาเป็นสีอะไรกันแน่ในสมการการเมืองไทยยุคนี้?
A fun, interactive quiz to discover your political shade in Thailand's political landscape. Built with vanilla JavaScript and deployed on Cloudflare Pages.
| Shade | Thai Name | Description |
|---|---|---|
| 🥊 | แดงน้ำหมาก (Nam Mak) | Traditionalist Red - Fighter who values loyalty |
| 🍼 | แดงนมผง (Nom Phong) | New Gen Red - Analytical bridge-builder |
| 🍷 | แดงมาดาม (Madam) | Sophisticated Red - Progressive pragmatist |
| ✨ | แดงดารา (Dara) | Celebrity Red - Pop culture progressive |
| 🍊👓 | ส้มวิชาการ (Academic Orange) | Academic - Evidence-based progressive |
| 🧡🔥 | ส้มแบก (Fandom Orange) | Fandom - Passionate movement supporter |
| 🎭 | ส้มแอบเนียน (Orange) | Closeted Orange - Silent supporter with sympathies |
| 🎗️ | เหลืองคลาสสิก (Classic Yellow) | Classic - Traditional conservative |
| 👑 | เหลืองสถาบัน (Royalist) | Royalist - Institution protector |
| 🔵 | น้ำเงิน (Blue) | Blue - Establishment moderate |
| 🌩️ | ฟ้า (Sky Blue) | Sky Blue - Progressive reformer |
| 🪖 | เขียว (Green) | Green - Military-affiliated |
| 🏳️ | ขาว (Silent White) | White - Silent majority |
- 🎨 Category-Specific Emoji Rain - Each result triggers unique celebration animations (80 emojis)
- 🔊 8-bit Sound System - Procedural sound effects via Web Audio API (Beep, Select, Win)
- 📊 Global Statistics - Real-time rankings persisted in Cloudflare D1 database
- ⬅️ Back Navigation - Review and change answers at any time
- 🌐 Bilingual Support - Thai and English interface
- 📱 Responsive Design - Works seamlessly on mobile and desktop
*Daily players one day after release*
- ⚡ Tailwind CSS v3 - Properly bundled and minified (no CDN dependencies)
- 🗄️ Cloudflare D1 - Serverless SQLite database for global stats
- 🚀 Pages Functions - Serverless API endpoints
- 🔒 Security Headers - CSP, XSS protection, frame denial
- 📦 Cache-Busting - Versioned assets for fresh deployments
This quiz is designed to map respondents to one of 13 political shades in Thailand's complex political landscape. Unlike traditional left-right spectrums, Thai politics involves multiple dimensions:
- Historical allegiance (Yellow vs Red movements)
- Generational divide (Traditional vs New Gen)
- Institutional loyalty (Royalist vs Reformist)
- Approach to change (Revolutionary vs Evolutionary vs Status Quo)
- Cultural expression (Academic vs Pop Culture vs Mainstream)
Each shade represents a unique combination of these factors, creating a nuanced political identity map.
Rather than forcing users into a single axis, we use multi-dimensional scoring:
Each answer contributes to multiple shades simultaneously
├── Primary shade: +3 points (strong alignment)
├── Secondary shade: +2 points (moderate alignment)
└── Tertiary shade: +1 point (partial alignment)
This allows for overlap detection and more accurate shade matching.
To ensure fair comparison across all shades, we use score normalization:
normalizedScore = rawScore × (avgMaxScore / maxPossibleScore)
Where:
- rawScore = Total points accumulated for a shade
- avgMaxScore = Average maximum possible score across all shades (~19)
- maxPossibleScore = Maximum achievable for that specific shade
Why normalization matters:
- Different shades have different answer opportunities
- Without normalization, shades with more answer options would dominate
- Normalized scores represent "how well you match" on a comparable scale
- All shades can now achieve 100% with perfect answers
Each shade has been calibrated for fair scoring:
| Shade | Max Score | Balance Status |
|---|---|---|
| NAM_MAK | 21 | ✅ Balanced |
| NOM_PHONG | 18 | ✅ Balanced |
| MADAM | 20 | ✅ Balanced |
| DARA | 20 | ✅ Balanced (v3.17.0) |
| ORANGE_ACADEMIC | 19 | ✅ Balanced |
| ORANGE_FAN | 19 | ✅ Balanced |
| ORANGE | 16 | ✅ Balanced (v3.17.0) |
| YELLOW_CLASSIC | 19 | ✅ Balanced |
| YELLOW_ROYALIST | 21 | ✅ Balanced |
| BLUE | 20 | ✅ Balanced |
| SKY_BLUE | 19 | ✅ Balanced |
| GREEN | 20 | ✅ Balanced |
| WHITE | 18 | ✅ Balanced |
Average max score: ~19 points
-
Scenario-Based Questions: Each question presents a realistic political scenario rather than direct ideological questions, reducing social desirability bias.
-
Balanced Answer Distribution: Each question has 5-9 answer options covering the full spectrum of political views.
-
Randomized Order: Fisher-Yates shuffle ensures answers appear in random order to prevent position bias.
-
Topic Diversity: 7 questions cover different dimensions:
- Q1: Historical allegiance
- Q2: Core values & principles
- Q3: Leadership preference
- Q4: Approach to conflict
- Q5: Reform attitudes
- Q6: Information sources
- Q7: Personal expression
// Calculate raw scores
for each answer:
for each shade in answer.score:
scores[shade] += answer.score[shade]
// Normalize for fair comparison
avgMax = average(maxPossibleScore for all shades)
for each shade:
normalizedScore = score[shade] * (avgMax / maxPossible[shade])
percentage = (normalizedScore / avgMax) * 100
// Determine result
result = shade with highest normalizedScore- Primary Result: Shade with highest normalized percentage
- Runner-ups: 2nd and 3rd place shades with their percentages
- Tie-breaking: Rare edge cases resolved by secondary score factors
┌─────────────────────────────────────────────────────────┐
│ Quiz Flow │
├─────────────────────────────────────────────────────────┤
│ [Start] → [Q1] → [Q2] → ... → [Q7] → [Calculate] │
│ ↓ │
│ ┌───────────────┐ │
│ │ Normalization │ │
│ └───────────────┘ │
│ ↓ │
│ ┌─────────────────┐ │
│ │ Result + Stats │ │
│ └─────────────────┘ │
│ ↓ │
│ ┌─────────────────┐ │
│ │ Save to D1 DB │ │
│ └─────────────────┘ │
└─────────────────────────────────────────────────────────┘
https://findyourshade.autobahn.bot/
- Node.js 18+
- npm or yarn
# Clone the repository
git clone https://github.com/bejranonda/FindYourShade.git
cd FindYourShade
# Install dependencies
npm install
# Build CSS
npm run build:css
# Start local server
npx serve .| Command | Description |
|---|---|
npm run build:css |
Build minified Tailwind CSS |
npm run watch:css |
Watch for CSS changes during development |
The site automatically deploys from the master branch.
Build Settings:
- Build command:
npm run build:css - Build output directory:
/ - Node.js version:
18or newer
wrangler pages deploy . --project-name=findyourshadeFor global statistics to work, set up Cloudflare D1:
wrangler d1 create DB --name=findyourshade-dbwrangler d1 execute DB --remote --file=schema.sqlThis creates two tables:
stats- Stores final quiz resultsanswers- Stores individual answer choices for analytics
The database is pre-configured in wrangler.toml:
[[d1_databases]]
binding = "DB"
database_name = "DB"
database_id = "7e5bd3e8-425c-4447-b340-60cbc14c57f6"wrangler pages deploy . --project-name=findyourshadeSave a quiz result to the database.
Request:
{
"id": "NAM_MAK"
}Valid Categories: NAM_MAK, NOM_PHONG, MADAM, DARA, ORANGE, BLUE, SKY_BLUE, ORANGE_ACADEMIC, ORANGE_FAN, YELLOW_CLASSIC, YELLOW_ROYALIST, GREEN, WHITE
Response:
{
"success": true
}Retrieve global statistics.
Response:
{
"NAM_MAK": 1234,
"NOM_PHONG": 567,
"BLUE": 890
}Caching: Response is cached for 60 seconds.
Save an individual answer choice to the database for detailed analytics.
Request:
{
"questionId": 0,
"choiceIndex": 3,
"sessionId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
}Parameters:
questionId(integer): Question number (0-7)choiceIndex(integer): Selected choice index (0-9)sessionId(string): UUID v4 identifying the quiz session
Response:
{
"success": true
}Retrieve answer statistics for analytics.
Get all question stats:
GET /api/answers
Response:
{
"0": { "0": 150, "1": 89, "2": 45 },
"1": { "0": 120, "1": 200, "3": 50 }
}Get specific question stats:
GET /api/answers?questionId=0
Response:
{
"questionId": 0,
"choices": {
"0": 150,
"1": 89,
"2": 45
}
}Caching: Response is cached for 60 seconds.
| Technology | Purpose |
|---|---|
| HTML5 | Core structure and semantic markup |
| Vanilla JavaScript | Quiz logic, state management, sound engine |
| Tailwind CSS v3 | Utility-first CSS framework |
| Cloudflare D1 | Serverless SQLite database |
| Cloudflare Pages Functions | Serverless API endpoints |
| Web Audio API | Procedural 8-bit sound effects |
| CSS Animations | Emoji rain effects and transitions |
| Google Fonts | Kanit (Thai) & Press Start 2P (8-bit font) |
FindYourShade/
├── index.html # Main HTML (bilingual Thai/English)
├── css/
│ ├── input.css # Tailwind CSS entry point
│ ├── tailwind.css # Built Tailwind CSS (generated)
│ └── style.css # Custom styles and animations
├── js/
│ └── app.js # Main application logic
├── functions/
│ └── api/
│ ├── save.js # POST /api/save - Save result to D1
│ ├── stats.js # GET /api/stats - Get stats from D1
│ ├── answer.js # POST /api/answer - Save individual answer
│ ├── answers.js # GET /api/answers - Get answer statistics
│ └── daily-stats.js # GET /api/daily-stats - Daily stats + anomaly detection
├── schema.sql # D1 database schema
├── package.json # Dependencies and build scripts
├── tailwind.config.js # Tailwind configuration
├── wrangler.toml # Cloudflare configuration
├── _headers # Security and caching headers
├── _redirects # URL redirection rules
└── README.md # This file
- Open the website
- Click "เริ่มวิเคราะห์ตัวตน" (Start Analysis)
- Answer 7 questions about your political views
- Discover your political shade!
- View global statistics or share your result
- New: Added X/Twitter link to header next to Facebook
- Major Release: Complete transparency & citizen verification system
- New: Daily trend line chart with interactive legend
- New: Tooltip shows all 13 political shades on hover
- New: "วันนี้" (Today) counter instead of minimum
- New: Social media share buttons (LINE, Facebook, Twitter/X)
- New: Web Share API with image support for mobile
- New:
/api/daily-statsendpoint with 30-day rolling data - New: Anomaly detection using Z-score algorithm
- UX: Click legend to toggle chart lines on/off
- UX: Neutral language for anomalies ("สูงกว่าปกติ")
- Dependency: Added Chart.js for chart rendering
- New: Daily trend chart showing political shades obtained each day
- New:
/api/daily-statsendpoint with 30-day rolling data - New: Anomaly detection using Z-score algorithm (>2 std dev)
- New: Summary statistics (avg/day, max, min) on stats page
- UX: Neutral language for anomalies ("สูงกว่าปกติ" not "น่าสงสัย")
- UX: Transparent data visualization for citizen verification
- Dependency: Added Chart.js for chart rendering
- Improved: Better desktop/mobile detection for Web Share API
- Improved: Desktop browsers now get text-only share if file share not supported
- Fixed: Handle user cancel (AbortError) gracefully without fallback
- Fixed: Download image on desktop even when text-only share succeeds
- Fixed: Removed duplicate social share function definitions
- Fixed: Better error handling in
shareWithImage()with try/catch - Fixed: Proper blob handling with reject on null
- Improved: Social share now uses Web Share API with image support (mobile)
- New:
generateResultCanvas()function for reusable image generation - New:
shareWithImage()- unified share function with Web Share API - UX: Mobile users can share image + text together via native share sheet
- UX: Desktop users get image download + share URL fallback
- Improved: Social share buttons now auto-download result image first
- New:
downloadResultImage()function for image generation - UX: Added notification message after image download
- New: Social media share buttons (LINE, Facebook, Twitter/X)
- New: Enhanced share text with detailed result info
- New:
getShareText()helper function for consistent share messages - New:
shareToLINE(),shareToFacebook(),shareToTwitter()functions - Improved: Share text now includes percentage match and website name
- Improved: Bilingual support for share messages (Thai/English)
- Style: Social buttons with brand colors and SVG icons
- Docs: Added comprehensive "Concept, Approach & Method" section
- Docs: Documented multi-dimensional scoring methodology
- Docs: Added score normalization formula explanation
- Docs: Added score balance table for all 13 shades
- Docs: Fixed shade count (12 → 13) including ส้มแอบเนียน (Orange)
- Docs: Added question design principles documentation
- Docs: Added technical implementation flow diagram
- Improved: Better score balance for all 13 political shades
- Improved: แดงดารา (DARA) max score increased from 15 to 20 (+5)
- Improved: ส้มแอบเนียน (ORANGE) max score increased from 13 to 16 (+3)
- Improved: Question 5 changed from party-specific to "reform-change" topic
- Improved: Split Q2 answers to differentiate NAM_MAK vs ORANGE_FAN
- New: Added
/api/clear-answersendpoint for database maintenance - Database: Cleared old answers data to match new question structure
- Docs: Added
scripts/clear-answers.sqlfor manual database cleanup - Docs: Added comprehensive "Concept, Approach & Method" section
- Docs: Fixed shade count (12 → 13) including ส้มแอบเนียน (Orange)
- Docs: Added score balance table and normalization formula documentation
- New: Normalized percentage calculation for fair cross-shade comparison
- Improved: Percentage now represents "how well you match this shade" on a comparable scale
- Fixed: Runner-up percentages are now correctly ordered (highest first)
- Algorithm: Uses average max possible score normalization to balance different shade opportunities
- Formula:
normalizedScore = score × (avgMax / maxPossible) - All shades can now achieve 100% with perfect answers
- Same percentage across different shades now represents comparable match levels
- Formula:
- Improved: Stats page now shows player count with percentage (e.g., "3,536 (62.1%)")
- Improved: Percentage displayed to 1 decimal place for better accuracy
- Fixed: Stats API cache reduced from 60s to 10s for near real-time updates
- Fixed: Added cache-busting to prevent stale stats display
- New: Individual answer tracking - saves each choice to D1 database
- New: Session ID generation for tracking complete quiz sessions
- New:
/api/answerendpoint - POST to save individual answers - New:
/api/answersendpoint - GET answer statistics per question - Database: Added
answerstable with session tracking - Analytics: Foundation for detailed question-level statistics
- New: Share button with subtle gradient animation
- New: Total players count on stats page
- Fixed: Screenshot watermark centering
- Fixed: Runner-up section spacing
- Improved: Screenshot function with clean inline layout
- Changed: "ดูผลลัพธ์จากผู้เล่น" → "ดูผลลัพธ์จากผู้เล่นอื่น"
- Fixed: Updated footerRelease version (was stuck at v3.6.1)
- Changed: "ดูผลลัพธ์จากผู้เล่น" → "ดูผลลัพธ์จากผู้เล่นอื่น"
- Improved: Better spacing in runner-up section
- Fixed: Removed duplicate camera emoji from share button
- Improved: Runner-up emojis larger (text-5xl) with better spacing (gap-10)
- Improved: Added border separator above runner-ups section
- Fixed: Main emoji size restored to text-8xl (was too small)
- Fixed: Runner-up emojis increased to text-4xl
- Fixed: Share button text visibility with inline gradient style
- Fixed: Watermark centering in screenshot
- New: Result page shows percentage match (e.g., "85% ตรงกับคุณ")
- New: Total players count displayed on result page
- New: Runner-up shades (2nd & 3rd place) with percentages
- New: Share button with screenshot functionality using html2canvas
- New: Watermark "thalay.eu/shade2569" on shared images
- Improved: Result page layout with better visual hierarchy
- Fixed: Desktop text sizes using CSS media queries (!important)
- Title: 28px (was 24px)
- Description: 18px (was 16px)
- Button: 20px (was 18px)
- Color wheel: 160px (was 150px)
- Improved: Desktop typography - larger, more readable text
- Improved: Larger color wheel on desktop (150px vs 120px)
- Title: text-2xl → text-3xl on desktop
- Description: text-base → text-lg on desktop
- Button: text-lg → text-xl on desktop
- Fixed: Cache-busting version numbers for CSS/JS assets
- Ensures color wheel animation loads correctly after deployment
- Improved: Better spacing between color wheel and title on start screen
- Improved: Animated spinning color wheel on start screen (replaces static icon)
- Visual: Added 12-color wheel representing all political shades
- UX: More engaging game-like introduction with glow effects
- Added: Randomized answer order for each question (Fisher-Yates shuffle)
- Improved: Fairness - answers are shuffled every time to prevent order bias
- Fixed: Title updated to be more inclusive of all political shades
- Added: D1 database binding configured for global stats persistence
- Fixed: wrangler.toml with proper
pages_build_output_dirfor deployment - Changed: Stats text shortened from "สถิติผลลัพธ์จากผู้เล่น" to "ผลลัพธ์จากผู้เล่น"
- Simplified: Removed canvas-confetti library, using CSS emoji rain only
- Each political shade now has unique symbols (80 emojis per celebration)
- Added: Category-specific emoji rain celebration
- Each political shade has unique symbols
- Removed: Fireworks/side-shooting confetti (simplified)
- Added: Cloudflare D1 database for global stats
- Added: Pages Functions (
/api/save,/api/stats) - Added: Back button to review and change answers
- Improved: Fallback to localStorage if API unavailable
- Added: Back button navigation for answer review
- Improved: Answer history tracking with score recalculation
- Added: wrangler.toml for Cloudflare Pages configuration
- Added: MIT License
- Infrastructure: GitHub connected to Cloudflare Pages
- Fixed: Removed stale submodule reference
- Added: Production-ready Tailwind CSS build process
- Added: package.json with build scripts
- Added: Global stats display
- Updated: Category descriptions for balanced tone
- Initial retro arcade-themed release
Thai: แบบทดสอบนี้สร้างขึ้นเพื่อความบันเทิงและการเสียดสีสังคมเท่านั้น มิได้มีเจตนาสร้างความแตกแยกหรือส่งเสริมแนวคิดใดๆ ทั้งสิ้น
English: This quiz is created for entertainment and social commentary purposes only. It is not intended to create division or promote any specific political ideology.
MIT License - feel free to fork and modify!
- Live Demo: findyourshade.autobahn.bot
- GitHub: github.com/bejranonda/FindYourShade
- Powered by: thalay.eu
- Sequel Game: Sim Thailand 2569
Made with 🇹🇭 for Thai politics enthusiasts