rproj
Guided bootstrap-to-game-dev CLI for Roblox.
Takes a fresh Windows PC all the way to a working Roblox/Luau development setup, then scaffolds projects on top of it โ and explains every tool and package as it goes, so you end up knowing why your setup looks the way it does.
๐ฎ rproj 0.2.1 - guided bootstrap-to-game-dev CLI for Roblox
Takes a fresh PC all the way to a working Roblox dev setup, then
scaffolds projects on top of it. Explains every tool and package
as it goes, so you end up knowing why your setup looks like it does.
๐ Commands
๐ rproj new <name> Scaffold a project. Sets your machine up first if it
hasn't been, then asks only about this project's packages.
--like <setup> reuses a saved selection, --save-setup saves one
๐ง rproj setup Install or change the machine-wide tools: system apps, CLI
tools, Studio plugins, editor extensions
๐ฉ rproj configure [tool] Walk through a tool's settings one at a time - StyLua,
Selene, luau-lsp - explaining each, then write them out
๐ rproj upgrade Re-apply rproj's generated config to a project you already made,
so it picks up fixes shipped since it was scaffolded
๐ rproj watch Resume the dev loop: install what's missing, watch the sourcemap
๐ rproj copy Copy every file under src/ to the clipboard, with path headers
๐ rproj info [key] Look up what a tool or package does, and how to use it
โจ New here? rproj new my-first-game sets your machine up and
scaffolds your first project in one go.
Why
Setting up a Roblox project properly means installing Git, VS Code, Roblox Studio, and Blender; installing Rokit and then Rojo, Wally, Selene, StyLua, Lute and luau-lsp through it; installing the Rojo and luau-lsp Studio plugins; installing four or five VS Code extensions; and then writing default.project.json, wally.toml, selene.toml, stylua.toml, .luaurc, .gitattributes, a sourcemap watcher, and a CI workflow that agrees with all of them.
Each of those has a gotcha that costs an evening the first time you meet it. rproj knows them and gets them right by construction:
- Wally deletes
Packages/when a project has no dependencies, and stripsexport typelines out of link files on every install. - ProfileStore is a server-realm package โ listed under
[dependencies]it doesn't just land in the wrong folder,wally installrefuses to resolve it at all. - Without a
.gitattributespinning LF, a fresh Windows clone failsstylua --checkon every file it has. - luau-lsp's Studio-plugin bridge is off by default, which is why parts you create in Studio never autocomplete in your editor.
- Vide's API is a mixed table by construction, so selene's
mixed_tablelint fails every UI file a Vide project will ever contain โ and selene exits 1 on warnings, not just errors.
Every one of those is a real bug that was reproduced and fixed here, not a hypothetical. Every one is documented in the source, next to the code that prevents it.
Requirements
- Windows. Installs go through
winget. This is the only supported platform. - Rust 1.89+ to build. Edition 2024 sets a floor of 1.85, but
notify-rustdeclares 1.89 and is the highest in the dependency tree.
Install
cargo install rproj
Or from source, to get unreleased changes:
cargo install rproj --locked
Quick start
rproj new my-first-game
That's the whole thing. On a machine that has never been set up it asks what to install first (system apps โ CLI tools โ Studio plugins โ VS Code extensions), then asks about this project's packages, then scaffolds. On every run after that it skips straight to the project questions โ the machine answers almost never change, and re-asking four multi-selects per project was friction with no payoff.
Nothing already installed is ever reinstalled, and a single item failing to install is a warning, not an abort.
Commands
| Command | What it does |
|---|---|
rproj |
Welcome screen. Touches neither disk nor network. |
rproj new <name> |
Scaffolds <RobloxProjects>/<name>. Provisions the machine inline only on a machine that's never been set up, or with --reconfigure. |
rproj new <name> --like <setup> |
Reuses a package selection you saved earlier instead of asking. |
rproj new <name> --save-setup <name> |
Saves this project's selection and workflow for later --like reuse. |
rproj setup |
Machine provisioning on its own, without creating a project. Optional โ rproj new is self-sufficient. Safe to re-run. |
rproj configure [tool] |
Walks through one tool's settings, explaining each before prompting, then merges them into its config file. Covers stylua, selene, luau-lsp, stylua-vscode. |
rproj upgrade [--yes] |
Re-applies rproj's generated config to a project you already made, so it picks up fixes shipped since. Shows the plan and asks first. |
rproj watch |
Run from inside a project: installs anything missing (including fetching submodules a plain git clone left empty), then blocks on Rojo's sourcemap watcher. |
rproj copy |
Concatenates everything under src/ with // --- path --- headers to the clipboard. |
rproj info [key] |
With no key, a compact listing of the whole catalog. With one, full detail: what it's for, when to reach for it, the commands to type, and the gotchas. |
-v / --verbose |
Global. Shows every sub-process and its full output. Without it, sub-process output appears only when a step fails. |
Choosing packages
rproj new offers two modes:
- Guided โ one prompt per category, in order: State management โ UI โ Data & profiles โ Testing โ Utilities. State/UI/Data are single-pick (you don't run two UI frameworks); Testing and Utilities are multi-pick. Guided mode adds companion packages automatically โ pick
reactand you getreact-roblox, pickcharmalongside Vide and you getvide-charmrather than the React binding. - Expert โ one flat multi-select across the whole catalog, no categories, no automatic companions.
Then: Wally (default) or git submodules. Submodules clone each package's repo into modules/submodules/ and generate link files, with dependencies resolved transitively โ submodules have no dependency resolution of their own, so a selection that isn't closed over its requirements mounts packages next to siblings that aren't there.
What gets scaffolded
my-first-game/
โโโ default.project.json server/client/shared tree + place properties
โโโ rokit.toml project-local pins for every selected CLI tool
โโโ wally.toml [dependencies] / [server-dependencies], split by realm
โโโ selene.toml std = "roblox" (or "roblox+testez")
โโโ stylua.toml Luau syntax
โโโ .luaurc languageMode = "strict"
โโโ .gitattributes pins the working tree to LF
โโโ .gitignore
โโโ rproj.toml what you picked, and how
โโโ sourcemap.json
โโโ src/
โ โโโ shared/hello.luau
โ โโโ server/hello.server.luau
โ โโโ client/hello.client.luau
โโโ tests/ TestEZ only
โ โโโ .luaurc TestEZ's globals, for luau-lsp
โ โโโ {shared,server,client}/hello.spec.luau
โโโ .lute/check.luau the quality gate
โโโ .github/workflows/ci.yml runs the same gate, unchanged
โโโ .vscode/settings.json sourcemap, Studio bridge, StyLua path, LF
Plus testez.yml and testez-companion.toml if TestEZ was selected, Packages/ (Wally) or modules/ (submodules), and a Blender starter scene if Blender was enabled at setup.
The quality gate
One script, .lute/check.luau, that you run locally with lute run check and CI runs unchanged โ so local and CI results can't drift.
| Step | Tool | What it does |
|---|---|---|
| sourcemap | rojo | Regenerates sourcemap.json so requires resolve against the current tree |
| analyze | luau-lsp | Fetches Roblox global types, type-checks with LuauSolverV2, cleans up after itself |
| lint | selene | Lints at the severity selene.toml sets |
| format | stylua | --check only โ CI must not rewrite the tree it was asked to check |
A step is emitted only if the project selected its tool, so a project without StyLua gets a script that never calls it rather than a guaranteed CI failure. All four run before the script exits, so one run reports every problem instead of stopping at the first. Targets are src, plus tests when TestEZ is in play.
The catalog
Every entry โ app, CLI tool, plugin, extension, package โ carries a one-line description and a maintenance badge (Active / Community-stable / Legacy), shown inline in every picker. Badges are hand-curated, not checked live.
System apps (winget): Git ยท VS Code ยท Roblox Studio ยท Roblox ยท Blender
CLI tools (rokit): rojo ยท wally ยท wally-package-types ยท selene ยท stylua ยท lute ยท luau-lsp ยท tarmac ยท mantle
Studio plugins: Rojo ยท Hoarcekat ยท luau-lsp companion ยท Roblox's Blender add-on
VS Code extensions: luau-lsp ยท vscode-rojo ยท selene ยท StyLua ยท roblox-ui ยท TestEZ Companion ยท GitHub Actions ยท three themes
Wally packages, 22 of them:
| Category | Packages |
|---|---|
| UI | react (+ react-roblox) ยท vide ยท fusion |
| State management | reflex (+ react-reflex) ยท charm (+ charm-sync, react-charm, vide-charm) |
| Data & profiles | lyra ยท profilestore |
| Testing | testez |
| Utilities | janitor ยท ripple (+ react-ripple, vide-ripple) ยท remo ยท promise ยท greentea ยท t ยท sift |
rproj info <key> prints the long version for any of them.
Development
cargo build
cargo test # 94 tests, ~3s
cargo clippy --all-targets -- -D warnings
There's also a live suite that scaffolds genuine projects โ real network, real wally install, real rojo build, real lute run check โ and removes them on Drop however the test ends:
cargo test --test live -- --ignored --test-threads=1 # ~69s
--test-threads=1 is not optional: the tests share rokit's global manifest and wally's package cache, and two scaffolds racing on those is an irreproducible flake.
The interactive commands are tested by driving the real binary through a pseudo-terminal (tests/common/mod.rs). Two things forced that: inquire reads the console input handle rather than stdin, so a piped rproj configure stylua renders its first prompt and then hangs forever; and the pty byte stream is not what the program printed โ ConPTY may express a line break as \n or as a cursor move depending on machine load, so assertions run against a rendered screen instead of the raw bytes. Synchronisation is by expecting output, never by sleeping.
Set RPROJ_NO_EMOJI=1 for + / - / ! markers instead of โ
/ โ / โ โ for a log file, a CI transcript, or a screen reader.
docs/architecture.md in the repository is the full reference: data model, subsystem map, flow diagrams, the data-driven matrices behind the catalog and the quality gate, and the list of ecosystem landmines with the reproduction behind each one. It is not shipped in the published crate โ it is a design document for maintainers, not install documentation.
Status
v0.2.1. Windows-only and Luau-only.
Deliberately not planned: macOS support and roblox-ts. On the roadmap: a GUI over the same core logic, and live maintenance-status checking once the catalog is large enough that hand-curation becomes a burden.
License
MIT ยฉ Chatar Abdelilah