WebSockets
Create typed realtime endpoints, events, route rooms, and Activity-instance rooms.
Ludicord WebSocket routes are authenticated server modules under app/ws. The client hook connects to the matching route, dispatches named events, and can reconnect with exponential backoff.
#Create a server route
1import { defineWS } from "ludicord/ws/server";23export default defineWS({4 connect(client) {5 client.activity.join();6 client.emit("ready", { clientId: client.id });7 },8 events: {9 message(client, data) {10 client.activity.broadcast("message", data, { includeSelf: true });11 },12 },13 disconnect(client) {14 client.activity.leave();15 },16});
defineWS() validates public event names. Names beginning with $ludicord: or _ludicord are reserved for the framework.
#Connect from React
1import { useEffect, useState } from "react";2import { useWS } from "ludicord/ws/client";34export default function embed() {5 const socket = useWS("/ws/chat");6 const [messages, setMessages] = useState<unknown[]>([]);78 useEffect(() => socket.on("message", (message) => {9 setMessages((current) => [...current, message]);10 }), [socket]);1112 return <button disabled={socket.status !== "open"} onClick={() => socket.emit("message", { text: "Hello" })}>Send</button>;13}
on() returns an unsubscribe function, so it works directly as the cleanup returned by useEffect.
#Understand connection status
Calling emit() before open throws. Disable the action, queue it in application state, or use shared Activity state for optimistic synchronization.
#Choose a broadcast scope
The server client has three useful scopes:
Activity rooms require a verified instanceId. They prevent two separate launches of the same application from sharing game state accidentally.
#Read trusted connection context
client.ludicord contains the verified session. client.params contains dynamic WebSocket route params.
1const userId = client.ludicord.user.id;2const roomId = client.params.roomId;
Params remain untrusted input. Use the session and server data to authorize joining a custom room.
#Reliability and limits
Ludicord supports heartbeat checks, payload limits, optional compression, backpressure protection, inbound events-per-second limits, and graceful shutdown. Reconnect behavior is configurable globally and per client.
1websocket: {2 heartbeatInterval: 30_000,3 maxPayload: 1_048_576,4 maxMessagesPerSecond: 120,5 reconnect: { enabled: true, attempts: 10, initialDelay: 500, maxDelay: 10_000 }6}
Validate every incoming event payload before storing or broadcasting it. Transport authentication does not make the payload safe.
#Hot updates
Changing a WebSocket route in development reloads the route without restarting the Ludicord server. Existing affected connections close with a service-restart signal and the client hook reconnects according to policy.
#Next step
Open Shared Activity state for a higher-level, revision-safe way to synchronize common multiplayer values.