# 🛋️ Discord Lounge — MaShowMagic Arcade

เกม Social/Hangout 2D top-down แบบ multiplayer real-time ฝังในเว็บ portfolio
(`mashowmagic.com/arcade/discord-lounge/`) — ผู้เล่นเดินไปมา เห็นกันแบบ real-time
และแชทผ่าน chat bubble เหนือหัวตัวละคร

---

## 🧱 Tech & เหตุผลที่เลือก

| ส่วน | เลือกใช้ | ทำไม |
|------|----------|------|
| Render | **Vanilla JS + Canvas 2D** | ไม่มี build step — เข้ากับ repo เดิมที่เป็น static HTML ล้วน, ไฟล์เดียวจบ, เบา, MVP นี้ไม่ต้องใช้ Phaser |
| Realtime | **Supabase Realtime** (broadcast + presence) | ไม่ต้องมี Node server รันตลอดเวลา ตรงตามข้อจำกัด static hosting |
| Auth | **reuse Discord login เดิมของ arcade** (`mashow.online`) | ผู้เล่น login ครั้งเดียวที่ hub ใช้ได้ทุกเกม ไม่ต้องตั้ง Discord app ใหม่ |
| โหลด lib | **ESM CDN** (`esm.sh/@supabase/supabase-js`) | ไม่ต้อง npm/bundler |

> **สำคัญ:** localStorage ใช้เก็บแค่ session identity จาก Discord login เดิมเท่านั้น
> — state ของ multiplayer (ตำแหน่ง/แชท/ใครออนไลน์) sync ผ่าน **Supabase อย่างเดียว** ตามข้อกำหนด

---

## 📁 โครงสร้างไฟล์

```
arcade/discord-lounge/
├── index.html      # เกมทั้งหมด (HTML + CSS + JS ในไฟล์เดียว)
└── README.md       # ไฟล์นี้
```

ภายใน `index.html` แบ่งเป็นบล็อกชัดเจน:
- **CONFIG** — ค่าที่ต้องแก้ (Supabase URL/key, ขนาดห้อง, ความเร็ว)
- **AUTH** — reuse session Discord จาก localStorage
- **REALTIME** — เชื่อม Supabase channel (presence = ใครออนไลน์, broadcast = ตำแหน่ง+แชท)
- **GAME LOOP / RENDER** — วาด canvas, กล้องตามตัว, chat bubble

---

## 🚀 Setup Supabase (ทำครั้งเดียว ~5 นาที)

MVP นี้ใช้แค่ **Realtime broadcast + presence** → **ไม่ต้องสร้างตารางหรือเขียน SQL เลย**

1. ไปที่ <https://supabase.com> → **New project** (ตั้งชื่อ เช่น `mashow-arcade`, เลือก region ใกล้ไทย เช่น `Southeast Asia (Singapore)`)
2. รอ project provision เสร็จ → เข้า **Project Settings → API**
3. คัดลอก 2 ค่า:
   - **Project URL** → ใส่ใน `SUPABASE_URL`
   - **anon / public key** → ใส่ใน `SUPABASE_ANON_KEY`
4. เปิด `index.html` แก้ส่วน CONFIG:
   ```js
   const SUPABASE_URL      = 'https://abcdxyz.supabase.co';
   const SUPABASE_ANON_KEY = 'eyJhbGciOi...';   // anon public key (ปลอดภัยที่จะอยู่ใน frontend)
   ```
5. Realtime เปิดใช้งานอยู่แล้วโดย default สำหรับ broadcast/presence — **เสร็จ**

> **anon key เปิดเผยใน frontend ได้ปลอดภัย** มันถูกออกแบบมาให้อยู่ฝั่ง client
> (ต่างจาก `service_role` key ที่ห้ามเอาออกมาเด็ดขาด)

### (ทางเลือก) เก็บประวัติแชต / presence ถาวร
ถ้าอยากเก็บ log แชตในอนาคต ค่อยสร้างตาราง `messages` + เปิด RLS แล้วใช้
`channel.on('postgres_changes', …)` — **ยังไม่ต้องทำใน MVP**

### (ทางเลือก) ล็อกห้องไม่ให้คนนอกยิง channel
Default แล้ว anon key เข้าทุก channel ได้ ถ้าต้องคุมเข้มค่อยเปิด
**Realtime Authorization** (RLS บน `realtime.messages`) ภายหลัง — เกินสโคป MVP

---

## 🔐 Discord OAuth

**ไม่ต้องตั้งค่าใหม่** — เกมนี้ reuse ระบบ login เดิมของ arcade:
- กดปุ่ม "เข้าสู่ระบบด้วย Discord" → เด้งไป `https://www.mashow.online/arcade/auth`
- หลัง authorize เด้งกลับ → แลก token ที่ `/arcade/auth/exchange` → เก็บใน localStorage
  (`arcade_discord_token`, `arcade_discord_user`) ใช้ร่วมกับเกมอื่นใน arcade

> ถ้าในอนาคตอยากให้ Lounge มี Discord app แยกของตัวเอง (เช่นแยก analytics):
> สร้าง app ใหม่ใน <https://discord.com/developers/applications> → OAuth2 →
> เพิ่ม Redirect URI เป็น `https://mashowmagic.com/arcade/discord-lounge/`
> แล้วเปลี่ยน flow ให้ยิงตรงแทน `BOT_API` — **ไม่จำเป็นสำหรับ MVP**

---

## 🧪 รันทดสอบบนเครื่อง

เป็น static file — เสิร์ฟด้วยอะไรก็ได้ (ห้ามเปิด `file://` ตรง ๆ เพราะ ES module + CORS):

```bash
# จาก root ของ repo
npx serve .          # หรือ  python -m http.server 8000
```
แล้วเปิด `http://localhost:8000/arcade/discord-lounge/`

**เทสคนเดียว:** เปิด 2 แท็บ — แต่ละแท็บได้ `clientId` คนละตัว จะเห็นตัวละคร 2 ตัวเดินสวนกัน + แชทหากันได้
(ต้อง login Discord ก่อน หรือชั่วคราว mock session ใน localStorage ก็ได้)

---

## 📦 Deploy เข้าเว็บเดิม

ไม่มีขั้น build — แค่ commit ไฟล์เข้า repo แล้ว push:
```bash
git add arcade/discord-lounge/
git commit -m "เพิ่มเกม Discord Lounge ใน Arcade"
git push
```
โฮสต์ static เดิม (Netlify/Vercel/GitHub Pages) จะ deploy อัตโนมัติ
เกมจะอยู่ที่ `https://mashowmagic.com/arcade/discord-lounge/`
และถูกลิงก์จากหน้า hub `/arcade/` (การ์ดเลือกเกม)

---

## 🎨 เปลี่ยนเป็น asset จริงทีหลัง

ตอนนี้ใช้ placeholder ที่ทำงานได้จริง — จุดที่ควรอัปเกรด:

| ตอนนี้ (placeholder) | เปลี่ยนเป็น asset จริง | สเปกแนะนำ |
|----------------------|------------------------|-----------|
| ตัวละคร = วงกลม clip Discord avatar | **sprite sheet** เดิน 4 ทิศ | PNG โปร่งใส, เฟรม **32×32 หรือ 48×48 px**, เรียง 4 แถว (ลง/ซ้าย/ขวา/บน) × 3-4 เฟรม/แถว |
| พื้น = grid วาดด้วย canvas | **tilemap** | tile **32×32 px** + ไฟล์ Tiled (`.json`) หรือ PNG พื้นห้อง |
| ไม่มีของตกแต่งห้อง | โซฟา/โต๊ะ/พรม เป็น sprite วางตำแหน่งคงที่ | PNG โปร่งใส วาง world coordinate |

ในโค้ด `drawPlayer()` คือจุดสลับจาก avatar-circle ไปเป็น sprite frame
(ใช้ `pl.dir` + ตัวนับเฟรมจาก `performance.now()` เลือกเฟรมจาก sheet)

---

## 🧩 ต่อยอดในอนาคต

- **หลายห้อง:** เปลี่ยน `const ROOM` เป็นตัวแปรจาก URL (`?room=xxx`) แล้วทำหน้าเลือกห้อง — แต่ละห้อง = คนละ Supabase channel
- **ของแต่งตัว/cosmetic:** เพิ่ม field ใน `presencePayload()` (เช่น `hat`, `skin`) แล้ววาดทับใน `drawPlayer()`; เก็บถาวรผ่าน cloud save เดิม (`/arcade/player/{id}`)
- **emote/animation:** เพิ่ม broadcast event `'emote'` คล้าย `'chat'`
- **mini-game ในห้อง:** broadcast event ใหม่ + state กลางใน Supabase table
- **กันสแปม/มอด:** ขยาย `BADWORDS`, เพิ่ม rate-limit, หรือทำ Realtime Authorization

---

## ⚙️ ปรับ performance (รองรับ 20-30 คน)

- `SEND_HZ` (default 12) = ความถี่ broadcast ตำแหน่ง — ลดลงถ้าคนเยอะแล้วหน่วง, เพิ่มถ้าอยากลื่นขึ้น
- broadcast เฉพาะตอน **ขยับจริง** เท่านั้น (อยู่นิ่ง = ไม่มี traffic)
- ตัวคนอื่น interpolate ให้ลื่นแม้รับ update ไม่ถี่
- Supabase free tier มีลิมิต concurrent/message rate — ถ้าชุมชนโตเกิน ค่อยอัป plan หรือลด `SEND_HZ`
