azul-sync 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/.gitattributes +1 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +31 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  4. package/README.md +142 -0
  5. package/dist/build.d.ts +19 -0
  6. package/dist/build.d.ts.map +1 -0
  7. package/dist/build.js +92 -0
  8. package/dist/build.js.map +1 -0
  9. package/dist/cli.d.ts +3 -0
  10. package/dist/cli.d.ts.map +1 -0
  11. package/dist/cli.js +397 -0
  12. package/dist/cli.js.map +1 -0
  13. package/dist/config.d.ts +26 -0
  14. package/dist/config.d.ts.map +1 -0
  15. package/dist/config.js +105 -0
  16. package/dist/config.js.map +1 -0
  17. package/dist/fs/fileWriter.d.ts +100 -0
  18. package/dist/fs/fileWriter.d.ts.map +1 -0
  19. package/dist/fs/fileWriter.js +342 -0
  20. package/dist/fs/fileWriter.js.map +1 -0
  21. package/dist/fs/treeManager.d.ts +84 -0
  22. package/dist/fs/treeManager.d.ts.map +1 -0
  23. package/dist/fs/treeManager.js +365 -0
  24. package/dist/fs/treeManager.js.map +1 -0
  25. package/dist/fs/watcher.d.ts +39 -0
  26. package/dist/fs/watcher.d.ts.map +1 -0
  27. package/dist/fs/watcher.js +120 -0
  28. package/dist/fs/watcher.js.map +1 -0
  29. package/dist/index.d.ts +61 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +349 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/ipc/httpPolling.d.ts +56 -0
  34. package/dist/ipc/httpPolling.d.ts.map +1 -0
  35. package/dist/ipc/httpPolling.js +171 -0
  36. package/dist/ipc/httpPolling.js.map +1 -0
  37. package/dist/ipc/messages.d.ts +112 -0
  38. package/dist/ipc/messages.d.ts.map +1 -0
  39. package/dist/ipc/messages.js +5 -0
  40. package/dist/ipc/messages.js.map +1 -0
  41. package/dist/ipc/server.d.ts +50 -0
  42. package/dist/ipc/server.d.ts.map +1 -0
  43. package/dist/ipc/server.js +168 -0
  44. package/dist/ipc/server.js.map +1 -0
  45. package/dist/pack.d.ts +19 -0
  46. package/dist/pack.d.ts.map +1 -0
  47. package/dist/pack.js +225 -0
  48. package/dist/pack.js.map +1 -0
  49. package/dist/push.d.ts +43 -0
  50. package/dist/push.d.ts.map +1 -0
  51. package/dist/push.js +532 -0
  52. package/dist/push.js.map +1 -0
  53. package/dist/rojo.d.ts +9 -0
  54. package/dist/rojo.d.ts.map +1 -0
  55. package/dist/rojo.js +114 -0
  56. package/dist/rojo.js.map +1 -0
  57. package/dist/snapshot/rojo.d.ts +39 -0
  58. package/dist/snapshot/rojo.d.ts.map +1 -0
  59. package/dist/snapshot/rojo.js +364 -0
  60. package/dist/snapshot/rojo.js.map +1 -0
  61. package/dist/snapshot.d.ts +23 -0
  62. package/dist/snapshot.d.ts.map +1 -0
  63. package/dist/snapshot.js +132 -0
  64. package/dist/snapshot.js.map +1 -0
  65. package/dist/sourcemap/generator.d.ts +78 -0
  66. package/dist/sourcemap/generator.d.ts.map +1 -0
  67. package/dist/sourcemap/generator.js +351 -0
  68. package/dist/sourcemap/generator.js.map +1 -0
  69. package/dist/sourcemap/propertyLoader.d.ts +19 -0
  70. package/dist/sourcemap/propertyLoader.d.ts.map +1 -0
  71. package/dist/sourcemap/propertyLoader.js +131 -0
  72. package/dist/sourcemap/propertyLoader.js.map +1 -0
  73. package/dist/util/id.d.ts +9 -0
  74. package/dist/util/id.d.ts.map +1 -0
  75. package/dist/util/id.js +14 -0
  76. package/dist/util/id.js.map +1 -0
  77. package/dist/util/log.d.ts +13 -0
  78. package/dist/util/log.d.ts.map +1 -0
  79. package/dist/util/log.js +51 -0
  80. package/dist/util/log.js.map +1 -0
  81. package/docs/assets/azul-logo.pdn +0 -0
  82. package/docs/assets/logo-200px.png +0 -0
  83. package/docs/assets/logo.png +0 -0
  84. package/docs/assets/plugin/toolbox.png +0 -0
  85. package/docs/assets/synced.png +0 -0
  86. package/package.json +41 -0
  87. package/plugin/README.md +54 -0
  88. package/plugin/sourcemap.json +264 -0
  89. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/Actor/AzulSync.server.luau +905 -0
  90. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/AzulService.luau +1010 -0
  91. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/Config.luau +29 -0
  92. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/Enums.luau +11 -0
  93. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/CollapsibleTitledSection.luau +214 -0
  94. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/ColorPicker.luau +360 -0
  95. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/CustomTextButton.luau +170 -0
  96. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/DropdownMenu.luau +363 -0
  97. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/HorizontalLine.luau +43 -0
  98. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/ImageButtonWithText.luau +181 -0
  99. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledCheckbox.luau +295 -0
  100. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledColorInputPicker.luau +294 -0
  101. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledMultiChoice.luau +163 -0
  102. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledNumberInput.luau +312 -0
  103. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledRadioButton.luau +55 -0
  104. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledSlider.luau +151 -0
  105. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledTextInput.luau +222 -0
  106. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledToggleButton.luau +73 -0
  107. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/StatefulImageButton.luau +125 -0
  108. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/VerticalScrollingFrame.luau +100 -0
  109. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/VerticalSpacer.luau +35 -0
  110. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/VerticallyScalingListFrame.luau +107 -0
  111. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/GuiUtilities.luau +429 -0
  112. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/RbxGui.luau +4363 -0
  113. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/UI.luau +425 -0
  114. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/WebSocketClient.luau +161 -0
  115. package/src/build.ts +120 -0
  116. package/src/cli.ts +496 -0
  117. package/src/config.ts +170 -0
  118. package/src/fs/fileWriter.ts +414 -0
  119. package/src/fs/treeManager.ts +458 -0
  120. package/src/fs/watcher.ts +142 -0
  121. package/src/index.ts +450 -0
  122. package/src/ipc/httpPolling.ts +214 -0
  123. package/src/ipc/messages.ts +159 -0
  124. package/src/ipc/server.ts +196 -0
  125. package/src/pack.ts +309 -0
  126. package/src/push.ts +726 -0
  127. package/src/snapshot/rojo.ts +467 -0
  128. package/src/snapshot.ts +161 -0
  129. package/src/sourcemap/generator.ts +504 -0
  130. package/src/sourcemap/propertyLoader.ts +195 -0
  131. package/src/util/id.ts +15 -0
  132. package/src/util/log.ts +94 -0
  133. package/tsconfig.json +24 -0
@@ -0,0 +1,131 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { randomUUID } from "node:crypto";
4
+ import { log } from "../util/log.js";
5
+ const pathClassKey = (segments, className) => `${segments.join("\u0001")}::${className}`;
6
+ export function loadSourcemapPropertyIndex(sourcemapPath) {
7
+ const resolved = path.resolve(sourcemapPath);
8
+ if (!fs.existsSync(resolved)) {
9
+ log.debug(`No sourcemap found at ${resolved}; skipping property merge.`);
10
+ return null;
11
+ }
12
+ let root;
13
+ try {
14
+ const raw = fs.readFileSync(resolved, "utf8");
15
+ root = JSON.parse(raw);
16
+ }
17
+ catch (error) {
18
+ log.warn(`Failed to read sourcemap at ${resolved}: ${error}`);
19
+ return null;
20
+ }
21
+ const byGuid = new Map();
22
+ const byPathClass = new Map();
23
+ const visit = (node, currentPath) => {
24
+ const nodePath = [...currentPath, node.name];
25
+ if (node.guid) {
26
+ byGuid.set(node.guid, node);
27
+ }
28
+ const key = pathClassKey(nodePath, node.className);
29
+ const bucket = byPathClass.get(key) ?? [];
30
+ bucket.push(node);
31
+ byPathClass.set(key, bucket);
32
+ for (const child of node.children ?? []) {
33
+ visit(child, nodePath);
34
+ }
35
+ };
36
+ for (const child of root.children ?? []) {
37
+ visit(child, []);
38
+ }
39
+ return { byGuid, byPathClass };
40
+ }
41
+ export function applySourcemapProperties(instances, index) {
42
+ if (!index)
43
+ return 0;
44
+ let applied = 0;
45
+ for (const instance of instances) {
46
+ const match = findNodeForInstance(instance, index);
47
+ if (!match)
48
+ continue;
49
+ const hasProps = match.properties && Object.keys(match.properties).length > 0;
50
+ const hasAttrs = match.attributes && Object.keys(match.attributes).length > 0;
51
+ if (!hasProps && !hasAttrs)
52
+ continue;
53
+ if (hasProps) {
54
+ instance.properties = match.properties;
55
+ }
56
+ if (hasAttrs) {
57
+ instance.attributes = match.attributes;
58
+ }
59
+ applied += 1;
60
+ }
61
+ return applied;
62
+ }
63
+ export function buildInstancesFromSourcemap(sourcemapPath) {
64
+ const resolved = path.resolve(sourcemapPath);
65
+ if (!fs.existsSync(resolved)) {
66
+ log.warn(`Sourcemap not found at ${resolved}`);
67
+ return null;
68
+ }
69
+ let root;
70
+ try {
71
+ const raw = fs.readFileSync(resolved, "utf8");
72
+ root = JSON.parse(raw);
73
+ }
74
+ catch (error) {
75
+ log.error(`Failed to parse sourcemap at ${resolved}: ${error}`);
76
+ return null;
77
+ }
78
+ const results = [];
79
+ const visit = (node, currentPath, parentGuid) => {
80
+ const nodePath = [...currentPath, node.name];
81
+ const guid = node.guid ?? randomUUID().replace(/-/g, "");
82
+ const instance = {
83
+ guid,
84
+ className: node.className,
85
+ name: node.name,
86
+ path: nodePath,
87
+ parentGuid,
88
+ };
89
+ if (node.properties)
90
+ instance.properties = node.properties;
91
+ if (node.attributes)
92
+ instance.attributes = node.attributes;
93
+ const isScript = node.className === "Script" ||
94
+ node.className === "LocalScript" ||
95
+ node.className === "ModuleScript";
96
+ if (isScript && node.filePaths && node.filePaths.length > 0) {
97
+ const scriptPath = path.resolve(process.cwd(), node.filePaths[0]);
98
+ try {
99
+ instance.source = fs.readFileSync(scriptPath, "utf8");
100
+ }
101
+ catch (error) {
102
+ log.warn(`Failed to read script file for ${nodePath.join("/")}: ${error}`);
103
+ }
104
+ }
105
+ results.push(instance);
106
+ for (const child of node.children ?? []) {
107
+ visit(child, nodePath, guid);
108
+ }
109
+ };
110
+ for (const child of root.children ?? []) {
111
+ visit(child, []);
112
+ }
113
+ results.sort((a, b) => a.path.length - b.path.length);
114
+ return results;
115
+ }
116
+ function findNodeForInstance(instance, index) {
117
+ if (instance.guid) {
118
+ const byGuid = index.byGuid.get(instance.guid);
119
+ if (byGuid)
120
+ return byGuid;
121
+ }
122
+ const key = pathClassKey(instance.path, instance.className);
123
+ const bucket = index.byPathClass.get(key);
124
+ if (!bucket || bucket.length === 0)
125
+ return null;
126
+ if (bucket.length === 1)
127
+ return bucket[0];
128
+ // Prefer a node that also carries a guid to reduce ambiguity
129
+ return bucket.find((node) => Boolean(node.guid)) ?? bucket[0];
130
+ }
131
+ //# sourceMappingURL=propertyLoader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"propertyLoader.js","sourceRoot":"","sources":["../../src/sourcemap/propertyLoader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Generate a unique GUID for tracking instances
3
+ */
4
+ export declare function generateGUID(): string;
5
+ /**
6
+ * Validate GUID format
7
+ */
8
+ export declare function isValidGUID(guid: string): boolean;
9
+ //# sourceMappingURL=id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"id.d.ts","sourceRoot":"","sources":["../../src/util/id.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD"}
@@ -0,0 +1,14 @@
1
+ import { randomBytes } from "crypto";
2
+ /**
3
+ * Generate a unique GUID for tracking instances
4
+ */
5
+ export function generateGUID() {
6
+ return randomBytes(16).toString("hex");
7
+ }
8
+ /**
9
+ * Validate GUID format
10
+ */
11
+ export function isValidGUID(guid) {
12
+ return /^[a-f0-9]{32}$/.test(guid);
13
+ }
14
+ //# sourceMappingURL=id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"id.js","sourceRoot":"","sources":["../../src/util/id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAErC;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrC,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Simple logging utility with color support
3
+ */
4
+ export declare const log: {
5
+ info(message: string, ...args: any[]): void;
6
+ success(message: string, ...args: any[]): void;
7
+ warn(message: string, ...args: any[]): void;
8
+ error(message: string, ...args: any[]): void;
9
+ debug(message: string, ...args: any[]): void;
10
+ userInput(message: string, ...args: any[]): void;
11
+ script(path: string, action: "created" | "updated" | "deleted"): void;
12
+ };
13
+ //# sourceMappingURL=log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/util/log.ts"],"names":[],"mappings":"AAAA;;GAEG;AAsBH,eAAO,MAAM,GAAG;kBACA,MAAM,WAAW,GAAG,EAAE,GAAG,IAAI;qBAS1B,MAAM,WAAW,GAAG,EAAE,GAAG,IAAI;kBAShC,MAAM,WAAW,GAAG,EAAE,GAAG,IAAI;mBAS5B,MAAM,WAAW,GAAG,EAAE,GAAG,IAAI;mBAS7B,MAAM,WAAW,GAAG,EAAE,GAAG,IAAI;uBASzB,MAAM,WAAW,GAAG,EAAE,GAAG,IAAI;iBASnC,MAAM,UAAU,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,IAAI;CActE,CAAC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Simple logging utility with color support
3
+ */
4
+ import { config } from "../config.js";
5
+ const colors = {
6
+ reset: "\x1b[0m",
7
+ bright: "\x1b[1m",
8
+ dim: "\x1b[2m",
9
+ red: "\x1b[31m",
10
+ green: "\x1b[32m",
11
+ yellow: "\x1b[33m",
12
+ blue: "\x1b[34m",
13
+ magenta: "\x1b[35m",
14
+ cyan: "\x1b[36m",
15
+ white: "\x1b[37m",
16
+ };
17
+ function timestamp() {
18
+ return new Date().toISOString().slice(11, 23);
19
+ }
20
+ export const log = {
21
+ info(message, ...args) {
22
+ console.log(`${colors.dim}[${timestamp()}]${colors.reset} ${colors.blue}ℹ${colors.reset} ${message}`, ...args);
23
+ },
24
+ success(message, ...args) {
25
+ console.log(`${colors.dim}[${timestamp()}]${colors.reset} ${colors.green}✓${colors.reset} ${message}`, ...args);
26
+ },
27
+ warn(message, ...args) {
28
+ console.log(`${colors.dim}[${timestamp()}]${colors.reset} ${colors.yellow}⚠${colors.reset} ${message}`, ...args);
29
+ },
30
+ error(message, ...args) {
31
+ console.error(`${colors.dim}[${timestamp()}]${colors.reset} ${colors.red}✗${colors.reset} ${message}`, ...args);
32
+ },
33
+ debug(message, ...args) {
34
+ if (config.debugMode) {
35
+ console.log(`${colors.dim}[${timestamp()}] 🔍 ${message}${colors.reset}`, ...args);
36
+ }
37
+ },
38
+ userInput(message, ...args) {
39
+ console.log(`${colors.dim}[${timestamp()}]${colors.reset} ${colors.cyan}?${colors.reset} ${message}`, ...args);
40
+ },
41
+ script(path, action) {
42
+ const emoji = action === "created" ? "+" : action === "updated" ? "~" : "−";
43
+ const color = action === "created"
44
+ ? colors.green
45
+ : action === "updated"
46
+ ? colors.yellow
47
+ : colors.red;
48
+ console.log(`${colors.dim}[${timestamp()}]${colors.reset} ${color}${emoji}${colors.reset} ${path}`);
49
+ },
50
+ };
51
+ //# sourceMappingURL=log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/util/log.ts"],"names":[],"mappings":"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"}
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "azul-sync",
3
+ "version": "1.3.0",
4
+ "description": "Azul is a two-way synchronization tool between Roblox Studio and your local filesystem, with full IntelliSense support.",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "azul": "./dist/cli.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsx watch src/index.ts",
13
+ "start": "node dist/index.js",
14
+ "clean": "rimraf dist",
15
+ "prepack": "npm run build",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "engines": {
19
+ "node": ">=20"
20
+ },
21
+ "keywords": [
22
+ "roblox",
23
+ "studio",
24
+ "sync",
25
+ "luau",
26
+ "lsp",
27
+ "rojo"
28
+ ],
29
+ "author": "",
30
+ "license": "MIT",
31
+ "dependencies": {
32
+ "ws": "^8.16.0",
33
+ "chokidar": "^3.5.3"
34
+ },
35
+ "devDependencies": {
36
+ "@types/node": "^20.11.0",
37
+ "@types/ws": "^8.5.10",
38
+ "tsx": "^4.7.0",
39
+ "typescript": "^5.3.3"
40
+ }
41
+ }
@@ -0,0 +1,54 @@
1
+ # <span><img src="/docs/assets/logo.png" alt="Azul Logo" height="30"></span> Azul Companion Plugin
2
+
3
+ ## Installation
4
+
5
+ ### Method 1: Automatic via Roblox Marketplace (Recommended)
6
+
7
+ 1. Install the plugin automatically using the Roblox Plugin Marketplace: https://create.roblox.com/store/asset/79510309341601/Azul-Companion-Plugin
8
+
9
+ > If the plugin does not show up, follow the [troubleshooting steps](#troubleshooting).
10
+
11
+ ### Method 2: Manual Install via Place File
12
+
13
+ 1. Download the source code from the [Azul Companion Plugin](https://www.roblox.com/games/132762411481199/Azul-Companion-Plugin) place: (3 dots (⋯) > "Download")
14
+ 2. Open the downloaded `.rbxlx` or `.rbxl` file in Roblox Studio
15
+ 3. Right-click the `AzulCompanionPlugin` folder in `ReplicatedFirst` and select **"Save as Local Plugin"**
16
+ 4. Restart Roblox Studio
17
+ 5. The Azul icon should now appear in the toolbar
18
+
19
+ ### Method 3: Build via Azul
20
+
21
+ In case you wish to help maintain the plugin or want to customize it, you can build the Plugin project yourself using Azul:
22
+
23
+ ```ps1
24
+ cd plugin
25
+ azul build --from-sourcemap .\sourcemap.json
26
+ ```
27
+
28
+ ## Troubleshooting
29
+
30
+ ### Plugin not showing up
31
+
32
+ Roblox is very particular about how plugins are installed. Sometimes, just "getting" the plugin from the marketplace isn't enough. Try the following steps:
33
+
34
+ 1. Restart Roblox Studio
35
+ 2. Open any game (or create a new one)
36
+ 3. Go to **Toolbox** > **Inventory**<br/>
37
+ ![alt text](../docs/assets/plugin/toolbox.png)
38
+ 4. In the dropdown, select **My Plugins**
39
+ 5. Locate the Azul Companion Plugin and click **Install**
40
+ 6. The Azul icon should now appear in the toolbar
41
+
42
+ ### Plugin not connecting
43
+
44
+ - Ensure the daemon is running (run `azul`)
45
+ - Check that `HttpService` is enabled:
46
+ - Go to **Home** → **Game Settings** → **Security**
47
+ - Enable **"Allow HTTP Requests"**
48
+ - Verify firewall isn't blocking port 8080
49
+
50
+ ### Scripts not syncing
51
+
52
+ - Click "Toggle Sync" to reconnect
53
+ - Check the Output window for error messages
54
+ - Restart both the daemon and Studio
@@ -0,0 +1,264 @@
1
+ {
2
+ "name": "Game",
3
+ "className": "DataModel",
4
+ "children": [
5
+ {
6
+ "name": "ReplicatedFirst",
7
+ "className": "ReplicatedFirst",
8
+ "guid": "7204",
9
+ "children": [
10
+ {
11
+ "name": "AzulCompanionPlugin",
12
+ "className": "Folder",
13
+ "guid": "9427",
14
+ "children": [
15
+ {
16
+ "name": "Actor",
17
+ "className": "Actor",
18
+ "guid": "9401",
19
+ "children": [
20
+ {
21
+ "name": "AzulSync",
22
+ "className": "Script",
23
+ "guid": "11066",
24
+ "filePaths": [
25
+ "sync/ReplicatedFirst/AzulCompanionPlugin/Actor/AzulSync.server.luau"
26
+ ],
27
+ "properties": {
28
+ "RunContext": {
29
+ "__type": "EnumItem",
30
+ "enumType": "RunContext",
31
+ "name": "Plugin"
32
+ }
33
+ }
34
+ }
35
+ ]
36
+ },
37
+ {
38
+ "name": "AzulService",
39
+ "className": "ModuleScript",
40
+ "guid": "9574",
41
+ "filePaths": [
42
+ "sync/ReplicatedFirst/AzulCompanionPlugin/AzulService.luau"
43
+ ]
44
+ },
45
+ {
46
+ "name": "Config",
47
+ "className": "ModuleScript",
48
+ "guid": "9573",
49
+ "filePaths": [
50
+ "sync/ReplicatedFirst/AzulCompanionPlugin/Config.luau"
51
+ ]
52
+ },
53
+ {
54
+ "name": "Enums",
55
+ "className": "ModuleScript",
56
+ "guid": "9572",
57
+ "filePaths": [
58
+ "sync/ReplicatedFirst/AzulCompanionPlugin/Enums.luau"
59
+ ]
60
+ },
61
+ {
62
+ "name": "StudioWidgets",
63
+ "className": "Folder",
64
+ "guid": "9428",
65
+ "children": [
66
+ {
67
+ "name": "Components",
68
+ "className": "Folder",
69
+ "guid": "9429",
70
+ "children": [
71
+ {
72
+ "name": "CollapsibleTitledSection",
73
+ "className": "ModuleScript",
74
+ "guid": "9565",
75
+ "filePaths": [
76
+ "sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/CollapsibleTitledSection.luau"
77
+ ]
78
+ },
79
+ {
80
+ "name": "ColorPicker",
81
+ "className": "ModuleScript",
82
+ "guid": "9564",
83
+ "filePaths": [
84
+ "sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/ColorPicker.luau"
85
+ ]
86
+ },
87
+ {
88
+ "name": "CustomTextButton",
89
+ "className": "ModuleScript",
90
+ "guid": "9562",
91
+ "filePaths": [
92
+ "sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/CustomTextButton.luau"
93
+ ]
94
+ },
95
+ {
96
+ "name": "DropdownMenu",
97
+ "className": "ModuleScript",
98
+ "guid": "9569",
99
+ "filePaths": [
100
+ "sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/DropdownMenu.luau"
101
+ ]
102
+ },
103
+ {
104
+ "name": "HorizontalLine",
105
+ "className": "ModuleScript",
106
+ "guid": "9568",
107
+ "filePaths": [
108
+ "sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/HorizontalLine.luau"
109
+ ]
110
+ },
111
+ {
112
+ "name": "ImageButtonWithText",
113
+ "className": "ModuleScript",
114
+ "guid": "9570",
115
+ "filePaths": [
116
+ "sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/ImageButtonWithText.luau"
117
+ ]
118
+ },
119
+ {
120
+ "name": "LabeledCheckbox",
121
+ "className": "ModuleScript",
122
+ "guid": "9563",
123
+ "filePaths": [
124
+ "sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledCheckbox.luau"
125
+ ]
126
+ },
127
+ {
128
+ "name": "LabeledColorInputPicker",
129
+ "className": "ModuleScript",
130
+ "guid": "9566",
131
+ "filePaths": [
132
+ "sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledColorInputPicker.luau"
133
+ ]
134
+ },
135
+ {
136
+ "name": "LabeledMultiChoice",
137
+ "className": "ModuleScript",
138
+ "guid": "9561",
139
+ "filePaths": [
140
+ "sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledMultiChoice.luau"
141
+ ]
142
+ },
143
+ {
144
+ "name": "LabeledNumberInput",
145
+ "className": "ModuleScript",
146
+ "guid": "9556",
147
+ "filePaths": [
148
+ "sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledNumberInput.luau"
149
+ ]
150
+ },
151
+ {
152
+ "name": "LabeledRadioButton",
153
+ "className": "ModuleScript",
154
+ "guid": "9555",
155
+ "filePaths": [
156
+ "sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledRadioButton.luau"
157
+ ]
158
+ },
159
+ {
160
+ "name": "LabeledSlider",
161
+ "className": "ModuleScript",
162
+ "guid": "9554",
163
+ "filePaths": [
164
+ "sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledSlider.luau"
165
+ ]
166
+ },
167
+ {
168
+ "name": "LabeledTextInput",
169
+ "className": "ModuleScript",
170
+ "guid": "9557",
171
+ "filePaths": [
172
+ "sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledTextInput.luau"
173
+ ]
174
+ },
175
+ {
176
+ "name": "LabeledToggleButton",
177
+ "className": "ModuleScript",
178
+ "guid": "9559",
179
+ "filePaths": [
180
+ "sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledToggleButton.luau"
181
+ ]
182
+ },
183
+ {
184
+ "name": "StatefulImageButton",
185
+ "className": "ModuleScript",
186
+ "guid": "9558",
187
+ "filePaths": [
188
+ "sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/StatefulImageButton.luau"
189
+ ]
190
+ },
191
+ {
192
+ "name": "VerticallyScalingListFrame",
193
+ "className": "ModuleScript",
194
+ "guid": "9560",
195
+ "filePaths": [
196
+ "sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/VerticallyScalingListFrame.luau"
197
+ ]
198
+ },
199
+ {
200
+ "name": "VerticalScrollingFrame",
201
+ "className": "ModuleScript",
202
+ "guid": "9567",
203
+ "filePaths": [
204
+ "sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/VerticalScrollingFrame.luau"
205
+ ]
206
+ },
207
+ {
208
+ "name": "VerticalSpacer",
209
+ "className": "ModuleScript",
210
+ "guid": "9571",
211
+ "filePaths": [
212
+ "sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/VerticalSpacer.luau"
213
+ ]
214
+ }
215
+ ]
216
+ },
217
+ {
218
+ "name": "GuiUtilities",
219
+ "className": "ModuleScript",
220
+ "guid": "9553",
221
+ "filePaths": [
222
+ "sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/GuiUtilities.luau"
223
+ ]
224
+ },
225
+ {
226
+ "name": "RbxGui",
227
+ "className": "ModuleScript",
228
+ "guid": "9552",
229
+ "filePaths": [
230
+ "sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/RbxGui.luau"
231
+ ]
232
+ }
233
+ ]
234
+ },
235
+ {
236
+ "name": "UI",
237
+ "className": "ModuleScript",
238
+ "guid": "9550",
239
+ "filePaths": [
240
+ "sync/ReplicatedFirst/AzulCompanionPlugin/UI.luau"
241
+ ]
242
+ },
243
+ {
244
+ "name": "WebSocketClient",
245
+ "className": "ModuleScript",
246
+ "guid": "9551",
247
+ "filePaths": [
248
+ "sync/ReplicatedFirst/AzulCompanionPlugin/WebSocketClient.luau"
249
+ ]
250
+ }
251
+ ]
252
+ }
253
+ ],
254
+ "properties": {
255
+ "Archivable": true
256
+ }
257
+ }
258
+ ],
259
+ "_azul": {
260
+ "packVersion": 1,
261
+ "packedAt": "2026-02-26T23:51:44.029Z",
262
+ "mode": "all"
263
+ }
264
+ }