# Calyo Otter — VR (Meta Quest, WebXR)

First-person multiplayer otter adventure. Swim the river, sniff out hidden shells,
starfish and sea urchins, trade with other otters, level up, and find Grandma's
Lost Shell Charm beyond the stone bridge.

![Calyo Otter](assets/ui/logo.webp)

## Play on Meta Quest (no install needed)

1. Serve this folder over HTTPS (WebXR requires a secure origin). Easiest options:
   - `npx serve .` then tunnel with `npx localtunnel --port 3000`, or
   - push the folder to any static host (GitHub Pages, Netlify, Vercel).
2. Open the URL in the **Quest browser** and press **Enter VR**.

For quick local testing on the same Wi-Fi you can also use `adb reverse`:
`adb reverse tcp:8080 tcp:8080` then browse to `http://localhost:8080` on Quest
(localhost is treated as secure).

## Desktop test

Any static server works: `python -m http.server 8080` in this folder →
open http://localhost:8080 → **Play on Desktop**.

## Multiplayer

Without a server the river is populated by AI otters you can trade with.

For real players:

```
cd server
npm install
npm start          # relay on ws://0.0.0.0:8090
```

Each player opens the game with `?server=ws://YOUR_PC_IP:8090` appended to the
URL (use `wss://` behind an HTTPS tunnel). Players see each other, get join
notifications, hear claps, and can trade items.

## Voice chat

Otters in the **same room** can talk to each other. Tap the **🎤 Voice** button
(bottom-right of the HUD) to go live; tap again to mute/unmute. It's open-mic:
once enabled your mic stays live until you mute.

Audio is peer-to-peer over WebRTC — the relay only shuttles the tiny setup
messages (SDP/ICE), so there's no media-server cost and voice is automatically
scoped to your room code. Requires HTTPS (or localhost) because browsers only
grant microphone access on secure origins.

Notes / limits:
- Uses public STUN for NAT traversal, which covers most home networks. Very
  restrictive/symmetric NATs would additionally need a **TURN** relay (a hosted,
  paid service) — not configured by default. Add one to `RTC_CONFIG` in
  `js/voice.js` if you hit players who can't connect.
- It's a peer mesh, ideal for small private rooms (a handful of otters).

In **VR**, the flat mic button isn't reachable, so voice is on the controller:
**hold the right B button** to toggle voice (a quick tap still opens the
inventory). The first hold enables the mic and prompts for permission; later
holds mute/unmute. A 🎤 Live / 🔇 Muted pill in the VR HUD shows your state.
Enabling on the desktop HUD before entering VR avoids the in-headset permission
prompt.

## Controls

| Action | Quest | Desktop |
|---|---|---|
| Swim | Left stick **or** squeeze a grip + pull your paw back (arm-swim) | WASD |
| Turn | Right stick | Mouse |
| Collect | A / Trigger | E |
| Inventory | B | Tab |
| Sonar (reveal treasures) | X | Q |
| Scent (track rare items) | Y | F |
| Dive boost | Right trigger | Shift |
| Clap / Trade | Right stick-press | C |
| Spin | Left stick-press | R |
| Jump / breach | Shove both gripped paws down | Space (at surface or on bank) |
| Dive down | Look down + swim | Ctrl (or look down + W) |
| Surface | Look up + swim | Space (while submerged) |
| Grab blaster / Fire | Trigger | E / Left click (hold) |
| Switch blaster | — | G |

## Diving

You swim in the direction you look — aim down and paddle to dive to the
riverbed, where most treasures hide. Underwater you get murky teal fog,
rising bubbles, and an **Air meter** (~20 s); run out and your health drains
until you surface. A hint appears when you float over something shiny.
AI otters dive and forage too.

## Water blasters (100% harmless)

Six glowing toy pickups float near the river: the **Water Squirter** (fast
jets), **Bubble Blaster** (floaty triple bubbles), and **Splash Cannon**
(lobbed water balloons). Hitting an otter just splashes them — they shake it
off with a spin and you earn XP. Nothing can ever be hurt. Icons and sound
effects are Higgsfield-generated (`assets/ui/gun_*.png`, `assets/sfx/`).

## Kelp economy

Two shops sit on the banks near spawn. **Sandy's Sell Shack** (right bank)
buys your finds — Commons 5 🌿, Rares 25, Epics 75, Legendaries 200 — with a
one-click "sell all commons" button. **Barnaby's Bazaar** (left bank) sells
the three blasters, energy snacks, permanent upgrades (max air, max health,
Speed Fins), and 40-kelp Mystery Shells. Walk up and press E. Your kelp
balance lives next to your level in the HUD and is saved with your game.

## Gameplay

- **17 collectible types** across Common / Rare / Epic / Legendary rarities,
  hidden on the riverbed, in reeds, and near rocks.
- **Sonar** makes nearby treasures pulse with rarity-colored glow rings.
- **Scent** draws a green particle trail toward the nearest rare+ item.
- **XP & levels** — collecting and trading grant XP; level-ups raise max
  health and energy. Progress autosaves to the browser.
- **Quest** — Grandma's Shell Charm hides past the bridge; return it to
  Grandma at the treehouse.
- **Trading** — approach any otter (player or AI) and press C/Grip.

## Files

- `index.html` + `js/` — the whole game (Three.js r160 via CDN, no build step)
- `assets/ui/` — logo.webp & inventory.webp (brand art) + Higgsfield-generated ability icons
- `assets/textures/` — Higgsfield-generated water/riverbed/moss tiles + sky panorama
- `server/` — optional multiplayer relay (Node + ws)
