Skip to content

Decisions

Weave is the set of practices that Roblox, three other engines, and the software architecture literature agree on, reduced to what holds on Roblox without a build step. This page records each decision with its reason and its cost, so a team that departs from one knows what it gives up.

No engine prescribes one folder structure. They agree on five practices, and each Weave rule comes from one of them.

PracticeStated byWeave rule
One entry point per sideRoblox Creator DocsR1
The server holds the rules; clients receive replicated stateUnreal’s Gameplay Framework, Roblox security guidanceR2, R7, R8
A feature registers with the core; the core does not name featuresUnreal’s Game Features, Bevy’s pluginsR4, the boot folders
Dependencies point one way and form no cycleParnas, Martin, Godot’s scene guidanceR3, R4, R5
Content is data, kept apart from behaviourGodot’s resources, Nystrom’s Type ObjectCatalogues, tags, attributes

One rule rests on measurement. Studies of large Java, C#, and C++ systems found that modules in a dependency cycle hold most of the defects, and that a cycle is rarely removed once it exists. That supports R5.

The other rules rest on the argument of the people who proposed them and on their use in shipped engines. No study measures feature folders against layer folders, a single writer against many, or any of this on a Roblox game. Treat the rules as engineering judgement that many independent sources share.

Flat boot folders, private code beside them

Section titled “Flat boot folders, private code beside them”

An entry is one ModuleScript in Services or Controllers. Its private code is in Modules/<Feature>.

The alternative was one folder per feature, holding the entry and its private code together. Lifecycle boots every module in the folder it is given and does not search a nested folder, so a feature folder would need a second way to discover entries. The flat form needs none, and the boot folder reads as the list of features.

Cost. A feature’s entry and its private code are in two folders.

A feature is not one folder, because a container decides who can read its contents. Server code beside client code would be published to every player. One shared name per feature stands in for the folder.

An entry fetches another with Lifecycle.Get("CoinService") in Start.

A require of a sibling at load is the direct alternative, and it forms a cycle as soon as two entries need each other. A name loses the type, which is the objection the author of Knit gave when archiving that framework. Weave keeps the name for the one case that needs it, between entries, and restores the type with an annotation.

Cost. One annotation per entry used, written by hand.

Creator Docs suggest a Script with its run context set to client, placed in ReplicatedStorage. Weave keeps a LocalScript in StarterPlayerScripts. The file is a few lines long, and sync tools disagree on the file suffix for the other form.

Shared/Remotes is a folder with one module per feature. One file for all remotes would list the whole attack surface in one place, and every feature would edit it. Net.List() gives the full list at run time.

The check is a script pasted into the command bar. A game script cannot read the source of another script, so a check that runs at boot could test placement and nothing else. The command bar needs no install and works in Studio alone.

README is a ModuleScript in ServerScriptService. A team that works in Studio alone has no repository to hold a file, and a module in the place is open in the editor people already use. It is on the server so it does not replicate.

AlternativeReason
Folders by technical layer: Utils, Handlers, ManagersOne change to one feature touches every folder.
Full ports and adapters in every featureIts own authors call full boundaries expensive. In Luau it becomes functions that pass a call along.
A dependency injection containerThe wiring is hidden, and a dynamic language gives no compile-time help to find a mistake in it.
A global event busIt is a global, it hides who acts on an event, and it can hide a cycle.
One store for all stateEvery feature depends on it, and it depends on every feature’s shape.
An ECS as the base modelIt pays off with very many similar objects, and costs in debugging. Weave allows one inside a feature.
Scripts on parts, models, and interfacesStart order is not promised, and sync tools handle them unevenly.
A feature as a script with child scriptsSync tools write that shape to disk in different ways.
Require aliasesThey need configuration that Studio alone does not read.
Remotes generated from a service tableGenerated remotes carry no validation.
A schema compiler as a requirementIt adds a build step, and Weave must work with none.

Interface architecture, the model inside a feature, matchmaking, testing strategy, and asset naming. Each depends on the game.