rainfall hero

TypesafeReal-Time APIsfor |

Multiplayer APIs powered-by TypeScript inference end-to-end

Multiplayer made easy

Pluv provides powerful utilities to make building complex multiplayer experiences easier.

8
7
6
5
4
3
2
1a
b
c
d
e
f
g
h
TurnWhiteBlack

Type-safety

Get auto-completion and in-code errors with end-to-end type-safety.

Multi-runtime

Build for either Cloudflare Workers or Node.js runtimes.

Yjs CRDT

Edit shared data and documents with the Yjs ecosystem.

Presence

Display user selections with per-user presence states.

Authentication

Add your own custom authentication rules to rooms.

Broadcast

Broadcast custom events to connected clients in the same room.

Simple-to-use APIs

Configure your server and client to unlock intuitive APIs that allow you to focus on your end-user experience.

jane
Drag the boxes
john
Drag the boxes
1import {
2 usePluvMyPresence,
3 usePluvOthers,
4 usePluvStorage,
5} from "client/pluv";
6import type { FC } from "react";
7
8export const Room: FC = () => {
9 // Get data and yjs shared type for mutations
10 const [boxes, sharedType] = usePluvStorage("boxes");
11 // { first: { x: -56, y: 0 },
12 // second: { x: 56, y: 0 } }
13
14 // Observe and update your selection
15 const [selection, setPresence] = usePluvMyPresence((me) => me.selection);
16 setPresence({ selection: "first" });
17
18 // Get selections of other users
19 const selections = usePluvOthers((others) => {
20 return others.map((other) => other.presence.selection);
21 });
22
23 // return ...
24};

End-to-end Type-Safety

Get intellisense and autocomplete, so you can move fast and catch errors in development

1// server/pluv.ts
2
3import { createIO } from "@pluv/io";
4import { platformCloudflare } from "@pluv/platform-cloudflare";
5import { z } from "zod";
6
7// Create your PluvIO server
8const io = createIO({
9 platform: platformCloudflare(),
10})
11 .event("EMIT_FIREWORK", {
12 input: z.object({ color: z.string() }),
13 resolver: ({ color }) => ({
14 FIREWORK_EMITTED: { color },
15 }),
16 })
17 .event("SEND_MESSAGE", {
18 // Set input validator and type
19 input: z.object({}),
20 // Set output value and type
21 resolver: ({}) => ({}),
22 });
1// client/Room.tsx
2
3import { usePluvBroadcast, usePluvEvent } from "client/pluv";
4import { FC, useCallback, useState } from "react";
5
6export const Room: FC = () => {
7 const [messages, setMessages] = useState<string[]>([]);
8
9 // Listen to new messages from the server
10 // Get types from the SEND_MESSAGE resolver output
11 usePluvEvent("MESSAGE_RECEIVED", ({}) => {
12 setMessages((prev) => [...prev]);
13 });
14
15 const broadcast = usePluvBroadcast();
16
17 const onSubmit = useCallback((message: string) => {
18 // Broadcast to all users
19 // Get types from the SEND_MESSAGE zod input
20 broadcast("SEND_MESSAGE", {});
21 }, [broadcast]);
22
23 // return ...
24};