diff --git a/README.md b/README.md index f39ec440..bef7a89b 100644 --- a/README.md +++ b/README.md @@ -1,46 +1,278 @@
- Rojo + Atlas
 
- Actions status - Latest server version - Rojo Documentation + CI status + VS Code Marketplace + Open VSX Registry

-**Rojo** is a tool designed to enable Roblox developers to use professional-grade software engineering tools. - -With Rojo, it's possible to use industry-leading tools like **Visual Studio Code** and **Git**. - -Rojo is designed for power users who want to use the best tools available for building games, libraries, and plugins. +**Atlas** bridges Roblox Studio with **Cursor/Claude**, so large teams can collaborate on complex games with full project context. ## Features -Rojo enables: -* Working on scripts and models from the filesystem, in your favorite editor -* Versioning your game, library, or plugin using Git or another VCS -* Streaming `rbxmx` and `rbxm` models into your game in real time -* Packaging and deploying your project to Roblox.com from the command line +- **Live Sync** — Work on scripts and models from the filesystem with real-time sync to Roblox Studio +- **Two-Way Sync** — Push changes from the filesystem to Studio, or pull changes from Studio back to the filesystem +- **Build & Upload** — Package and deploy `.rbxl`, `.rbxm`, `.rbxlx`, and `.rbxmx` files from the command line +- **Syncback** — Pull an entire Roblox place into a local project with one command +- **Clone** — Create a full local project from any existing Roblox place: `atlas clone PLACEID` +- **Cursor / VS Code Extension** — JSON5 schema support, automatic CLI installation, bundled Luau tooling -In the future, Rojo will be able to: +## Installation -* Sync instances from Roblox Studio to the filesystem -* Automatically convert your existing game to work with Rojo -* Import custom instances like MoonScript code +The fastest way to get started is to install the Cursor or VS Code extension, which handles CLI installation automatically. -## [Documentation](https://rojo.space/docs) -Documentation is hosted in the [rojo.space repository](https://github.com/rojo-rbx/rojo.space). +### 1. Install the Extension -## Contributing -Check out our [contribution guide](CONTRIBUTING.md) for detailed instructions for helping work on Rojo! +- **Cursor / Other**: [Open VSX Registry](https://open-vsx.org/extension/UserGeneratedLLC/vscode-roblox-atlas) +- **VS Code**: [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=UserGeneratedLLC.vscode-roblox-atlas) -Pull requests are welcome! +The extension will prompt to install the Atlas CLI via [Rokit](https://github.com/rojo-rbx/rokit) and the Roblox Studio plugin if they aren't already on your system. -Rojo supports Rust 1.88 and newer. The minimum supported version of Rust is based on the latest versions of the dependencies that Rojo has. +### 2. Alternative: Manual CLI Install -## License -Rojo is available under the terms of the Mozilla Public License, Version 2.0. See [LICENSE.txt](LICENSE.txt) for details. +If you prefer not to use the extension, install the CLI directly: + +**Via Rokit (recommended):** +```bash +rokit add --global UserGeneratedLLC/rojo atlas +``` + +**Build from source:** +```bash +git clone --recursive https://github.com/UserGeneratedLLC/rojo +cd rojo +cargo build --release +``` + +The binary is output to `target/release/atlas` (or `atlas.exe` on Windows). + +## Getting Started + +### Clone an Existing PlaceId + +```bash +atlas clone 123456789 # Download and set up the project locally +atlas serve # Start live sync server for Roblox Studio +``` + +Then just: + +```bash +atlas studio # Open the project in Roblox Studio +atlas cursor # Open the project in Cursor IDE +``` + +## New Project + +```bash +atlas init --kind place +atlas serve +``` + +Then in Roblox Studio, open the Atlas plugin widget and click **Connect**. + +## CLI Commands + +### Core + +```bash +atlas serve [project] # Start live sync server (default port: 34873) +atlas serve --port 8080 # Use a custom port +atlas build [project] -o out.rbxl # Build to .rbxl, .rbxm, .rbxlx, or .rbxmx +atlas build --watch -o out.rbxl # Rebuild automatically on file changes +atlas build --plugin Plugin.rbxm # Build directly to Studio's plugins folder +atlas upload [project] --asset_id ID # Upload to Roblox (cookie or API key auth) +``` + +### Project Management + +```bash +atlas init # Initialize a new place project +atlas init --kind model # Initialize a model project +atlas init --kind plugin # Initialize a plugin project +atlas clone PLACEID # Clone a Roblox place into a new local project +atlas fmt-project [project] # Reformat project file with sorted keys +``` + +### Syncback + +```bash +atlas syncback [project] # Sync from a local .rbxl to the filesystem +atlas syncback -d PLACEID # Download the place from Roblox first +atlas syncback --incremental # Preserve existing file structure +atlas syncback --list # Preview what will change (no writes) +atlas syncback --dry-run # Simulate without writing files +atlas syncback --sourcemap # Generate sourcemap.json after sync +``` + +`atlas pull` is an alias for `atlas syncback`. + +### Tooling + +```bash +atlas sourcemap [project] # Generate sourcemap.json for Luau LSP +atlas sourcemap --watch # Regenerate on file changes +atlas plugin install # Install the Studio plugin +atlas plugin uninstall # Remove the Studio plugin +atlas studio [project] # Open the project in Roblox Studio +atlas cursor [path] # Open the project in Cursor IDE +atlas doc # Open documentation in the browser +``` + +### Global Options + +```bash +atlas --verbose # Enable debug logging (-v, -vv, -vvv) +atlas --color never # Disable colored output (auto | always | never) +``` + +## Workflows + +### Cloning from an Existing Place + +```bash +atlas clone 123456789 +``` + +What happens: +1. Fetches the experience name from the Roblox API +2. Creates a project folder with a sanitized name +3. Initializes the project with `atlas init` +4. Downloads the place and runs syncback to write all instances to the filesystem +5. Commits the result if git was initialized + +### Updating from Roblox + +If the place has been edited in Studio and you want to pull those changes back: + +```bash +atlas syncback -d PLACEID +``` + +Or if you already have a local `.rbxl` file: + +```bash +atlas syncback +``` + +Use `--incremental` to preserve your existing file layout, or omit it for a clean rebuild. Use `--list` or `--dry-run` to preview before committing to changes. + +### Shortcuts + +| Command | What it does | +|---------|-------------| +| `atlas studio` | Opens the project's place in Roblox Studio (reads `servePlaceIds` from the project file) | +| `atlas cursor` | Opens the project directory in Cursor IDE | + +## One-Shot Mode + +One-Shot Sync is a plugin setting (enabled by default) that performs a single sync and then disconnects. When enabled: + +- The project tree syncs once, then the plugin automatically disconnects +- All automatic outgoing writes are blocked — only changes you explicitly confirm are applied +- The sync lock is skipped, so any number of people can connect and work together simultaneously +- A 30-second safety timeout ensures the connection is cleaned up + +To use persistent (continuous) sync instead, disable "One-Shot Sync" in the plugin settings. + +## Working with Teams + +Atlas includes a sync lock to prevent conflicts when multiple people work on the same place in Team Create. + +- A session lock (`__Atlas_SessionLock` in `ServerStorage`) is acquired when someone connects in persistent mode +- Only one user can actively sync at a time — others see a message indicating who holds the lock +- **One-shot mode bypasses the lock**, letting the whole team preview the synced state without conflicts + +**Recommended team workflow:** One designated person syncs in persistent mode (one-shot disabled). Everyone else uses one-shot mode for quick, conflict-free previews. + +## File Formats + +### Scripts + +| Extension | Result | RunContext | +|-----------|--------|-----------| +| `*.luau` | ModuleScript | — | +| `*.server.luau` | Script | Server | +| `*.client.luau` | Script | Client | +| `*.plugin.luau` | Script | Plugin | +| `*.local.luau` | LocalScript | — | +| `*.legacy.luau` | Script | Legacy | + +### Data & Models + +| Extension | Result | +|-----------|--------| +| `*.json5` | ModuleScript (Lua table) | +| `*.toml` | ModuleScript (Lua table) | +| `*.yaml` / `*.yml` | ModuleScript (Lua table) | +| `*.csv` | LocalizationTable | +| `*.txt` | StringValue | +| `*.rbxm` | Binary model | +| `*.rbxmx` | XML model | +| `*.model.json5` | JSON model | + +### Metadata & Projects + +| Extension | Purpose | +|-----------|---------| +| `*.meta.json5` | Add properties/attributes to a sibling instance | +| `*.project.json5` | Project file (or nested project) | + +Legacy `.lua`, `.json`, `.meta.json`, `.model.json`, and `.project.json` extensions are still supported. + +## Project Structure + +A typical Atlas place project: + +``` +MyGame/ +├── default.project.json5 # Project configuration +├── src/ # Instance tree (synced to DataModel) +│ ├── ReplicatedStorage/ +│ ├── ServerScriptService/ +│ ├── ServerStorage/ +│ ├── StarterGui/ +│ ├── StarterPlayer/ +│ └── Workspace/ +├── rokit.toml # Pins Atlas version for the project +└── .luaurc # Luau LSP configuration +``` + +Example `default.project.json5`: + +```json5 +{ + name: "MyGame", + servePlaceIds: [123456789], + tree: { + $className: "DataModel", + $path: "src" + } +} +``` + +## Troubleshooting + +### Plugin not connecting +- Ensure `atlas serve` is running +- Check that the port matches (default: `34873`, or whatever `servePort` is set to in your project file) +- Verify the Atlas CLI version matches the plugin version (major.minor must agree) + +### Syncback produces unexpected results +- Use `--list` or `--dry-run` to preview changes before writing +- Try `--incremental` to preserve your existing file structure +- Check `syncbackRules` in your project file for ignored paths or classes + +### Build errors +- Run `atlas fmt-project` to fix JSON formatting issues +- Ensure all `$path` entries in the project file point to existing files/directories + +### Plugin shows "another user is syncing" +- Someone else holds the sync lock in Team Create +- Wait for them to disconnect, or use one-shot mode to preview without locking diff --git a/src/cli/clone.rs b/src/cli/clone.rs index 5bcbb3e3..1c7ac103 100644 --- a/src/cli/clone.rs +++ b/src/cli/clone.rs @@ -36,6 +36,10 @@ pub struct CloneCommand { /// Skip cloning cursor rules into .cursor directory. #[clap(long)] pub skip_rules: bool, + + /// Skip changing the working directory into the project after creation. + #[clap(long)] + pub skip_cd: bool, } impl CloneCommand { @@ -72,6 +76,7 @@ impl CloneCommand { skip_git, placeid: Some(self.placeid), skip_rules: self.skip_rules, + skip_cd: true, }; init.run()?; @@ -111,6 +116,11 @@ impl CloneCommand { .status(); } + if !self.skip_cd { + std::env::set_current_dir(&path) + .with_context(|| format!("Failed to cd into {}", path.display()))?; + } + Ok(()) } } diff --git a/src/cli/init.rs b/src/cli/init.rs index 792518fb..47dad03a 100644 --- a/src/cli/init.rs +++ b/src/cli/init.rs @@ -9,7 +9,7 @@ use std::{ io::{self, Write}, }; -use anyhow::{bail, format_err}; +use anyhow::{bail, format_err, Context}; use clap::Parser; use fs_err as fs; use fs_err::OpenOptions; @@ -45,6 +45,10 @@ pub struct InitCommand { /// Skip cloning cursor rules into .cursor directory. #[clap(long)] pub skip_rules: bool, + + /// Skip changing the working directory into the project after creation. + #[clap(skip)] + pub skip_cd: bool, } impl InitCommand { @@ -206,8 +210,9 @@ impl InitCommand { println!("Created project successfully."); - if self.placeid.is_some() { - println!("Run 'atlas syncback' to sync your place."); + if !self.skip_cd { + std::env::set_current_dir(&base_path) + .with_context(|| format!("Failed to cd into {}", base_path.display()))?; } Ok(())