@rbxts/app-forge 0.0.3 → 0.0.5

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 (2) hide show
  1. package/README.md +316 -0
  2. package/package.json +57 -57
package/README.md CHANGED
@@ -0,0 +1,316 @@
1
+ # AppForge — React App & Window Manager for roblox-ts
2
+
3
+ AppForge is a UI/app orchestration system for React in Roblox, enabling:
4
+
5
+ ✔ App registration
6
+ ✔ Visibility & state control
7
+ ✔ App grouping
8
+ ✔ Exclusive UI modes
9
+ ✔ Rule-based interactions
10
+ ✔ Priority & layering
11
+ ✔ React-friendly state bindings
12
+
13
+ ---
14
+
15
+ # 📦 Installation
16
+
17
+ ```bash
18
+ npm i @rbxts/app-forge
19
+ # or
20
+ bun i @rbxts/app-forge
21
+ ```
22
+
23
+ ---
24
+
25
+ # 🧩 Setup — REQUIRED
26
+
27
+ ### Create `global.d.ts`
28
+
29
+ ```ts
30
+ declare global {
31
+ // All registered Apps by name
32
+ type AppNames = readonly ["HUD", "Inventory", "Shop", "SideButtons", "Pause"];
33
+
34
+ // Logical groupings of apps
35
+ type AppGroups = readonly ["HUD", "Panel", "Overlay"];
36
+
37
+ // Props that are injected into each App
38
+ interface AppProps {
39
+ player: Player;
40
+ target: GuiObject | Camera;
41
+ playerData: any;
42
+ events: any;
43
+ appManager: import("@rbxts/app-forge").default;
44
+ }
45
+
46
+ export {};
47
+ }
48
+ ```
49
+
50
+ > AppForge will now use your AppNames & AppProps as typed globals.
51
+
52
+ ---
53
+
54
+ # 🚀 Initializing AppForge
55
+
56
+ ```ts
57
+ import AppManager, { Render } from "@rbxts/app-forge";
58
+ import { createPortal, createRoot } from "@rbxts/react-roblox";
59
+ import React from "@rbxts/react";
60
+
61
+ const manager = new AppManager();
62
+ const root = createRoot(new Instance("Folder"));
63
+
64
+ const props: AppProps = {
65
+ player: Players.LocalPlayer!,
66
+ target: new Instance("Folder"),
67
+ playerData: {},
68
+ events: {},
69
+ appManager: manager,
70
+ };
71
+
72
+ root.render(
73
+ createPortal(
74
+ <screengui ResetOnSpawn={false} ZIndexBehavior="Sibling">
75
+ <Render props={props} manager={manager} />
76
+ </screengui>,
77
+ Players.LocalPlayer!.WaitForChild("PlayerGui"),
78
+ ),
79
+ );
80
+ ```
81
+
82
+ > `Render` will automatically render ALL registered apps.
83
+
84
+ ---
85
+
86
+ # 🧱 Creating an App
87
+
88
+ ```ts
89
+ import { App, Args } from "@rbxts/app-forge";
90
+ import React from "@rbxts/react";
91
+
92
+ @App({
93
+ name: "SideButtons",
94
+ visible: true,
95
+ })
96
+ export default class SideButtons extends Args {
97
+ render() {
98
+ return (
99
+ <frame Size={UDim2.fromScale(1, 1)}>Side Buttons UI</frame>
100
+ );
101
+ }
102
+ }
103
+ ```
104
+
105
+ ### ❗ Note
106
+
107
+ `Args` automatically injects AppProps into `this`, such as:
108
+
109
+ ```ts
110
+ this.props
111
+ ```
112
+
113
+ You never manually `new` apps — AppForge constructs them automatically.
114
+
115
+ ---
116
+
117
+ # 🕹 App Manager API
118
+
119
+ ```ts
120
+ appManager.toggle("Inventory");
121
+ appManager.set("Shop", true);
122
+ appManager.set("HUD", false);
123
+ const isShown = appManager.getState("Pause");
124
+ const bind = appManager.getBind("Inventory");
125
+ ```
126
+
127
+ ---
128
+
129
+ # 📐 Using `getBind()` in React
130
+
131
+ ```tsx
132
+ return (
133
+ <frame Visible={props.appManager.getBind("Inventory")}>
134
+ Items…
135
+ </frame>
136
+ );
137
+ ```
138
+
139
+ Binds re-render automatically on visibility change.
140
+
141
+ ---
142
+
143
+ # ⌨️ Hotkey Toggle Example
144
+
145
+ ```ts
146
+ UserInputService.InputBegan.Connect((input) => {
147
+ if (input.KeyCode === Enum.KeyCode.I)
148
+ appManager.toggle("Inventory");
149
+ });
150
+ ```
151
+
152
+ ---
153
+
154
+ # ⚖️ APP RULES SYSTEM
155
+
156
+ Rules control UI interaction & visibility behavior.
157
+
158
+ | Rule | Effect |
159
+ |---|---|
160
+ | blockedBy | Prevents opening if another app is active |
161
+ | blocks | Auto-closes another app when opened |
162
+ | exclusive | Closes ALL other apps except same group |
163
+ | groups | Logical grouping categories |
164
+ | layer | (Coming soon — currently not functional) |
165
+
166
+ ---
167
+
168
+ ## `blockedBy`
169
+
170
+ App cannot open if the listed apps are open.
171
+
172
+ ```ts
173
+ @App({ name: "Inventory", rules: { blockedBy: "Shop" } })
174
+ ```
175
+
176
+ Multiple:
177
+
178
+ ```ts
179
+ @App({ name: "Inventory", rules: { blockedBy: ["Shop", "Trade"] } })
180
+ ```
181
+
182
+ ---
183
+
184
+ ## `blocks`
185
+
186
+ Opening the app will hide other apps.
187
+
188
+ ```ts
189
+ @App({ name: "Shop", rules: { blocks: "Inventory" } })
190
+ ```
191
+
192
+ Multiple:
193
+
194
+ ```ts
195
+ @App({ name: "Shop", rules: { blocks: ["Inventory", "TeamUI"] } })
196
+ ```
197
+
198
+ ---
199
+
200
+ ## `exclusive`
201
+
202
+ For fullscreen apps:
203
+
204
+ ```ts
205
+ @App({ name: "Pause", rules: { exclusive: true } })
206
+ ```
207
+
208
+ When Pause opens:
209
+
210
+ ✔ Inventory closes
211
+ ✔ HUD closes
212
+ ✔ SideButtons closes
213
+ ✔ Everything except Core
214
+
215
+ ---
216
+
217
+ ## `groups`
218
+
219
+ Apps inside the same group DO NOT block each other.
220
+
221
+ ```ts
222
+ @App({ name: "HUD", rules: { groups: ["HUD"] } })
223
+ @App({ name: "Crosshair", rules: { groups: ["HUD"] } })
224
+ ```
225
+
226
+ These can both be open at the same time.
227
+
228
+ ---
229
+
230
+ ## `Core` Group
231
+
232
+ Core apps are ALWAYS allowed and never auto-hidden.
233
+
234
+ ```ts
235
+ @App({ name: "FPSCounter", rules: { groups: "Core" } })
236
+ ```
237
+
238
+ This app will NEVER be closed by rules.
239
+
240
+ ---
241
+
242
+ ## `layer` *(not implemented yet)*
243
+
244
+ > The `layer` property is part of the upcoming UI priority system.
245
+ > Setting it currently does not affect rendering order.
246
+
247
+ Example (for future readiness):
248
+
249
+ ```ts
250
+ @App({ name: "DebugUI", rules: { layer: 999 } })
251
+ ```
252
+
253
+ ---
254
+
255
+ # 🧪 Full Rules Example
256
+
257
+ ```ts
258
+ @App({ name: "HUD", rules: { groups: ["HUD"] } })
259
+ @App({ name: "Inventory", rules: { blockedBy: "Shop", groups: ["Panel"] } })
260
+ @App({ name: "Shop", rules: { blocks: "Inventory", groups: ["Panel"] } })
261
+ @App({ name: "Pause", rules: { exclusive: true } })
262
+ @App({ name: "FPSCounter", rules: { groups: "Core" } })
263
+ ```
264
+
265
+ Behavior:
266
+
267
+ | Action | Result |
268
+ | -------------- | -------------------------------- |
269
+ | Open Inventory | HUD + FPS stay |
270
+ | Open Shop | Inventory closes |
271
+ | Open Pause | ALL apps close except Core |
272
+ | Open HUD | Never conflicts with SideButtons |
273
+ | FPSCounter | Always visible |
274
+
275
+ ---
276
+
277
+ # 🧠 Using AppForge in UI Components
278
+
279
+ ```tsx
280
+ function MenuUI(props: AppProps) {
281
+ return (
282
+ <frame Visible={props.appManager.getBind("Shop")}>
283
+ Shop UI…
284
+ </frame>
285
+ );
286
+ }
287
+ ```
288
+
289
+ ---
290
+
291
+ # ❗ Best Practices
292
+
293
+ ✔ Use `groups` for UI coexistence
294
+ ✔ Use `exclusive` for fullscreen menus
295
+ ✔ Use `blockedBy` for preventing conflicts
296
+ ✔ Use `blocks` for auto-closing logic
297
+ ✔ Use `Core` for never-closed apps
298
+ ✔ Use `layer` for future-proofing (not active yet)
299
+
300
+ ---
301
+
302
+ # 🛠 Future Roadmap
303
+
304
+ - [ ] layer / priority rendering
305
+
306
+ ---
307
+
308
+ # ❤️ Contributing
309
+
310
+ Feel free to submit PRs, suggestions, or feature requests.
311
+
312
+ ---
313
+
314
+ # 📄 License
315
+
316
+ MIT
package/package.json CHANGED
@@ -1,59 +1,59 @@
1
1
  {
2
- "name": "@rbxts/app-forge",
3
- "version": "0.0.3",
4
- "description": "An App Manager for react",
5
- "main": "out/init.lua",
6
- "packageManager": "bun@1.3.1",
7
- "scripts": {
8
- "build": "rbxtsc",
9
- "dev": "rbxtsc -w --type game --rojo test.project.json",
10
- "login": "bunx npm login --auth-type=legacy"
11
-
12
- },
13
- "keywords": [
14
- "roblox-ts",
15
- "react"
16
- ],
17
- "author": "loner1536",
18
- "license": "MIT",
19
- "repository": {
20
- "type": "git",
21
- "url": "https://github.com/Loner1536/AppForge"
22
- },
23
- "bugs": {
24
- "url": "https://github.com/Loner1536/AppForge/issues"
25
- },
26
- "types": "out/index.d.ts",
27
- "files": [
28
- "out",
29
- "!**/*.tsbuildinfo",
30
- "!**/*.spec.lua",
31
- "!**/*.spec.d.ts"
32
- ],
33
- "publishConfig": {
34
- "access": "public"
35
- },
36
- "devDependencies": {
37
- "@rbxts/compiler-types": "3.0.0-types.0",
38
- "@rbxts/react": "17.3.0-alpha.1",
39
- "@rbxts/react-roblox": "17.3.0-alpha.1",
40
- "@rbxts/types": "^1.0.891",
41
- "@typescript-eslint/eslint-plugin": "^8.46.4",
42
- "@typescript-eslint/parser": "^8.46.4",
43
- "roblox-ts": "3.0.0",
44
- "typescript": "^5.9.3"
45
- },
46
- "dependencies": {
47
- "@rbxts/charm": "^0.10.0",
48
- "@rbxts/loners-pretty-react-hooks": "^0.0.3",
49
- "@rbxts/react-charm": "^0.3.0",
50
- "@rbxts/ripple": "^0.9.3",
51
- "@rbxts/services": "^1.6.0",
52
- "@rbxts/set-timeout": "^1.1.2"
53
- },
54
- "peerDependencies": {
55
- "@rbxts/object-utils": "*",
56
- "@rbxts/react-roblox": "*",
57
- "@rbxts/react": "*"
58
- }
2
+ "name": "@rbxts/app-forge",
3
+ "version": "0.0.5",
4
+ "description": "An App Manager for react",
5
+ "main": "out/init.lua",
6
+ "packageManager": "bun@1.3.1",
7
+ "scripts": {
8
+ "build": "rbxtsc",
9
+ "dev": "rbxtsc -w --type game --rojo test.project.json",
10
+ "login": "bunx npm login --auth-type=legacy"
11
+ },
12
+ "keywords": [
13
+ "roblox-ts",
14
+ "react"
15
+ ],
16
+ "author": "loner1536",
17
+ "license": "MIT",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/Loner1536/AppForge"
21
+ },
22
+ "bugs": {
23
+ "url": "https://github.com/Loner1536/AppForge/issues"
24
+ },
25
+ "types": "out/index.d.ts",
26
+ "files": [
27
+ "out",
28
+ "!**/*.tsbuildinfo",
29
+ "!**/*.spec.lua",
30
+ "!**/*.spec.d.ts"
31
+ ],
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "devDependencies": {
36
+ "@biomejs/biome": "^2.3.7",
37
+ "@rbxts/compiler-types": "3.0.0-types.0",
38
+ "@rbxts/react": "17.3.0-alpha.1",
39
+ "@rbxts/react-roblox": "17.3.0-alpha.1",
40
+ "@rbxts/types": "^1.0.891",
41
+ "@typescript-eslint/eslint-plugin": "^8.46.4",
42
+ "@typescript-eslint/parser": "^8.46.4",
43
+ "roblox-ts": "3.0.0",
44
+ "typescript": "^5.9.3"
45
+ },
46
+ "dependencies": {
47
+ "@rbxts/charm": "^0.10.0",
48
+ "@rbxts/loners-pretty-react-hooks": "^0.0.3",
49
+ "@rbxts/react-charm": "^0.3.0",
50
+ "@rbxts/ripple": "^0.9.3",
51
+ "@rbxts/services": "^1.6.0",
52
+ "@rbxts/set-timeout": "^1.1.2"
53
+ },
54
+ "peerDependencies": {
55
+ "@rbxts/object-utils": "*",
56
+ "@rbxts/react-roblox": "*",
57
+ "@rbxts/react": "*"
58
+ }
59
59
  }