@volter/browser-godot 0.1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Volter Browser Substrate contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,14 @@
1
+ # @volter/browser-godot
2
+
3
+ A structural, bidirectional bridge between the shared browser filesystem and a
4
+ Godot web editor whose Emscripten `FS` is exposed by the reproducible recipe in
5
+ `programs/godot-editor/4.7.2`.
6
+
7
+ - `GodotEditorEmbed` materializes a workspace into editor and game engine
8
+ instances and reopens safely when display scale changes.
9
+ - `GodotEditorBridge` mirrors atomic editor commits into the workspace and
10
+ workspace mutations into the editor, excluding `.agent` and `.godot` state.
11
+ - `addon/agent_bridge` asks the editor to rescan after inbound changes.
12
+
13
+ The package uses structural filesystem interfaces and imports no execution
14
+ engine. `examples/godot` is the terminal-plus-editor reference composition.
@@ -0,0 +1,7 @@
1
+ [plugin]
2
+
3
+ name="Agent Bridge"
4
+ description="Shared-workspace bridge: rescans the project filesystem when the runtime requests it."
5
+ author="Volter"
6
+ version="0.1"
7
+ script="plugin.gd"
@@ -0,0 +1,30 @@
1
+ @tool
2
+ extends EditorPlugin
3
+
4
+ # The web editor does not rescan on focus (desktop behavior absent on web),
5
+ # so external writes stay invisible until a scan runs. The runtime writes
6
+ # res://.agent/scan_request after committing files into the project; this
7
+ # poll consumes it and triggers the scan. Pure GDScript — the web editor
8
+ # supports no other extension mechanism (no GDExtension, no C#).
9
+
10
+ var timer: Timer
11
+
12
+
13
+ func _enter_tree() -> void:
14
+ timer = Timer.new()
15
+ timer.wait_time = 1.0
16
+ timer.timeout.connect(_poll)
17
+ add_child(timer)
18
+ timer.start()
19
+
20
+
21
+ func _exit_tree() -> void:
22
+ if timer:
23
+ timer.queue_free()
24
+ timer = null
25
+
26
+
27
+ func _poll() -> void:
28
+ if FileAccess.file_exists("res://.agent/scan_request"):
29
+ DirAccess.remove_absolute("res://.agent/scan_request")
30
+ EditorInterface.get_resource_filesystem().scan()
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Bidirectional file bridge between the workbench's live virtual filesystem
3
+ * and a running FS-exposed Godot web editor (built by
4
+ * scripts/build-godot-web-editor.sh).
5
+ *
6
+ * Both directions use the same method the chassis uses for AlmostNode→OPFS
7
+ * persistence: wrap the filesystem's mutation functions, keep the originals,
8
+ * filter by root, restore on dispose. The workspace side mirrors the
9
+ * VirtualFS method names structurally so a consumer can pass the live
10
+ * filesystem directly; this package deliberately imports nothing from the
11
+ * chassis or any execution engine.
12
+ *
13
+ * Outbound (editor → workspace): Godot commits files as write-to-temp then
14
+ * atomic rename, so a rename into a final path is a per-file commit point.
15
+ * Direct writes without a rename are flushed on a short debounce.
16
+ *
17
+ * Inbound (workspace → editor): bytes are applied to the editor's Emscripten
18
+ * FS immediately; a debounced `.agent/scan_request` write asks the in-project
19
+ * agent_bridge addon to rescan, because the web editor does not rescan on
20
+ * focus.
21
+ */
22
+ export interface BridgeWorkspace {
23
+ readFileSync(path: string): Uint8Array;
24
+ writeFileSync(path: string, data: Uint8Array): void;
25
+ mkdirSync(path: string, options?: {
26
+ recursive?: boolean;
27
+ }): void;
28
+ unlinkSync(path: string): void;
29
+ rmdirSync(path: string): void;
30
+ renameSync(from: string, to: string): void;
31
+ existsSync(path: string): boolean;
32
+ }
33
+ interface EmscriptenStream {
34
+ path?: string;
35
+ }
36
+ export interface EditorFilesystem {
37
+ readFile(path: string, options: {
38
+ encoding: "binary";
39
+ }): Uint8Array;
40
+ writeFile(path: string, data: Uint8Array): void;
41
+ write(stream: EmscriptenStream, ...rest: unknown[]): number;
42
+ mkdir(path: string, mode?: number): void;
43
+ unlink(path: string): void;
44
+ rmdir(path: string): void;
45
+ rename(from: string, to: string): void;
46
+ analyzePath(path: string): {
47
+ exists: boolean;
48
+ };
49
+ }
50
+ export interface GodotEditorBridgeOptions {
51
+ workspace: BridgeWorkspace;
52
+ /** Workspace-side project root, e.g. "/workspace". */
53
+ workspaceRoot: string;
54
+ editorFilesystem: EditorFilesystem;
55
+ /** Editor-side project root, e.g. "/home/web_user/new-game-project". */
56
+ editorRoot: string;
57
+ /**
58
+ * Path prefixes (relative to the project root) excluded from both
59
+ * directions. `.agent` is the bridge's own channel; `.godot` is the
60
+ * editor's derived cache tree.
61
+ */
62
+ excludePrefixes?: readonly string[];
63
+ /** Called after inbound changes are applied and the scan is requested. */
64
+ onInboundApplied?(relativePaths: readonly string[]): void;
65
+ /** Called after an outbound editor commit reaches the workspace. */
66
+ onOutboundApplied?(relativePaths: readonly string[]): void;
67
+ onError?(cause: unknown): void;
68
+ /** Milliseconds before a direct editor write without a rename is flushed. */
69
+ outboundDebounceMilliseconds?: number;
70
+ /** Milliseconds before batched inbound changes request one editor scan. */
71
+ scanDebounceMilliseconds?: number;
72
+ }
73
+ export declare class GodotEditorBridge {
74
+ private readonly workspace;
75
+ private readonly workspaceRoot;
76
+ private readonly editor;
77
+ private readonly editorRoot;
78
+ private readonly excludePrefixes;
79
+ private readonly workspaceOriginals;
80
+ private readonly editorOriginals;
81
+ private readonly options;
82
+ private readonly applyingInbound;
83
+ private readonly applyingOutbound;
84
+ private readonly pendingOutboundWrites;
85
+ private readonly pendingScanPaths;
86
+ private outboundTimer;
87
+ private scanTimer;
88
+ private disposed;
89
+ constructor(options: GodotEditorBridgeOptions);
90
+ dispose(): void;
91
+ private relativeOf;
92
+ private fail;
93
+ private installWorkspaceHooks;
94
+ private forwardInbound;
95
+ private ensureEditorParents;
96
+ private ensureEditorDirectory;
97
+ private queueScan;
98
+ private installEditorHooks;
99
+ private forwardOutbound;
100
+ private scheduleOutboundFlush;
101
+ private syncOutboundFile;
102
+ private ensureWorkspaceParents;
103
+ }
104
+ export {};
105
+ //# sourceMappingURL=editor-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editor-bridge.d.ts","sourceRoot":"","sources":["../src/editor-bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,334 @@
1
+ /**
2
+ * Bidirectional file bridge between the workbench's live virtual filesystem
3
+ * and a running FS-exposed Godot web editor (built by
4
+ * scripts/build-godot-web-editor.sh).
5
+ *
6
+ * Both directions use the same method the chassis uses for AlmostNode→OPFS
7
+ * persistence: wrap the filesystem's mutation functions, keep the originals,
8
+ * filter by root, restore on dispose. The workspace side mirrors the
9
+ * VirtualFS method names structurally so a consumer can pass the live
10
+ * filesystem directly; this package deliberately imports nothing from the
11
+ * chassis or any execution engine.
12
+ *
13
+ * Outbound (editor → workspace): Godot commits files as write-to-temp then
14
+ * atomic rename, so a rename into a final path is a per-file commit point.
15
+ * Direct writes without a rename are flushed on a short debounce.
16
+ *
17
+ * Inbound (workspace → editor): bytes are applied to the editor's Emscripten
18
+ * FS immediately; a debounced `.agent/scan_request` write asks the in-project
19
+ * agent_bridge addon to rescan, because the web editor does not rescan on
20
+ * focus.
21
+ */
22
+ const DEFAULT_EXCLUDES = [".agent", ".godot"];
23
+ const SCAN_REQUEST_RELATIVE = ".agent/scan_request";
24
+ /**
25
+ * Godot writes a file as `<final>-XXXXXX` then renames it over `<final>`.
26
+ * The temp name must never reach the workspace: the rename is the commit,
27
+ * and it syncs the final path. Matches a six-character mkstemp-style suffix.
28
+ */
29
+ const EDITOR_TEMPORARY_NAME = /-[A-Za-z0-9]{6}$/;
30
+ function isEditorTemporary(relative) {
31
+ return EDITOR_TEMPORARY_NAME.test(relative);
32
+ }
33
+ function normalize(path) {
34
+ const collapsed = path.replace(/\/+/g, "/");
35
+ return collapsed.length > 1 && collapsed.endsWith("/") ? collapsed.slice(0, -1) : collapsed;
36
+ }
37
+ export class GodotEditorBridge {
38
+ workspace;
39
+ workspaceRoot;
40
+ editor;
41
+ editorRoot;
42
+ excludePrefixes;
43
+ workspaceOriginals;
44
+ editorOriginals;
45
+ options;
46
+ applyingInbound = new Set();
47
+ applyingOutbound = new Set();
48
+ pendingOutboundWrites = new Set();
49
+ pendingScanPaths = [];
50
+ outboundTimer;
51
+ scanTimer;
52
+ disposed = false;
53
+ constructor(options) {
54
+ this.options = options;
55
+ this.workspace = options.workspace;
56
+ this.workspaceRoot = normalize(options.workspaceRoot);
57
+ this.editor = options.editorFilesystem;
58
+ this.editorRoot = normalize(options.editorRoot);
59
+ this.excludePrefixes = options.excludePrefixes ?? DEFAULT_EXCLUDES;
60
+ this.workspaceOriginals = {
61
+ writeFileSync: this.workspace.writeFileSync.bind(this.workspace),
62
+ mkdirSync: this.workspace.mkdirSync.bind(this.workspace),
63
+ unlinkSync: this.workspace.unlinkSync.bind(this.workspace),
64
+ rmdirSync: this.workspace.rmdirSync.bind(this.workspace),
65
+ renameSync: this.workspace.renameSync.bind(this.workspace),
66
+ };
67
+ this.editorOriginals = {
68
+ write: this.editor.write.bind(this.editor),
69
+ mkdir: this.editor.mkdir.bind(this.editor),
70
+ unlink: this.editor.unlink.bind(this.editor),
71
+ rmdir: this.editor.rmdir.bind(this.editor),
72
+ rename: this.editor.rename.bind(this.editor),
73
+ };
74
+ this.installWorkspaceHooks();
75
+ this.installEditorHooks();
76
+ }
77
+ dispose() {
78
+ if (this.disposed)
79
+ return;
80
+ this.disposed = true;
81
+ if (this.outboundTimer !== undefined)
82
+ clearTimeout(this.outboundTimer);
83
+ if (this.scanTimer !== undefined)
84
+ clearTimeout(this.scanTimer);
85
+ this.workspace.writeFileSync = this.workspaceOriginals.writeFileSync;
86
+ this.workspace.mkdirSync = this.workspaceOriginals.mkdirSync;
87
+ this.workspace.unlinkSync = this.workspaceOriginals.unlinkSync;
88
+ this.workspace.rmdirSync = this.workspaceOriginals.rmdirSync;
89
+ this.workspace.renameSync = this.workspaceOriginals.renameSync;
90
+ this.editor.write = this.editorOriginals.write;
91
+ this.editor.mkdir = this.editorOriginals.mkdir;
92
+ this.editor.unlink = this.editorOriginals.unlink;
93
+ this.editor.rmdir = this.editorOriginals.rmdir;
94
+ this.editor.rename = this.editorOriginals.rename;
95
+ }
96
+ relativeOf(root, path) {
97
+ const normalized = normalize(path);
98
+ if (normalized === root)
99
+ return "";
100
+ if (!normalized.startsWith(root + "/"))
101
+ return undefined;
102
+ const relative = normalized.slice(root.length + 1);
103
+ for (const prefix of this.excludePrefixes) {
104
+ if (relative === prefix || relative.startsWith(prefix + "/"))
105
+ return undefined;
106
+ }
107
+ return relative;
108
+ }
109
+ fail(cause) {
110
+ this.options.onError?.(cause);
111
+ }
112
+ // ---- Inbound: workspace mutations flow into the editor filesystem. ----
113
+ installWorkspaceHooks() {
114
+ this.workspace.writeFileSync = (path, data) => {
115
+ this.workspaceOriginals.writeFileSync(path, data);
116
+ this.forwardInbound(path, (editorPath) => {
117
+ this.ensureEditorParents(editorPath);
118
+ this.editor.writeFile(editorPath, this.workspace.readFileSync(normalize(path)));
119
+ });
120
+ };
121
+ this.workspace.mkdirSync = (path, options) => {
122
+ this.workspaceOriginals.mkdirSync(path, options);
123
+ this.forwardInbound(path, (editorPath) => this.ensureEditorDirectory(editorPath));
124
+ };
125
+ this.workspace.unlinkSync = (path) => {
126
+ this.workspaceOriginals.unlinkSync(path);
127
+ this.forwardInbound(path, (editorPath) => {
128
+ if (this.editor.analyzePath(editorPath).exists)
129
+ this.editor.unlink(editorPath);
130
+ });
131
+ };
132
+ this.workspace.rmdirSync = (path) => {
133
+ this.workspaceOriginals.rmdirSync(path);
134
+ this.forwardInbound(path, (editorPath) => {
135
+ if (this.editor.analyzePath(editorPath).exists)
136
+ this.editor.rmdir(editorPath);
137
+ });
138
+ };
139
+ this.workspace.renameSync = (from, to) => {
140
+ this.workspaceOriginals.renameSync(from, to);
141
+ const fromRelative = this.relativeOf(this.workspaceRoot, from);
142
+ const toRelative = this.relativeOf(this.workspaceRoot, to);
143
+ if (fromRelative === undefined && toRelative === undefined)
144
+ return;
145
+ try {
146
+ if (fromRelative !== undefined && toRelative !== undefined) {
147
+ this.applyingInbound.add(fromRelative);
148
+ this.applyingInbound.add(toRelative);
149
+ try {
150
+ this.editor.rename(`${this.editorRoot}/${fromRelative}`, `${this.editorRoot}/${toRelative}`);
151
+ }
152
+ finally {
153
+ this.applyingInbound.delete(fromRelative);
154
+ this.applyingInbound.delete(toRelative);
155
+ }
156
+ this.queueScan([fromRelative, toRelative]);
157
+ }
158
+ else if (toRelative !== undefined) {
159
+ this.forwardInbound(to, (editorPath) => {
160
+ this.ensureEditorParents(editorPath);
161
+ this.editor.writeFile(editorPath, this.workspace.readFileSync(normalize(to)));
162
+ });
163
+ }
164
+ else if (fromRelative !== undefined) {
165
+ this.forwardInbound(from, (editorPath) => {
166
+ if (this.editor.analyzePath(editorPath).exists)
167
+ this.editor.unlink(editorPath);
168
+ });
169
+ }
170
+ }
171
+ catch (cause) {
172
+ this.fail(cause);
173
+ }
174
+ };
175
+ }
176
+ forwardInbound(workspacePath, apply) {
177
+ const relative = this.relativeOf(this.workspaceRoot, workspacePath);
178
+ if (relative === undefined || relative === "" || this.applyingOutbound.has(relative))
179
+ return;
180
+ this.applyingInbound.add(relative);
181
+ try {
182
+ apply(`${this.editorRoot}/${relative}`);
183
+ this.queueScan([relative]);
184
+ }
185
+ catch (cause) {
186
+ this.fail(cause);
187
+ }
188
+ finally {
189
+ this.applyingInbound.delete(relative);
190
+ }
191
+ }
192
+ ensureEditorParents(editorPath) {
193
+ const parent = editorPath.slice(0, editorPath.lastIndexOf("/"));
194
+ if (parent.length > this.editorRoot.length)
195
+ this.ensureEditorDirectory(parent);
196
+ }
197
+ ensureEditorDirectory(editorPath) {
198
+ if (this.editor.analyzePath(editorPath).exists)
199
+ return;
200
+ this.ensureEditorParents(editorPath);
201
+ this.editorOriginals.mkdir(editorPath);
202
+ }
203
+ queueScan(relativePaths) {
204
+ this.pendingScanPaths.push(...relativePaths);
205
+ if (this.scanTimer !== undefined)
206
+ clearTimeout(this.scanTimer);
207
+ this.scanTimer = setTimeout(() => {
208
+ this.scanTimer = undefined;
209
+ const applied = this.pendingScanPaths.splice(0);
210
+ try {
211
+ this.ensureEditorDirectory(`${this.editorRoot}/.agent`);
212
+ this.editor.writeFile(`${this.editorRoot}/${SCAN_REQUEST_RELATIVE}`, new Uint8Array([49]));
213
+ this.options.onInboundApplied?.(applied);
214
+ }
215
+ catch (cause) {
216
+ this.fail(cause);
217
+ }
218
+ }, this.options.scanDebounceMilliseconds ?? 100);
219
+ }
220
+ // ---- Outbound: editor commits flow into the workspace filesystem. ----
221
+ installEditorHooks() {
222
+ this.editor.write = (stream, ...rest) => {
223
+ const result = this.editorOriginals.write(stream, ...rest);
224
+ const relative = stream.path === undefined ? undefined : this.relativeOf(this.editorRoot, stream.path);
225
+ if (relative !== undefined && relative !== "" && !this.applyingInbound.has(relative) && !isEditorTemporary(relative)) {
226
+ this.pendingOutboundWrites.add(relative);
227
+ this.scheduleOutboundFlush();
228
+ }
229
+ return result;
230
+ };
231
+ this.editor.mkdir = (path, mode) => {
232
+ this.editorOriginals.mkdir(path, mode);
233
+ this.forwardOutbound(path, (workspacePath) => {
234
+ if (!this.workspace.existsSync(workspacePath)) {
235
+ this.workspaceOriginals.mkdirSync(workspacePath, { recursive: true });
236
+ }
237
+ });
238
+ };
239
+ this.editor.unlink = (path) => {
240
+ this.editorOriginals.unlink(path);
241
+ const relative = path === undefined ? undefined : this.relativeOf(this.editorRoot, path);
242
+ if (relative !== undefined)
243
+ this.pendingOutboundWrites.delete(relative);
244
+ this.forwardOutbound(path, (workspacePath) => {
245
+ if (this.workspace.existsSync(workspacePath))
246
+ this.workspaceOriginals.unlinkSync(workspacePath);
247
+ });
248
+ };
249
+ this.editor.rmdir = (path) => {
250
+ this.editorOriginals.rmdir(path);
251
+ this.forwardOutbound(path, (workspacePath) => {
252
+ if (this.workspace.existsSync(workspacePath))
253
+ this.workspaceOriginals.rmdirSync(workspacePath);
254
+ });
255
+ };
256
+ this.editor.rename = (from, to) => {
257
+ this.editorOriginals.rename(from, to);
258
+ const fromRelative = this.relativeOf(this.editorRoot, from);
259
+ const toRelative = this.relativeOf(this.editorRoot, to);
260
+ if (fromRelative !== undefined)
261
+ this.pendingOutboundWrites.delete(fromRelative);
262
+ if (toRelative === undefined || this.applyingInbound.has(toRelative))
263
+ return;
264
+ // A rename into a final path is Godot's atomic per-file commit point:
265
+ // sync the destination bytes now instead of waiting for the debounce.
266
+ this.pendingOutboundWrites.delete(toRelative);
267
+ this.syncOutboundFile(toRelative);
268
+ if (fromRelative !== undefined) {
269
+ this.forwardOutbound(from, (workspacePath) => {
270
+ if (this.workspace.existsSync(workspacePath))
271
+ this.workspaceOriginals.unlinkSync(workspacePath);
272
+ });
273
+ }
274
+ };
275
+ }
276
+ forwardOutbound(editorPath, apply) {
277
+ const relative = this.relativeOf(this.editorRoot, editorPath);
278
+ if (relative === undefined || relative === "" || this.applyingInbound.has(relative))
279
+ return;
280
+ // A temporary never reached the workspace, so its removal is not an event.
281
+ if (isEditorTemporary(relative))
282
+ return;
283
+ this.applyingOutbound.add(relative);
284
+ try {
285
+ apply(`${this.workspaceRoot}/${relative}`);
286
+ this.options.onOutboundApplied?.([relative]);
287
+ }
288
+ catch (cause) {
289
+ this.fail(cause);
290
+ }
291
+ finally {
292
+ this.applyingOutbound.delete(relative);
293
+ }
294
+ }
295
+ scheduleOutboundFlush() {
296
+ if (this.outboundTimer !== undefined)
297
+ return;
298
+ this.outboundTimer = setTimeout(() => {
299
+ this.outboundTimer = undefined;
300
+ const pending = [...this.pendingOutboundWrites];
301
+ this.pendingOutboundWrites.clear();
302
+ for (const relative of pending)
303
+ this.syncOutboundFile(relative);
304
+ }, this.options.outboundDebounceMilliseconds ?? 150);
305
+ }
306
+ syncOutboundFile(relative) {
307
+ this.applyingOutbound.add(relative);
308
+ try {
309
+ const editorPath = `${this.editorRoot}/${relative}`;
310
+ if (!this.editor.analyzePath(editorPath).exists)
311
+ return;
312
+ const bytes = this.editor.readFile(editorPath, { encoding: "binary" });
313
+ this.ensureWorkspaceParents(relative);
314
+ this.workspaceOriginals.writeFileSync(`${this.workspaceRoot}/${relative}`, bytes);
315
+ this.options.onOutboundApplied?.([relative]);
316
+ }
317
+ catch (cause) {
318
+ this.fail(cause);
319
+ }
320
+ finally {
321
+ this.applyingOutbound.delete(relative);
322
+ }
323
+ }
324
+ ensureWorkspaceParents(relative) {
325
+ const lastSlash = relative.lastIndexOf("/");
326
+ if (lastSlash <= 0)
327
+ return;
328
+ const parent = `${this.workspaceRoot}/${relative.slice(0, lastSlash)}`;
329
+ if (!this.workspace.existsSync(parent)) {
330
+ this.workspaceOriginals.mkdirSync(parent, { recursive: true });
331
+ }
332
+ }
333
+ }
334
+ //# sourceMappingURL=editor-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editor-bridge.js","sourceRoot":"","sources":["../src/editor-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAiDH,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAU,CAAC;AACvD,MAAM,qBAAqB,GAAG,qBAAqB,CAAC;AACpD;;;;GAIG;AACH,MAAM,qBAAqB,GAAG,kBAAkB,CAAC;AAEjD,SAAS,iBAAiB,CAAC,QAAgB;IACzC,OAAO,qBAAqB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC9C,CAAC;AAkBD,SAAS,SAAS,CAAC,IAAY;IAC7B,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5C,OAAO,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9F,CAAC;AAED,MAAM,OAAO,iBAAiB;IACX,SAAS,CAAkB;IAC3B,aAAa,CAAS;IACtB,MAAM,CAAmB;IACzB,UAAU,CAAS;IACnB,eAAe,CAAoB;IACnC,kBAAkB,CAAqB;IACvC,eAAe,CAAkB;IACjC,OAAO,CAA2B;IAClC,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;IACpC,gBAAgB,GAAG,IAAI,GAAG,EAAU,CAAC;IACrC,qBAAqB,GAAG,IAAI,GAAG,EAAU,CAAC;IAC1C,gBAAgB,GAAa,EAAE,CAAC;IACzC,aAAa,CAA4C;IACzD,SAAS,CAA4C;IACrD,QAAQ,GAAG,KAAK,CAAC;IAEzB,YAAY,OAAiC;QAC3C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QACtD,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;QACvC,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAChD,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,eAAe,IAAI,gBAAgB,CAAC;QACnE,IAAI,CAAC,kBAAkB,GAAG;YACxB,aAAa,EAAE,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;YAChE,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;YACxD,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;YAC1D,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;YACxD,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;SAC3D,CAAC;QACF,IAAI,CAAC,eAAe,GAAG;YACrB,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;YAC1C,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;YAC1C,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;YAC5C,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;YAC1C,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;SAC7C,CAAC;QACF,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC7B,IAAI,CAAC,kBAAkB,EAAE,CAAC;IAC5B,CAAC;IAED,OAAO;QACL,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC1B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,IAAI,CAAC,aAAa,KAAK,SAAS;YAAE,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACvE,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS;YAAE,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/D,IAAI,CAAC,SAAS,CAAC,aAAa,GAAG,IAAI,CAAC,kBAAkB,CAAC,aAAa,CAAC;QACrE,IAAI,CAAC,SAAS,CAAC,SAAS,GAAG,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC;QAC7D,IAAI,CAAC,SAAS,CAAC,UAAU,GAAG,IAAI,CAAC,kBAAkB,CAAC,UAAU,CAAC;QAC/D,IAAI,CAAC,SAAS,CAAC,SAAS,GAAG,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC;QAC7D,IAAI,CAAC,SAAS,CAAC,UAAU,GAAG,IAAI,CAAC,kBAAkB,CAAC,UAAU,CAAC;QAC/D,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC;QACjD,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC;IACnD,CAAC;IAEO,UAAU,CAAC,IAAY,EAAE,IAAY;QAC3C,MAAM,UAAU,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,UAAU,KAAK,IAAI;YAAE,OAAO,EAAE,CAAC;QACnC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,GAAG,GAAG,CAAC;YAAE,OAAO,SAAS,CAAC;QACzD,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACnD,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YAC1C,IAAI,QAAQ,KAAK,MAAM,IAAI,QAAQ,CAAC,UAAU,CAAC,MAAM,GAAG,GAAG,CAAC;gBAAE,OAAO,SAAS,CAAC;QACjF,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAEO,IAAI,CAAC,KAAc;QACzB,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IAED,0EAA0E;IAElE,qBAAqB;QAC3B,IAAI,CAAC,SAAS,CAAC,aAAa,GAAG,CAAC,IAAY,EAAE,IAAgB,EAAQ,EAAE;YACtE,IAAI,CAAC,kBAAkB,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAClD,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,UAAU,EAAE,EAAE;gBACvC,IAAI,CAAC,mBAAmB,CAAC,UAAU,CAAC,CAAC;gBACrC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClF,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QACF,IAAI,CAAC,SAAS,CAAC,SAAS,GAAG,CAAC,IAAY,EAAE,OAAiC,EAAQ,EAAE;YACnF,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YACjD,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,UAAU,CAAC,CAAC,CAAC;QACpF,CAAC,CAAC;QACF,IAAI,CAAC,SAAS,CAAC,UAAU,GAAG,CAAC,IAAY,EAAQ,EAAE;YACjD,IAAI,CAAC,kBAAkB,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YACzC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,UAAU,EAAE,EAAE;gBACvC,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM;oBAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YACjF,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QACF,IAAI,CAAC,SAAS,CAAC,SAAS,GAAG,CAAC,IAAY,EAAQ,EAAE;YAChD,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACxC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,UAAU,EAAE,EAAE;gBACvC,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM;oBAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YAChF,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QACF,IAAI,CAAC,SAAS,CAAC,UAAU,GAAG,CAAC,IAAY,EAAE,EAAU,EAAQ,EAAE;YAC7D,IAAI,CAAC,kBAAkB,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC7C,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;YAC/D,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;YAC3D,IAAI,YAAY,KAAK,SAAS,IAAI,UAAU,KAAK,SAAS;gBAAE,OAAO;YACnE,IAAI,CAAC;gBACH,IAAI,YAAY,KAAK,SAAS,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;oBAC3D,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;oBACvC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;oBACrC,IAAI,CAAC;wBACH,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,UAAU,IAAI,YAAY,EAAE,EAAE,GAAG,IAAI,CAAC,UAAU,IAAI,UAAU,EAAE,CAAC,CAAC;oBAC/F,CAAC;4BAAS,CAAC;wBACT,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;wBAC1C,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;oBAC1C,CAAC;oBACD,IAAI,CAAC,SAAS,CAAC,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC;gBAC7C,CAAC;qBAAM,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;oBACpC,IAAI,CAAC,cAAc,CAAC,EAAE,EAAE,CAAC,UAAU,EAAE,EAAE;wBACrC,IAAI,CAAC,mBAAmB,CAAC,UAAU,CAAC,CAAC;wBACrC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;oBAChF,CAAC,CAAC,CAAC;gBACL,CAAC;qBAAM,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;oBACtC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,UAAU,EAAE,EAAE;wBACvC,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM;4BAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;oBACjF,CAAC,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACnB,CAAC;QACH,CAAC,CAAC;IACJ,CAAC;IAEO,cAAc,CAAC,aAAqB,EAAE,KAAmC;QAC/E,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;QACpE,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,EAAE,IAAI,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,OAAO;QAC7F,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACnC,IAAI,CAAC;YACH,KAAK,CAAC,GAAG,IAAI,CAAC,UAAU,IAAI,QAAQ,EAAE,CAAC,CAAC;YACxC,IAAI,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC7B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnB,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IAEO,mBAAmB,CAAC,UAAkB;QAC5C,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,IAAI,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM;YAAE,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC;IACjF,CAAC;IAEO,qBAAqB,CAAC,UAAkB;QAC9C,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM;YAAE,OAAO;QACvD,IAAI,CAAC,mBAAmB,CAAC,UAAU,CAAC,CAAC;QACrC,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACzC,CAAC;IAEO,SAAS,CAAC,aAAgC;QAChD,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,CAAC;QAC7C,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS;YAAE,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/D,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;YAC/B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;YAC3B,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAChD,IAAI,CAAC;gBACH,IAAI,CAAC,qBAAqB,CAAC,GAAG,IAAI,CAAC,UAAU,SAAS,CAAC,CAAC;gBACxD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,UAAU,IAAI,qBAAqB,EAAE,EAAE,IAAI,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC3F,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,OAAO,CAAC,CAAC;YAC3C,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACnB,CAAC;QACH,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,wBAAwB,IAAI,GAAG,CAAC,CAAC;IACnD,CAAC;IAED,yEAAyE;IAEjE,kBAAkB;QACxB,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,MAAwB,EAAE,GAAG,IAAe,EAAU,EAAE;YAC3E,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC;YAC3D,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;YACvG,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACrH,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACzC,IAAI,CAAC,qBAAqB,EAAE,CAAC;YAC/B,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,IAAY,EAAE,IAAa,EAAQ,EAAE;YACxD,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACvC,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,aAAa,EAAE,EAAE;gBAC3C,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;oBAC9C,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBACxE,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAY,EAAQ,EAAE;YAC1C,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,QAAQ,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;YACzF,IAAI,QAAQ,KAAK,SAAS;gBAAE,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YACxE,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,aAAa,EAAE,EAAE;gBAC3C,IAAI,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,aAAa,CAAC;oBAAE,IAAI,CAAC,kBAAkB,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;YAClG,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,IAAY,EAAQ,EAAE;YACzC,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACjC,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,aAAa,EAAE,EAAE;gBAC3C,IAAI,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,aAAa,CAAC;oBAAE,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;YACjG,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAY,EAAE,EAAU,EAAQ,EAAE;YACtD,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACtC,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;YAC5D,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;YACxD,IAAI,YAAY,KAAK,SAAS;gBAAE,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;YAChF,IAAI,UAAU,KAAK,SAAS,IAAI,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC;gBAAE,OAAO;YAC7E,sEAAsE;YACtE,sEAAsE;YACtE,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAC9C,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;YAClC,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;gBAC/B,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,aAAa,EAAE,EAAE;oBAC3C,IAAI,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,aAAa,CAAC;wBAAE,IAAI,CAAC,kBAAkB,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;gBAClG,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CAAC;IACJ,CAAC;IAEO,eAAe,CAAC,UAAkB,EAAE,KAAsC;QAChF,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QAC9D,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,EAAE,IAAI,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,OAAO;QAC5F,2EAA2E;QAC3E,IAAI,iBAAiB,CAAC,QAAQ,CAAC;YAAE,OAAO;QACxC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACpC,IAAI,CAAC;YACH,KAAK,CAAC,GAAG,IAAI,CAAC,aAAa,IAAI,QAAQ,EAAE,CAAC,CAAC;YAC3C,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC/C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnB,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IAEO,qBAAqB;QAC3B,IAAI,IAAI,CAAC,aAAa,KAAK,SAAS;YAAE,OAAO;QAC7C,IAAI,CAAC,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE;YACnC,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;YAC/B,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,qBAAqB,CAAC,CAAC;YAChD,IAAI,CAAC,qBAAqB,CAAC,KAAK,EAAE,CAAC;YACnC,KAAK,MAAM,QAAQ,IAAI,OAAO;gBAAE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAClE,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,4BAA4B,IAAI,GAAG,CAAC,CAAC;IACvD,CAAC;IAEO,gBAAgB,CAAC,QAAgB;QACvC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACpC,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,GAAG,IAAI,CAAC,UAAU,IAAI,QAAQ,EAAE,CAAC;YACpD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM;gBAAE,OAAO;YACxD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;YACvE,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC;YACtC,IAAI,CAAC,kBAAkB,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC,aAAa,IAAI,QAAQ,EAAE,EAAE,KAAK,CAAC,CAAC;YAClF,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC/C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnB,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IAEO,sBAAsB,CAAC,QAAgB;QAC7C,MAAM,SAAS,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAC5C,IAAI,SAAS,IAAI,CAAC;YAAE,OAAO;QAC3B,MAAM,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC;QACvE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACvC,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Embeds a patched Godot web editor in an iframe and materializes a project
3
+ * into it from the shared workspace.
4
+ *
5
+ * The editor shell is patched at build time by
6
+ * scripts/patch-editor-shell.py, which adds the seven hook points this module
7
+ * drives: engine exposure, embed-mode notice suppression, ephemeral
8
+ * filesystem (the workspace is the durable copy, not the editor's IDBFS),
9
+ * caller-supplied editor arguments, and a materialize callback invoked after
10
+ * both the editor and the game engines initialize.
11
+ *
12
+ * The game engine is a SEPARATE Emscripten instance with its own filesystem,
13
+ * so the project is materialized into it as well; otherwise pressing play in
14
+ * an ephemeral-FS editor runs against an empty tree.
15
+ *
16
+ * Godot resolves its editor UI scale from `devicePixelRatio` once at startup
17
+ * and marks the setting restart-required, so a window moved between displays
18
+ * of different pixel ratios leaves the interface drawn at the old scale. The
19
+ * embed watches for that change and reopens the editor, which is safe
20
+ * precisely because the workspace — not the editor's filesystem — holds the
21
+ * project.
22
+ */
23
+ export interface EmbedWorkspaceSource {
24
+ readFileSync(path: string): Uint8Array;
25
+ readdirSync(path: string): string[];
26
+ statSync(path: string): {
27
+ isDirectory(): boolean;
28
+ };
29
+ existsSync(path: string): boolean;
30
+ }
31
+ interface EmbedEngine {
32
+ copyToFS(path: string, data: Uint8Array): void;
33
+ rtenv?: unknown;
34
+ }
35
+ export interface GodotEditorEmbedOptions {
36
+ /** Iframe that will host the editor; its `src` is set by `open()`. */
37
+ frame: HTMLIFrameElement;
38
+ /** URL of the patched editor shell, e.g. "/godot/godot.editor.html". */
39
+ editorUrl: string;
40
+ workspace: EmbedWorkspaceSource;
41
+ /** Workspace-side project root, e.g. "/workspace". */
42
+ workspaceRoot: string;
43
+ /** Editor-side project root, e.g. "/home/web_user/project". */
44
+ editorRoot: string;
45
+ /** Excluded from materialization; defaults match the bridge's excludes. */
46
+ excludePrefixes?: readonly string[];
47
+ /**
48
+ * Called with a fresh handle after the editor is reopened because the
49
+ * device pixel ratio changed. Consumers must rebind anything holding the
50
+ * previous editor filesystem, such as `GodotEditorBridge`.
51
+ */
52
+ onReopen?(handle: GodotEditorHandle): void;
53
+ onError?(cause: unknown): void;
54
+ }
55
+ export interface GodotEditorHandle {
56
+ /** The editor engine, once initialized. */
57
+ engine: EmbedEngine;
58
+ /** The editor's Emscripten filesystem, for `GodotEditorBridge`. */
59
+ filesystem: unknown;
60
+ }
61
+ export declare class GodotEditorEmbed {
62
+ private readonly options;
63
+ private readonly excludePrefixes;
64
+ private pixelRatioQuery;
65
+ private pixelRatioTimer;
66
+ /**
67
+ * Increments on every open. An open whose generation is stale by the time
68
+ * it finishes lost a race with a newer one — a real case, because moving a
69
+ * window across displays can change the ratio twice in quick succession,
70
+ * and two opens sharing one iframe leave a blank editor.
71
+ */
72
+ private openGeneration;
73
+ private readonly handlePixelRatioChange;
74
+ constructor(options: GodotEditorEmbedOptions);
75
+ dispose(): void;
76
+ /**
77
+ * Reopens the editor when the device pixel ratio changes, so its UI scale
78
+ * matches the canvas again. Re-armed after each change because the query
79
+ * is pinned to the ratio observed at startup.
80
+ */
81
+ private watchPixelRatio;
82
+ /**
83
+ * Loads the editor and resolves once its engine has initialized with the
84
+ * workspace project materialized into it.
85
+ */
86
+ open(): Promise<GodotEditorHandle>;
87
+ private materialize;
88
+ }
89
+ export {};
90
+ //# sourceMappingURL=editor-embed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editor-embed.d.ts","sourceRoot":"","sources":["../src/editor-embed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,WAAW,oBAAoB;IACnC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;IACvC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,WAAW,IAAI,OAAO,CAAA;KAAE,CAAC;IACnD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CACnC;AAED,UAAU,WAAW;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/C,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAWD,MAAM,WAAW,uBAAuB;IACtC,sEAAsE;IACtE,KAAK,EAAE,iBAAiB,CAAC;IACzB,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,oBAAoB,CAAC;IAChC,sDAAsD;IACtD,aAAa,EAAE,MAAM,CAAC;IACtB,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC;;;;OAIG;IACH,QAAQ,CAAC,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC3C,OAAO,CAAC,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;CAChC;AAID,MAAM,WAAW,iBAAiB;IAChC,2CAA2C;IAC3C,MAAM,EAAE,WAAW,CAAC;IACpB,mEAAmE;IACnE,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,qBAAa,gBAAgB;IA0Bf,OAAO,CAAC,QAAQ,CAAC,OAAO;IAzBpC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAoB;IACpD,OAAO,CAAC,eAAe,CAA6B;IACpD,OAAO,CAAC,eAAe,CAA4C;IACnE;;;;;OAKG;IACH,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAarC;gBAE2B,OAAO,EAAE,uBAAuB;IAI7D,OAAO,IAAI,IAAI;IAOf;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAOvB;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAgDxC,OAAO,CAAC,WAAW;CAkBpB"}
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Embeds a patched Godot web editor in an iframe and materializes a project
3
+ * into it from the shared workspace.
4
+ *
5
+ * The editor shell is patched at build time by
6
+ * scripts/patch-editor-shell.py, which adds the seven hook points this module
7
+ * drives: engine exposure, embed-mode notice suppression, ephemeral
8
+ * filesystem (the workspace is the durable copy, not the editor's IDBFS),
9
+ * caller-supplied editor arguments, and a materialize callback invoked after
10
+ * both the editor and the game engines initialize.
11
+ *
12
+ * The game engine is a SEPARATE Emscripten instance with its own filesystem,
13
+ * so the project is materialized into it as well; otherwise pressing play in
14
+ * an ephemeral-FS editor runs against an empty tree.
15
+ *
16
+ * Godot resolves its editor UI scale from `devicePixelRatio` once at startup
17
+ * and marks the setting restart-required, so a window moved between displays
18
+ * of different pixel ratios leaves the interface drawn at the old scale. The
19
+ * embed watches for that change and reopens the editor, which is safe
20
+ * precisely because the workspace — not the editor's filesystem — holds the
21
+ * project.
22
+ */
23
+ const DEFAULT_EXCLUDES = [".agent", ".godot"];
24
+ export class GodotEditorEmbed {
25
+ options;
26
+ excludePrefixes;
27
+ pixelRatioQuery;
28
+ pixelRatioTimer;
29
+ /**
30
+ * Increments on every open. An open whose generation is stale by the time
31
+ * it finishes lost a race with a newer one — a real case, because moving a
32
+ * window across displays can change the ratio twice in quick succession,
33
+ * and two opens sharing one iframe leave a blank editor.
34
+ */
35
+ openGeneration = 0;
36
+ handlePixelRatioChange = () => {
37
+ this.pixelRatioQuery = undefined;
38
+ if (this.pixelRatioTimer !== undefined)
39
+ clearTimeout(this.pixelRatioTimer);
40
+ this.pixelRatioTimer = setTimeout(() => {
41
+ this.pixelRatioTimer = undefined;
42
+ const generation = this.openGeneration + 1;
43
+ void this.open()
44
+ .then((handle) => {
45
+ if (generation !== this.openGeneration)
46
+ return;
47
+ this.options.onReopen?.(handle);
48
+ })
49
+ .catch((cause) => this.options.onError?.(cause));
50
+ }, 400);
51
+ };
52
+ constructor(options) {
53
+ this.options = options;
54
+ this.excludePrefixes = options.excludePrefixes ?? DEFAULT_EXCLUDES;
55
+ }
56
+ dispose() {
57
+ if (this.pixelRatioTimer !== undefined)
58
+ clearTimeout(this.pixelRatioTimer);
59
+ this.pixelRatioTimer = undefined;
60
+ this.pixelRatioQuery?.removeEventListener("change", this.handlePixelRatioChange);
61
+ this.pixelRatioQuery = undefined;
62
+ }
63
+ /**
64
+ * Reopens the editor when the device pixel ratio changes, so its UI scale
65
+ * matches the canvas again. Re-armed after each change because the query
66
+ * is pinned to the ratio observed at startup.
67
+ */
68
+ watchPixelRatio() {
69
+ if (typeof matchMedia !== "function")
70
+ return;
71
+ this.pixelRatioQuery?.removeEventListener("change", this.handlePixelRatioChange);
72
+ this.pixelRatioQuery = matchMedia(`(resolution: ${devicePixelRatio}dppx)`);
73
+ this.pixelRatioQuery.addEventListener("change", this.handlePixelRatioChange, { once: true });
74
+ }
75
+ /**
76
+ * Loads the editor and resolves once its engine has initialized with the
77
+ * workspace project materialized into it.
78
+ */
79
+ async open() {
80
+ const generation = ++this.openGeneration;
81
+ const stale = () => generation !== this.openGeneration;
82
+ const frame = this.options.frame;
83
+ const loaded = new Promise((resolve, reject) => {
84
+ frame.addEventListener("load", () => resolve(), { once: true });
85
+ frame.addEventListener("error", () => reject(new Error("Godot editor frame failed to load.")), { once: true });
86
+ });
87
+ const url = new URL(this.options.editorUrl, location.href);
88
+ url.searchParams.set("browserEmbed", "1");
89
+ frame.src = url.href;
90
+ await loaded;
91
+ if (stale())
92
+ throw new Error("Godot editor open superseded by a newer open.");
93
+ const embedWindow = frame.contentWindow;
94
+ if (!embedWindow)
95
+ throw new Error("Godot editor frame has no window.");
96
+ if (typeof embedWindow.startEditor !== "function") {
97
+ throw new Error("Godot editor shell is unpatched: startEditor is unavailable.");
98
+ }
99
+ let ready;
100
+ let failed;
101
+ const handle = new Promise((resolve, reject) => {
102
+ ready = resolve;
103
+ failed = reject;
104
+ });
105
+ embedWindow.__volterBrowserEphemeralFS = true;
106
+ embedWindow.__volterBrowserEditorArgs = ["--editor", "--path", this.options.editorRoot, "--single-window"];
107
+ embedWindow.__volterBrowserMaterialize = (engine) => {
108
+ if (stale())
109
+ return;
110
+ try {
111
+ this.materialize(engine);
112
+ // The editor engine initializes first; the game engine reuses this
113
+ // same callback when the user runs the project.
114
+ if (engine === embedWindow.__volterBrowserGodotEngine) {
115
+ this.watchPixelRatio();
116
+ ready({ engine, filesystem: engine.rtenv?.FS });
117
+ }
118
+ }
119
+ catch (cause) {
120
+ this.options.onError?.(cause);
121
+ failed(cause);
122
+ }
123
+ };
124
+ embedWindow.startEditor();
125
+ return handle;
126
+ }
127
+ materialize(engine) {
128
+ const root = this.options.workspaceRoot;
129
+ const workspace = this.options.workspace;
130
+ if (!workspace.existsSync(root))
131
+ return;
132
+ const walk = (workspacePath, relative) => {
133
+ for (const prefix of this.excludePrefixes) {
134
+ if (relative === prefix || relative.startsWith(`${prefix}/`))
135
+ return;
136
+ }
137
+ if (workspace.statSync(workspacePath).isDirectory()) {
138
+ for (const name of workspace.readdirSync(workspacePath)) {
139
+ walk(`${workspacePath}/${name}`, relative === "" ? name : `${relative}/${name}`);
140
+ }
141
+ return;
142
+ }
143
+ engine.copyToFS(`${this.options.editorRoot}/${relative}`, workspace.readFileSync(workspacePath));
144
+ };
145
+ walk(root, "");
146
+ }
147
+ }
148
+ //# sourceMappingURL=editor-embed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editor-embed.js","sourceRoot":"","sources":["../src/editor-embed.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export * from "./editor-bridge.js";
2
+ export * from "./editor-embed.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./editor-bridge.js";
2
+ export * from "./editor-embed.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "@volter/browser-godot",
3
+ "version": "0.1.0",
4
+ "description": "Bidirectional bridge between a browser workspace and the Godot web editor",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/volter-ai/browser-substrate.git",
9
+ "directory": "packages/godot"
10
+ },
11
+ "type": "module",
12
+ "files": ["dist", "addon", "README.md", "LICENSE"],
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" },
16
+ "./*.js": { "types": "./dist/*.d.ts", "import": "./dist/*.js" }
17
+ },
18
+ "scripts": { "build": "tsc -p tsconfig.build.json" },
19
+ "publishConfig": { "access": "public" }
20
+ }