Home Teleport System
The home teleport system allows players to return to their spawn location with a 10-second interruptible cast time and 30-second cooldown.Overview
Added: March 26, 2026 (PR #1095) Features:- 10-second cast time (interruptible by movement/combat)
- 30-second cooldown (reduced from 15 minutes)
- Visual cast effects with portal animation
- Server-authoritative cooldown tracking
- Minimap orb integration for quick access
- Dual UI: dedicated button + minimap orb
Constants
Client Components
HomeTeleportButton
Dedicated teleport button with cast progress and cooldown visualization. Location:packages/client/src/game/hud/HomeTeleportButton.tsx
States:
ready- Available to castcasting- Cast in progress (shows progress bar)cooldown- On cooldown (shows remaining time + refill visual)
- Click to start cast
- Progress bar during 10-second cast
- Cooldown refill visual (bottom-to-top gradient)
- Displays remaining cooldown time (”25s”, “1m 5s”)
MinimapHomeTeleportOrb
Minimap orb for quick teleport access. Location:packages/client/src/game/hud/MinimapHomeTeleportOrb.tsx
Features:
- Circular progress indicator (SVG-based)
- Color-coded states (purple=ready, blue=casting, gray=cooldown)
- Cooldown refill animation
- Compact design for minimap integration
Shared Utilities
Location:packages/client/src/game/hud/homeTeleportUi.ts
readHomeTeleportRemainingMs()
Extract remaining cooldown milliseconds from server event.
event- Event payload fromHOME_TELEPORT_FAILED
getHomeTeleportCooldownProgress()
Calculate cooldown progress percentage for UI visualization.
cooldownRemaining- Remaining cooldown in milliseconds
Server Implementation
HomeTeleportManager
Location:packages/server/src/systems/ServerNetwork/handlers/home-teleport.ts
formatCooldownRemaining()
Format cooldown duration as human-readable string.
remainingMs- Remaining cooldown in milliseconds
Server Validation
The server validates teleport requests and sends detailed rejection reasons:- Already casting
- On cooldown (includes
remainingMs) - In combat
- Dead
- In duel arena
Visual Effects
Cast Effect (Channel Mode)
Location:packages/shared/src/systems/client/ClientTeleportEffectsSystem.ts
Components:
- Portal veil (cylinder with gradient)
- Lower orbital ring (bronze, rotating)
- Upper orbital ring (gold, counter-rotating)
- Crown ring (parchment, top of portal)
HOME_TELEPORT_CAST_START→ spawn channel effect- Update every frame with progress-based animations
HOME_TELEPORT_FAILEDorHOME_TELEPORT_CAST_CANCEL→ stop effectPLAYER_TELEPORTED→ transition to arrival burst
- Portal anchored to player’s lowest bone position (feet/hips)
- Falls back to terrain height if bones unavailable
- Small ground clearance (0.015m) for visual grounding
Arrival Effect (Burst Mode)
Separate burst effect when teleport completes:- Rune circle
- Beam eruption
- Particle helix
- Shockwave rings
PLAYER_TELEPORTED event with position field
Events
HOME_TELEPORT_CAST_START
Fired when player begins casting home teleport.
Payload:
ClientTeleportEffectsSystem- Spawns channel-mode portal effectHomeTeleportButton- Enters casting stateMinimapHomeTeleportOrb- Enters casting state
HOME_TELEPORT_FAILED
Fired when teleport is rejected or interrupted.
Payload:
ClientTeleportEffectsSystem- Stops channel effectHomeTeleportButton- Enters cooldown or ready stateMinimapHomeTeleportOrb- Enters cooldown or ready state
HOME_TELEPORT_CAST_CANCEL
Fired when player cancels cast (movement/combat).
Payload: None
Subscribers:
ClientTeleportEffectsSystem- Stops channel effectHomeTeleportButton- Returns to ready stateMinimapHomeTeleportOrb- Returns to ready state
PLAYER_TELEPORTED
Fired when teleport completes successfully.
Payload:
ClientTeleportEffectsSystem- Spawns arrival burst effect, stops channel effectHomeTeleportButton- Enters cooldown stateMinimapHomeTeleportOrb- Enters cooldown state
Network Protocol
Client → Server
homeTeleport
Request to start home teleport cast.
Payload: Empty object {}
Response:
- Success:
homeTeleportCastStartpacket - Failure:
homeTeleportFailedpacket with reason
homeTeleportCancel
Request to cancel active cast.
Payload: Empty object {}
Response: homeTeleportCastCancel packet
Server → Client
homeTeleportCastStart
Cast started successfully.
Payload:
homeTeleportFailed
Teleport rejected or interrupted.
Payload:
homeTeleportCastCancel
Cast cancelled (movement/combat).
Payload: Empty object {}
playerTeleported
Teleport completed (also used for other teleport types).
Payload:
Server-Side Logic
Cast State Machine
States:- Idle - Not casting
- Casting - Cast in progress (10 seconds)
- Cooldown - Recently teleported (30 seconds)
Interruption Conditions
Cast is interrupted if:- Player moves
- Player enters combat
- Player takes damage
- Player dies
Cooldown Tracking
Per-Player State:Testing
Unit Tests
Location:packages/server/tests/unit/teleport/HomeTeleportManager.test.ts
Coverage:
- Cast start and completion
- Cooldown enforcement (30 seconds)
- Interruption by movement/combat
- Multiple players casting simultaneously
- Cooldown expiration
remainingMsfield in rejection packetsformatCooldownRemaining()edge cases
Integration Tests
Use Playwright to test full teleport flow:- Click teleport button
- Verify cast progress bar appears
- Wait 10 seconds
- Verify player teleports to spawn
- Verify cooldown state
- Wait 30 seconds
- Verify ready state
Performance Considerations
Channel Effect Pool
Channel effects reuse the same object pool as burst teleport effects. If all pool entries are active, channel effect spawn returnsnull and cast visual is silently missing.
Pool Size: 8 entries (configurable via POOL_SIZE constant)
Mitigation: Channel effect has timeout buffer (1.5 seconds) to auto-deactivate if server completion is delayed.
Bone Iteration
getLocalPlayerTeleportAnchor() iterates up to 12 bones per frame during cast to find lowest bone position for grounding. This is acceptable for a single-player effect at 60fps.
Bones Checked:
Vector3 scratch objects avoid per-frame allocations.
Troubleshooting
Cast Effect Not Appearing
Diagnosis:- Check browser console for
HOME_TELEPORT_CAST_STARTevent - Verify
ClientTeleportEffectsSystemis initialized - Check object pool availability (may be exhausted)
Cooldown Stuck
Symptoms: Button shows cooldown but server allows teleport, or vice versa. Diagnosis:- Check server logs for cooldown state
- Verify
remainingMsfield inhomeTeleportFailedpacket - Check client is reading
remainingMscorrectly
remainingMs field.
Portal Not Grounded
Symptoms: Portal floats above or sinks below player. Diagnosis:- Verify terrain system is ready (
terrain.isReady()) - Check
getHeightAt()returns valid values - Verify bone transforms are available
- Lowest bone position (if avatar has bones)
- Terrain height (if terrain system ready)
- Player position + small offset (final fallback)
See Also
- ClientTeleportEffectsSystem - Visual effects implementation
- HomeTeleportManager - Server-side logic
- GameConstants - Cooldown and cast time constants