mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-23 05:51:39 +00:00
- Introduced a new endpoint `/api/syncback` for one-click full sync from Roblox Studio to the filesystem, eliminating the need for an active WebSocket connection. - Implemented `SyncbackRequest` and `ServiceChunk` structures to handle service-level properties and child instances during syncback. - Enhanced `encodeService` to include ObjectValue carriers for accurate reference handling and prevent data loss. - Updated the syncback process to utilize Luau-style relative paths for reference attributes, improving path management and consistency. - Integrated session caching in the matching algorithm to optimize performance during syncback operations. These changes significantly improve the live syncback experience, ensuring reliable data synchronization and enhanced performance during development.
394 lines
13 KiB
Text
394 lines
13 KiB
Text
---
|
|
alwaysApply: true
|
|
---
|
|
|
|
# Atlas Project File Format
|
|
|
|
> Atlas is a fork of Rojo. Many internal identifiers, API endpoints, and struct names still reference the original "Rojo" naming.
|
|
|
|
## Project File Schema
|
|
|
|
**Recognized files:** `*.project.json5` (preferred) | `*.project.json` (legacy)
|
|
|
|
**Special:** `default.project.json5` inherits parent folder name.
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `name` | string | Yes* | Instance name (*optional if `default.project.json5`) |
|
|
| `tree` | ProjectNode | Yes | Root instance tree structure |
|
|
| `servePort` | number | No | Port for `atlas serve` (default: 34872) |
|
|
| `serveAddress` | string | No | Address to bind (default: `"127.0.0.1"`) |
|
|
| `servePlaceIds` | number[] | No | Only allow sync to these place IDs |
|
|
| `blockedPlaceIds` | number[] | No | Block sync to these place IDs |
|
|
| `placeId` | number | No | Set place ID on plugin connect |
|
|
| `gameId` | number | No | Set game/universe ID on plugin connect |
|
|
| `globIgnorePaths` | string[] | No | Glob patterns to ignore during sync |
|
|
| `syncRules` | SyncRule[] | No | Custom file type mappings |
|
|
| `syncbackRules` | SyncbackRules | No | Syncback configuration |
|
|
| `syncScriptsOnly` | bool | No | Only sync script instances (default: false) |
|
|
| `ignoreHiddenServices` | bool | No | Ignore internal services (default: true) |
|
|
|
|
```json5
|
|
{
|
|
"$schema": "https://raw.githubusercontent.com/UserGeneratedLLC/vscode-rojo/master/schemas/project.schema.json",
|
|
"name": "MyProject",
|
|
"tree": { /* ProjectNode */ },
|
|
"servePort": 34872,
|
|
"serveAddress": "0.0.0.0",
|
|
"servePlaceIds": [123456],
|
|
"blockedPlaceIds": [111111],
|
|
"placeId": 123456,
|
|
"gameId": 789012,
|
|
"globIgnorePaths": ["**/*.md", "**/node_modules/**"],
|
|
"syncRules": [/* SyncRule */],
|
|
"syncbackRules": { /* SyncbackRules */ },
|
|
"syncScriptsOnly": false,
|
|
"ignoreHiddenServices": true
|
|
}
|
|
```
|
|
|
|
## ProjectNode Schema
|
|
|
|
Used in `tree` and recursively for all children.
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `$className` | string | Instance class (required for non-services) |
|
|
| `$path` | string | Filesystem path to sync from |
|
|
| `$id` | string | Unique ID for Ref property linking |
|
|
| `$properties` | object | Instance properties to set |
|
|
| `$attributes` | object | Instance attributes to set |
|
|
| `$ignoreUnknownInstances` | bool | Whether to ignore instances not in project during sync |
|
|
|
|
**Keys without `$` prefix are child instances.**
|
|
|
|
```json5
|
|
{
|
|
"$className": "Folder",
|
|
"$path": "src/MyFolder",
|
|
"$id": "unique-id",
|
|
"$properties": { "Anchored": true },
|
|
"$attributes": { "Health": 100 },
|
|
"$ignoreUnknownInstances": false,
|
|
|
|
// Children
|
|
"ChildFolder": { "$className": "Folder" },
|
|
"MyScript": { "$path": "src/MyScript.luau" }
|
|
}
|
|
```
|
|
|
|
**Services auto-inferred:** Workspace, ReplicatedStorage, ServerScriptService, ServerStorage, StarterGui, StarterPlayer, Lighting, Teams, Chat, SoundService, LocalizationService, TestService, etc.
|
|
|
|
## File Extension Mappings
|
|
|
|
### Scripts
|
|
|
|
| Extension | Result | RunContext | Note |
|
|
|-----------|--------|------------|------|
|
|
| `*.luau` | ModuleScript | — | Preferred |
|
|
| `*.server.luau` | Script | Server | Preferred |
|
|
| `*.client.luau` | Script | Client | Preferred |
|
|
| `*.plugin.luau` | Script | Plugin | |
|
|
| `*.local.luau` | LocalScript | — | |
|
|
| `*.legacy.luau` | Script | Legacy | |
|
|
| `*.lua` | ModuleScript | — | Legacy |
|
|
| `*.server.lua` | Script | Legacy | Legacy |
|
|
| `*.client.lua` | LocalScript | — | Legacy |
|
|
| `*.plugin.lua` | Script | Plugin | Legacy |
|
|
|
|
**Prefer `.luau`** — modern RunContext. `.lua` is legacy (still supported).
|
|
|
|
### Models & Data
|
|
|
|
| Extension | Result | Note |
|
|
|-----------|--------|------|
|
|
| `*.rbxm` | Binary model | |
|
|
| `*.rbxmx` | XML model | |
|
|
| `*.model.json5` | JSON model | Preferred |
|
|
| `*.model.json` | JSON model | Legacy |
|
|
| `*.txt` | StringValue | |
|
|
| `*.csv` | LocalizationTable | |
|
|
| `*.json5` | ModuleScript (Lua table) | Preferred |
|
|
| `*.json` | ModuleScript (Lua table) | Legacy |
|
|
| `*.toml` | ModuleScript (Lua table) | |
|
|
| `*.yaml`, `*.yml` | ModuleScript (Lua table) | |
|
|
|
|
### Meta & Project
|
|
|
|
| Extension | Purpose | Note |
|
|
|-----------|---------|------|
|
|
| `*.meta.json5` | Add properties/attributes to sibling | Preferred |
|
|
| `*.meta.json` | Add properties/attributes to sibling | Legacy |
|
|
| `*.project.json5` | Nested project | Preferred |
|
|
| `*.project.json` | Nested project | Legacy |
|
|
|
|
## Init File Priority
|
|
|
|
When directory has multiple init files, first match wins:
|
|
|
|
1. `default.project.json5` → Nested project (preferred)
|
|
2. `default.project.json` → Nested project (legacy)
|
|
3. `init.luau` → ModuleScript (preferred)
|
|
4. `init.server.luau` → Script (Server)
|
|
5. `init.client.luau` → Script (Client)
|
|
6. `init.plugin.luau` → Script (Plugin)
|
|
7. `init.local.luau` → LocalScript
|
|
8. `init.legacy.luau` → Script (Legacy)
|
|
9. `init.csv` → LocalizationTable
|
|
10. `init.lua` → ModuleScript (legacy)
|
|
11. `init.server.lua` → Script (Legacy)
|
|
12. `init.client.lua` → LocalScript (legacy)
|
|
|
|
**No init file?** → Directory becomes Folder. **Prefer `.luau` and `.json5` extensions.**
|
|
|
|
## Sync Rules Schema
|
|
|
|
Custom file type handling in `syncRules` array:
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `pattern` | string | Yes | Glob pattern to match files |
|
|
| `use` | string | Yes | Middleware type (see table below) |
|
|
| `suffix` | string | No | Extension to strip from instance name |
|
|
| `exclude` | string | No | Glob pattern to exclude from matching |
|
|
|
|
```json5
|
|
{
|
|
"syncRules": [{
|
|
"pattern": "*.foo",
|
|
"use": "moduleScript",
|
|
"suffix": ".foo",
|
|
"exclude": "*.test.foo"
|
|
}]
|
|
}
|
|
```
|
|
|
|
### `use` Values
|
|
|
|
| Value | Result |
|
|
|-------|--------|
|
|
| `serverScript` | Script (Server) |
|
|
| `clientScript` | Script (Client) |
|
|
| `moduleScript` | ModuleScript |
|
|
| `pluginScript` | Script (Plugin) |
|
|
| `localScript` | LocalScript |
|
|
| `legacyScript` | Script (Legacy) |
|
|
| `json`, `toml`, `yaml` | ModuleScript |
|
|
| `csv` | LocalizationTable |
|
|
| `text` | StringValue |
|
|
| `jsonModel`, `rbxm`, `rbxmx` | Instance tree |
|
|
| `project` | Nested project |
|
|
| `ignore` | Skip file |
|
|
|
|
## Syncback Rules Schema
|
|
|
|
Configure `syncbackRules` object for Roblox → filesystem sync:
|
|
|
|
| Field | Type | Default | Description |
|
|
|-------|------|---------|-------------|
|
|
| `ignoreTrees` | string[] | `[]` | Roblox tree paths to skip (e.g., `"ServerStorage/Secrets"`) |
|
|
| `ignorePaths` | string[] | `[]` | Filesystem glob patterns to skip (e.g., `"src/generated/*"`) |
|
|
| `ignoreProperties` | object | `{}` | Properties to skip per class: `{"ClassName": ["Prop1", "Prop2"]}` |
|
|
| `ignoreClasses` | string[] | `[]` | Instance classes to skip entirely |
|
|
| `syncCurrentCamera` | bool | `false` | Whether to sync `Workspace.CurrentCamera` |
|
|
| `syncUnscriptable` | bool | `false` | Whether to sync unscriptable properties |
|
|
| `ignoreReferents` | bool | `false` | Whether to skip Ref properties (e.g., `Model.PrimaryPart`) |
|
|
| `createIgnoreDirPaths` | bool | `false` | Whether `/**` in ignore paths also matches the directory itself |
|
|
| `ignoreHiddenServices` | bool | — | Override root-level `ignoreHiddenServices` for syncback |
|
|
| `warnDuplicateNames` | bool | `false` | Warn on duplicate child names during syncback |
|
|
|
|
```json5
|
|
{
|
|
"syncbackRules": {
|
|
"ignoreTrees": ["ServerStorage/Secrets", "Workspace/Camera"],
|
|
"ignorePaths": ["src/generated/*", "src/temp/**"],
|
|
"ignoreProperties": {
|
|
"BasePart": ["Color", "BrickColor"],
|
|
"Script": ["Disabled"]
|
|
},
|
|
"ignoreClasses": ["Terrain", "Camera"],
|
|
"syncCurrentCamera": false,
|
|
"syncUnscriptable": false,
|
|
"ignoreReferents": false,
|
|
"createIgnoreDirPaths": false,
|
|
"warnDuplicateNames": false
|
|
}
|
|
}
|
|
```
|
|
|
|
## Meta Files
|
|
|
|
Add metadata to file-based instances. Meta files use **camelCase keys** (no `$` prefix -- that's only for ProjectNode).
|
|
|
|
**Adjacent meta** (e.g. `MyScript.server.meta.json5` for `MyScript.server.luau`):
|
|
|
|
```json5
|
|
{
|
|
"name": "Key:Script", // Override filename-derived instance name (slugify support)
|
|
"id": "unique-id", // For Ref property linking
|
|
"properties": { "Disabled": false },
|
|
"attributes": { "Priority": 1 },
|
|
"ignoreUnknownInstances": true
|
|
}
|
|
```
|
|
|
|
**Directory meta** (e.g. `init.meta.json5` inside a directory):
|
|
|
|
```json5
|
|
{
|
|
"name": "My:Folder", // Override directory-derived instance name
|
|
"className": "Configuration", // Override class (directory meta only)
|
|
"id": "unique-id",
|
|
"properties": { "Anchored": true },
|
|
"attributes": { "Health": 100 },
|
|
"ignoreUnknownInstances": false
|
|
}
|
|
```
|
|
|
|
**Key differences from ProjectNode:** Meta uses `className`, `properties`, `attributes` (camelCase, no `$` prefix). Adjacent meta does NOT support `className`.
|
|
|
|
**`name` field (slugify support):** When an instance name contains forbidden filesystem characters (`: / ? * < > | " \`), syncback slugifies the filename (forbidden chars → `_`) and stores the real name in the `name` field. On forward sync, `name` overrides the filename-derived instance name. On collisions (e.g. `A/B` and `A_B` both slugify to `A_B`), `~2`, `~3` suffixes are appended and meta `name` fields distinguish them.
|
|
|
|
**`Rojo_Ref_*` attributes:** Meta files may also contain `Rojo_Ref_PropertyName` attributes written by syncback/two-way sync for Ref property linking. These are managed automatically and should not be hand-edited.
|
|
|
|
**Meta files CAN'T:** Set `$path`, have children.
|
|
|
|
## Model.json5 Format
|
|
|
|
Inline instance definition. Like meta files, model files use **camelCase keys** (no `$` prefix).
|
|
|
|
```json5
|
|
{
|
|
"name": "What?Model", // Override filename-derived name (slugify support)
|
|
"className": "Tool",
|
|
"id": "unique-id",
|
|
"properties": { "CanBeDropped": false },
|
|
"attributes": { "Damage": 50 },
|
|
"children": {
|
|
"Handle": {
|
|
"className": "Part",
|
|
"properties": { "Size": [1, 1, 3] }
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Note:** Children are nested under a `"children"` key (not flattened like in ProjectNode).
|
|
|
|
## Property Formats
|
|
|
|
### Shorthand (Recommended)
|
|
|
|
```json5
|
|
{
|
|
"$properties": {
|
|
"Anchored": true, // Bool
|
|
"Health": 100, // Number
|
|
"Position": [0, 5, 0], // Vector3
|
|
"ImageRectSize": [100, 100], // Vector2
|
|
"Color": [1, 0, 0], // Color3 (normalized RGB)
|
|
"BrickColor": "Bright red", // BrickColor name
|
|
"Shape": "Ball", // Enum name
|
|
"Tags": ["Collectible", "PowerUp"], // Array
|
|
"Size": { "X": {"Scale": 1, "Offset": 0}, "Y": {"Scale": 0, "Offset": 100} }, // UDim2
|
|
"CFrame": { "position": [0, 5, 0], "orientation": [[1,0,0],[0,1,0],[0,0,1]] } // CFrame
|
|
}
|
|
}
|
|
```
|
|
|
|
### Explicit Type
|
|
|
|
Use when ambiguous or specifying enum by number:
|
|
|
|
```json5
|
|
{
|
|
"$properties": {
|
|
"Position": { "Vector3": [0, 5, 0] },
|
|
"Shape": { "Enum": 1 },
|
|
"BrickColor": { "BrickColor": 21 }
|
|
}
|
|
}
|
|
```
|
|
|
|
## Attributes
|
|
|
|
Same format as properties. Limitations: no Ref, no NumberSequence/ColorSequence, enums use string names only.
|
|
|
|
```json5
|
|
{
|
|
"$attributes": {
|
|
"Health": 100,
|
|
"Position": [0, 5, 0],
|
|
"MyFont": { "family": "rbxasset://fonts/families/SourceSansPro.json", "weight": "Regular", "style": "Normal" }
|
|
}
|
|
}
|
|
```
|
|
|
|
## Ref Property Linking
|
|
|
|
Two systems for linking instance references, both supported:
|
|
|
|
### Path-Based: `Rojo_Ref_*` (preferred, written by syncback/two-way sync)
|
|
|
|
Uses filesystem-name paths (slugified, dedup'd) to reference target instances:
|
|
|
|
```json5
|
|
// In meta file for an instance with PrimaryPart pointing to Handle
|
|
{
|
|
"attributes": {
|
|
"Rojo_Ref_PrimaryPart": "Workspace/MyModel/Handle.model.json5"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Attribute format:** `Rojo_Ref_<PropertyName> = "<path>"`
|
|
|
|
Syncback writes **Luau-style relative paths**:
|
|
- `@self` / `@self/Child.luau` -- target is same instance or a descendant
|
|
- `./Sibling.luau` -- target is a same-parent sibling
|
|
- `../Uncle.luau` -- target is a parent's sibling
|
|
- `@game/Service/Path` -- cross-service reference
|
|
|
|
Forward sync resolves both relative and absolute formats via `resolve_ref_path_to_absolute()` + `get_instance_by_path()`. Path segments use full filesystem names (slug + extension + dedup suffix), matched case-insensitive with instance name fallback.
|
|
|
|
### ID-Based: `Rojo_Target_*` + `$id` (legacy, still read by forward sync)
|
|
|
|
Link instances via `$id` and special attributes:
|
|
|
|
```json5
|
|
{
|
|
"tree": {
|
|
"Target": { "$className": "Part", "$id": "myTarget" },
|
|
"Pointer": {
|
|
"$className": "ObjectValue",
|
|
"$attributes": { "Rojo_Target_Value": "myTarget" }
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Attribute format:** `Rojo_Target_<PropertyName>`
|
|
|
|
**Priority:** When both `Rojo_Ref_*` and `Rojo_Target_*` exist for the same property, `Rojo_Ref_*` takes precedence.
|
|
|
|
## Property Types
|
|
|
|
`String`, `Bool`, `Int32`, `Int64`, `Float32`, `Float64`, `Vector2`, `Vector3`, `Vector2int16`, `Vector3int16`, `UDim`, `UDim2`, `CFrame`, `Color3`, `Color3uint8`, `BrickColor`, `NumberRange`, `Rect`, `NumberSequence`, `ColorSequence`, `Enum`, `Ref`, `Content`, `Font`, `PhysicalProperties`, `Axes`, `Faces`, `Tags`, `Attributes`
|
|
|
|
See `rbx_reflection_database` for property listings per class.
|
|
|
|
## Validation Errors
|
|
|
|
1. Unknown fields (except children)
|
|
2. Reserved names starting with `$` as children
|
|
3. Missing `$className` or `$path`
|
|
4. `$path` to non-existent file
|
|
5. Invalid property types
|
|
6. Invalid glob syntax
|
|
7. Duplicate `$id`
|
|
|
|
## Source Files
|
|
|
|
- `src/project.rs` - Project parsing
|
|
- `src/snapshot_middleware/mod.rs` - Extension mappings
|
|
- `src/snapshot/` - Instance tree structure
|