A production-ready starter kit for building coordination tools for the BRKT working group. This template demonstrates scalable patterns for multiplayer applications with shared state, real-time collaboration, and testable architecture.
BRKT is a working group focused on building tools for coordination. This starter kit is based on battle-tested patterns and components from Resonance, one of our core tools, and serves as a foundation for future coordination applications.
Building scalable multiplayer applications requires careful consideration of where state lives and how it flows through your system. This starter demonstrates our proven approach to these challenges, making it easier for BRKT team members (especially non-frontend developers) to start projects faster while following established patterns.
Application scalability comes from correct problem modeling - essentially anticipating user behaviors (both current v1 needs and future requirements) and designing how your store needs to change as a result.
The key insight: work backward from the view you want to the shape of data that needs to exist to support that view. The difficulty comes in thinking through all the permutations of views you need to enable.
We organize state based on where it needs to live and how long it should persist:
- Question: "On refresh, should this still be true?"
- Storage: Database, file system, or durable storage
- Examples: User profiles, saved documents, configuration settings
- Implementation: [Not Implemented] - would require database or external storage
- Future: Could integrate with Party Server's durable storage or external DB
- Question: "Do other people need to see this during the active session?"
- Storage: Server memory for the duration of active connections
- Examples: Live collaboration state, real-time cursors, shared toggles
- Implementation:
- Development: PartyKit room storage (persists during development session)
- Production: In-memory only (resets when all users disconnect)
- Note: Currently, session state is lost when the last user leaves the room
- Question: "Is this just for the browser right now? (would it be there if I refreshed?)"
- Storage: React state, local component state
- Examples: Form inputs, UI state, loading states, temporary selections
- Implementation: React useState, component state
- Next.js - React framework with App Router
- shadcn/ui - Component library for consistent UI patterns
- TypeScript - Type safety and developer experience
- Party Server - Real-time multiplayer capabilities on Cloudflare Workers
- Zod - Runtime validation and type generation
- Bun - Fast test runner and package manager
Instead of complex authentication systems, we use a lightweight user identification pattern:
- Persistent Identity: User IDs stored in localStorage (
brkt-user-id) - Collision-resistant: Generated using
nanoid()for URL-safe identifiers - Hydration-safe: Prevents SSR mismatches with careful client-side initialization
- Zero Config: No auth providers, databases, or signup flows needed
This approach is perfect for coordination tools where you need to track users but don't need secure login.
We implement a Redux-style Flux pattern that enables comprehensive testability:
- Predictable State: All state changes go through pure reducer functions
- Type Safety: Discriminated unions ensure action type safety
- Testability: Pure functions are easy to test in isolation
- Debugging: Clear audit trail of all state changes
- Scalability: Adding new actions and state is straightforward
// 1. Define state schema with Zod
export const SessionStateSchema = z.object({
id: z.string(),
isToggled: z.boolean(),
createdAt: z.number(),
updatedAt: z.number(),
});
// 2. Define actions with discriminated unions
export const SessionActionSchema = z.discriminatedUnion('type', [
z.object({
type: z.literal('TOGGLE_SWITCH'),
payload: z.object({ userId: z.string() }),
}),
// ... more actions
]);
// 3. Pure reducer function
export function sessionReducer(state: SessionState, action: SessionAction): SessionState {
switch (action.type) {
case 'TOGGLE_SWITCH':
return { ...state, isToggled: !state.isToggled, updatedAt: Date.now() };
default:
return state;
}
}- Unit Tests: Test state transformations independently of UI
- Validation: Zod schemas ensure runtime safety
- Immutability: Guaranteed state immutability prevents bugs
- Coverage: Comprehensive test coverage in
lib/session.test.ts
- Client Action: User interaction triggers action creation
- Action Dispatch: Action sent to Party Server via WebSocket
- Server Validation: Zod validates action structure
- State Transformation: Pure reducer applies action to current state
- State Persistence: New state saved to Party Server storage
- State Broadcast: Updated state sent to all connected clients
- UI Update: React components re-render with new state
# Install dependencies
bun install
# Start development server
bun devOpen http://localhost:3000 to see the home page.
- Navigate to
/session/your-session-name - Open the same URL in multiple browser tabs/windows
- Toggle the switch - see real-time updates across all tabs
Always run these commands after making changes:
bun run typecheck # Check for TypeScript errors
bun run lint # Check for linting issues
bun test # Run test suite├── app/ # Next.js App Router pages
│ ├── session/[sessionId] # Multiplayer session page
│ └── page.tsx # Home page
├── components/ # React components
│ ├── ui/ # shadcn/ui components
│ └── user-provider.tsx # User identification wrapper
├── hooks/ # Custom React hooks
│ └── useUserId.ts # User ID management
├── lib/ # Core business logic
│ ├── session.ts # State management (Zod schemas, reducers)
│ └── session.test.ts # Comprehensive state tests
├── party/ # Real-time server code
│ ├── server.ts # Development server (PartyKit)
│ └── index.ts # Production server (Cloudflare Workers)
└── AGENT.md # Detailed development guide
- Model the Problem: Identify what views you need and work backward to required state shape
- Determine State Location: Decide if state is persisted, shared, or client-only
- Extend Schema: Add new fields to
SessionStateSchemainlib/session.ts - Create Actions: Define new actions in
SessionActionSchema - Update Reducer: Add cases to
sessionReducerfunction - Write Tests: Add test cases for new functionality
- Build UI: Create React components that use the new state
- Validate: Run typecheck, lint, and tests
This starter kit is designed to be approachable even if you're not primarily a frontend developer:
- Type Safety: TypeScript catches errors at compile time
- Clear Patterns: Consistent patterns for state management and API design
- Comprehensive Tests: Test-driven approach ensures reliability
- Documentation: Detailed AGENT.md for development guidance
- Minimal Setup: No complex authentication or database setup required
The Flux pattern especially helps non-frontend developers because it treats state changes like API endpoints - each action is a clearly defined operation with inputs and outputs.
- See
AGENT.mdfor detailed development patterns and guidance - Study
lib/session.tsandlib/session.test.tsfor state management examples - Explore the session page at
app/session/[sessionId]/page.tsxfor real-time implementation patterns