One way syncing from your editor into Roblox Studio. The server owns the truth, Studio only ever receives.
Keep your game on disk, in real files, under version control, in the editor you already use. RoFlux watches the folder and pushes every change into Studio as it happens.
$ roflux serve
ok TestProject loaded, 24 instances, 3 scripts
info watching C:\dev\TestProject
ok listening on http://127.0.0.1:34872
sync studio connected (1 total)
sync +1 ~1 -0 (25 instances, 3 scripts)
+ ReplicatedStorage/Shared/Inventory [ModuleScript]
~ StarterPlayer/StarterPlayerScripts/Client (Source)
Studio never tells the server anything about the place. Files are the source of truth, so there is no merge, no conflict, and no chance of Studio quietly overwriting your work.
Every instance is managed, passthrough or a reference. RoFlux deletes drift inside the trees you own and leaves everything else in the place completely alone.
Hook into reads, writes and file events. Rewrite source on its way out, or claim a file extension and turn it into a whole tree of instances.
sourcemap.json is regenerated on every rebuild and is what luau-lsp reads, so types and autocomplete follow your files without a second tool.
roflux build writes real .rbxl and .rbxm files with properly typed properties, so the same project can go straight to a build pipeline.
roflux plugin installs the Studio plugin from the server executable itself, so the plugin you are running always matches the server you are running.
There is no giant manifest describing your tree. A file becomes an instance, a folder becomes a folder, and a small meta.json says where a tree belongs and what it is.
MyGame/
├─ default.project.json -- project info and service properties
├─ scripts/ -- compile time hooks
│ └─ banner.luau
├─ Shared/
│ ├─ init.meta.json -- { "$Parent": "ReplicatedStorage" }
│ ├─ Inventory.luau -- ModuleScript
│ └─ Signal/
│ ├─ init.luau -- the folder becomes a ModuleScript
│ └─ Connection.luau -- a child of it
└─ Server/
├─ init.meta.json -- { "$Parent": "ServerScriptService" }
└─ Main.server.luau -- Script
A hook script can claim an extension and return a declaration. One file can build a whole subtree, and every instance it produces is traced back to that file, so editing it patches only what changed and deleting it removes everything it made.
roflux.transpile("html", function(file)
local screen = { ["$ClassName"] = "Frame" }
for tag, body in file.text:gmatch("<(%a[%w]*)[^>]*>%s*([^<]*)%s*</") do
screen[tag] = {
["$ClassName"] = "TextLabel",
["$Properties"] = { Text = body },
}
end
return screen
end)
-- build the server
cargo build --release --manifest-path Server/Cargo.toml
-- install the Studio plugin out of the binary
roflux plugin
-- start syncing
roflux serve MyGame
Then open Studio, click the RoFlux button, and press Connect.