Back to Skills

fvtt-sockets

verified

This skill should be used when implementing multiplayer synchronization, using game.socket.emit/on, creating executeAsGM patterns for privileged operations, broadcasting events between clients, or avoiding common pitfalls like race conditions and duplicate execution.

View on GitHub

Marketplace

hh-agentics

ImproperSubset/hh-agentics

Plugin

fvtt-dev

development

Repository

ImproperSubset/hh-agentics

fvtt-dev/skills/fvtt-sockets/SKILL.md

Last Verified

January 21, 2026

Install Skill

Select agents to install to:

Scope:
npx add-skill https://github.com/ImproperSubset/hh-agentics/blob/main/fvtt-dev/skills/fvtt-sockets/SKILL.md -a claude-code --skill fvtt-sockets

Installation paths:

Claude
.claude/skills/fvtt-sockets/
Powered by add-skill CLI

Instructions

# Foundry VTT Sockets & Multiplayer

**Domain:** Foundry VTT Module/System Development
**Status:** Production-Ready
**Last Updated:** 2026-01-04

## Overview

Foundry VTT uses Socket.io for real-time communication between server and clients. Understanding socket patterns is essential for multiplayer-safe code.

### When to Use This Skill

- Broadcasting events to other connected clients
- Implementing GM-delegated operations for players
- Synchronizing non-document state across clients
- Creating animations/effects visible to all players
- Avoiding duplicate execution in hooks

## Socket Setup

### Manifest Configuration

Request socket access in your manifest:

```json
{
  "id": "my-module",
  "socket": true
}
```

### Event Naming

Each package gets ONE event namespace:
- **Modules:** `module.{module-id}`
- **Systems:** `system.{system-id}`

Multiplex event types with structured data:

```javascript
const SOCKET_NAME = "module.my-module";

game.socket.emit(SOCKET_NAME, {
  type: "playAnimation",
  payload: { tokenId: "abc123", effect: "fire" }
});
```

### Registration Timing

Register listeners after `game.socket` is available:

```javascript
Hooks.once("init", () => {
  game.socket.on("module.my-module", handleSocketMessage);
});

function handleSocketMessage(data) {
  switch (data.type) {
    case "playAnimation":
      playTokenAnimation(data.payload);
      break;
    case "syncState":
      updateLocalState(data.payload);
      break;
  }
}
```

## Basic Socket Patterns

### Emit to All Other Clients

```javascript
function broadcastAnimation(tokenId, effect) {
  game.socket.emit("module.my-module", {
    type: "playAnimation",
    tokenId,
    effect
  });
}
```

**Critical:** Emitting client does NOT receive its own broadcast.

### Self-Invoke Pattern

Always call handler locally when emitting:

```javascript
function triggerEffect(tokenId, effect) {
  const data = { type: "effect", tokenId, effect };

  // Execute locally
  handleEffect(data);

  // Broad

Validation Details

Front Matter
Required Fields
Valid Name Format
Valid Description
Has Sections
Allowed Tools
Instruction Length:
10681 chars