rojo/.cursor/rules/atlas-project.mdc
Joe 3fd50df0b2 Update logging and enhance .gitignore for Atlas directory
- Introduced a logging system using `tracing` and related crates to improve log management and output formatting.
- Updated `.gitignore` to include the `.atlas/` directory, ensuring that log files and other generated content are not tracked by Git.
- Enhanced project templates to include the new `.gitignore` settings for Atlas in various project types.

These changes aim to improve logging capabilities and maintain a cleaner repository by ignoring unnecessary files.
2026-03-01 13:16:00 -06:00

396 lines
14 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) |
| `fileLogLevel` | string | No | File logging level: "trace" (default), "debug", "info", "warn", "error", "none" |
```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,
"fileLogLevel": "trace"
}
```
## 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