Architecture Overview
App-Based Modularity
Woodlands uses a modular app-based architecture. Each feature area is an app under src/apps/ with its own client, server, and shared directories. Apps communicate through typed remotes (Remo) and shared reactive state (Charm atoms).
src/apps/
├── chunks/ # Procedural world generation
├── enemies/ # Entity spawning & AI behaviors
├── global/ # Death, respawn, player data
├── lobby/ # Queue & matchmaking
├── quirkymals/ # Player character system
└── devtools/ # Debug tools
Flamework Decorators
| Decorator | Side | Purpose |
|---|---|---|
@Service | Server | Singleton service with lifecycle hooks |
@Controller | Client | Singleton controller with lifecycle hooks |
@Component | Both | Instance-attached behavior (tag-based) |
Lifecycle order: onInit() → onStart() → onTick() (per frame)
Dependencies are resolved via Dependency<T>() for cross-service communication.
State Management
Charm Atoms
Reactive state containers that trigger effects when values change:
// Define
const gameSeed = atom(0);
// Read
const seed = gameSeed();
// Write
gameSeed(12345);
// React
effect(() => {
const seed = gameSeed();
// runs whenever gameSeed changes
});
Atom Categories
| Store | Scope | Key Atoms |
|---|---|---|
worldAtoms | Server → All Clients | dayNight, pathNodes, gameSeed, chunkPacing |
playerAtoms | Server → All Clients | dangerZonePlayers, safeZonePlayers, gamePhase |
datastore | Server → Owner Client | Player save data (quirkymal, settings, stats) |
Sync Pipeline
Server atoms → charm-sync producer → network → charm-sync consumer → Client atoms
Networking (Remo)
Each app defines its own remotes in shared/*-remotes.ts:
export const chunksRemotes = createRemotes({
// Server → Client (one-way)
chunkSpawned: remote<Client, [data: {...}]>(),
// Client → Server (one-way)
safeZoneEntered: remote<Server, [data: {...}]>(),
// Request-Response
retrievePacket: remote<Server>().returns<{...}>(),
});
ECS (jecs)
Used exclusively for enemy entities. The ECS world is a singleton in shared/ecs/world.ts.
Components define data (position, state, type). Tags classify entities (IsFlowerTrap, IsWatcher). Systems run behavior logic each frame on the server, with network sync broadcasting to clients.
See ECS System for details.
Build Pipeline
TypeScript → rbxtsc (with Flamework transformer) → Luau → Rojo → Roblox Studio
The default.project.json maps output directories to Roblox services:
out/server+out/apps/*/server→ ServerScriptServiceout/client+out/apps/*/client→ StarterPlayerScriptsout/shared+out/apps/*/shared→ ReplicatedStorage