@holoscript/core 6.0.4 → 7.0.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 (236) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -1
  3. package/dist/compiler/index.d.ts +82 -0
  4. package/dist/constants.d.ts +3 -2
  5. package/dist/coordinators/index.d.ts +189 -0
  6. package/dist/index.d.ts +501 -19
  7. package/dist/paper-0c-spike/index.d.ts +29 -0
  8. package/dist/reconstruction/index.d.ts +78 -0
  9. package/dist/tools/index.d.ts +22 -1
  10. package/dist/traitDocs/traitDocs.d.ts +69 -0
  11. package/dist/traits/index.d.ts +61 -0
  12. package/package.json +105 -57
  13. package/dist/GLTFPipeline-DEN36VNK.js +0 -12
  14. package/dist/GLTFPipeline-YPCAK236.cjs +0 -33
  15. package/dist/HoloScriptPlusParser-BN6KVRCM.js +0 -692
  16. package/dist/HoloScriptPlusParser-NC5FE6AL.cjs +0 -697
  17. package/dist/USDZExporter-NTMBNTDB.js +0 -707
  18. package/dist/USDZExporter-UWGWNMMD.cjs +0 -709
  19. package/dist/chunk-27LWW5FU.cjs +0 -410
  20. package/dist/chunk-2CWOLHTE.js +0 -69
  21. package/dist/chunk-33LSUQDD.cjs +0 -835
  22. package/dist/chunk-3FJCK5XA.js +0 -2232
  23. package/dist/chunk-3FXV5S25.cjs +0 -633
  24. package/dist/chunk-3FYZOR7S.cjs +0 -69
  25. package/dist/chunk-3SAK5KFL.cjs +0 -83
  26. package/dist/chunk-4XSNJCLC.cjs +0 -1859
  27. package/dist/chunk-54FHG2MX.js +0 -655
  28. package/dist/chunk-56IF4NTA.js +0 -56
  29. package/dist/chunk-5BGSECRJ.cjs +0 -2237
  30. package/dist/chunk-5GLCTO44.js +0 -161
  31. package/dist/chunk-5O6TQC6M.cjs +0 -1871
  32. package/dist/chunk-5OEOHAAW.cjs +0 -682
  33. package/dist/chunk-5TOFIR6L.js +0 -407
  34. package/dist/chunk-5WUNN6ZN.cjs +0 -428
  35. package/dist/chunk-6TZPZCOJ.cjs +0 -1404
  36. package/dist/chunk-6UEHYZ7V.cjs +0 -773
  37. package/dist/chunk-6XSERL6L.js +0 -5678
  38. package/dist/chunk-72EQECGT.cjs +0 -908
  39. package/dist/chunk-7AGYRWKW.cjs +0 -507
  40. package/dist/chunk-7LCYLPW2.cjs +0 -663
  41. package/dist/chunk-A7PIMZGU.js +0 -263
  42. package/dist/chunk-ATSKSYVE.cjs +0 -51683
  43. package/dist/chunk-B5TCIAPQ.cjs +0 -117
  44. package/dist/chunk-BF2235SI.cjs +0 -5714
  45. package/dist/chunk-BKIGPPVM.js +0 -629
  46. package/dist/chunk-BND3ST2K.cjs +0 -662
  47. package/dist/chunk-BU7VWW2K.js +0 -2522
  48. package/dist/chunk-BWFJEM5A.js +0 -5419
  49. package/dist/chunk-CAUCGUEA.cjs +0 -130
  50. package/dist/chunk-CBJSLA2E.cjs +0 -5423
  51. package/dist/chunk-CDPGV4DN.js +0 -114
  52. package/dist/chunk-CLYEIWA5.cjs +0 -408
  53. package/dist/chunk-CS2EMTGF.js +0 -1966
  54. package/dist/chunk-DMG7C4H2.js +0 -975
  55. package/dist/chunk-DXJQDCFL.js +0 -468
  56. package/dist/chunk-E3FWRT3Z.js +0 -608
  57. package/dist/chunk-E3UALNFA.js +0 -421
  58. package/dist/chunk-EONILVMF.js +0 -762
  59. package/dist/chunk-EQV4R3EV.cjs +0 -769
  60. package/dist/chunk-F3HH56EB.cjs +0 -5538
  61. package/dist/chunk-F4IULT7N.js +0 -1488
  62. package/dist/chunk-FF3Q7ADR.js +0 -380
  63. package/dist/chunk-FFKU7BTK.cjs +0 -1046
  64. package/dist/chunk-FHQVYCH2.js +0 -70
  65. package/dist/chunk-FSF7EQVA.cjs +0 -1974
  66. package/dist/chunk-G4VZTCIB.js +0 -659
  67. package/dist/chunk-G7CT3EMP.cjs +0 -1002
  68. package/dist/chunk-GGHSW2NN.js +0 -51334
  69. package/dist/chunk-GVUR45UF.cjs +0 -777
  70. package/dist/chunk-H5Z7NASB.js +0 -9662
  71. package/dist/chunk-HE7ULERA.cjs +0 -697
  72. package/dist/chunk-HJJLD366.js +0 -1169
  73. package/dist/chunk-HPS76H7Q.js +0 -309
  74. package/dist/chunk-HQUEA5R6.cjs +0 -424
  75. package/dist/chunk-HYNTS5CP.js +0 -422
  76. package/dist/chunk-I6XZ5DZF.cjs +0 -488
  77. package/dist/chunk-IBDG74G2.cjs +0 -1219
  78. package/dist/chunk-IFNQFCTM.js +0 -3098
  79. package/dist/chunk-IHOUYQIA.js +0 -406
  80. package/dist/chunk-ILRBGFVD.cjs +0 -72
  81. package/dist/chunk-IWI6J7FX.js +0 -421
  82. package/dist/chunk-K3JDKWGI.cjs +0 -270
  83. package/dist/chunk-K6EKD26I.js +0 -630
  84. package/dist/chunk-KCQ5NDYC.cjs +0 -3172
  85. package/dist/chunk-KED34ILP.js +0 -832
  86. package/dist/chunk-KSGXLT74.cjs +0 -457
  87. package/dist/chunk-L4G4RLXX.js +0 -767
  88. package/dist/chunk-LDP5OK6G.js +0 -1216
  89. package/dist/chunk-LGGRPKTV.cjs +0 -735
  90. package/dist/chunk-LK5IAVH6.cjs +0 -1173
  91. package/dist/chunk-LSW7P7ML.js +0 -3675
  92. package/dist/chunk-LXJ4667L.cjs +0 -3874
  93. package/dist/chunk-LZ266PCM.cjs +0 -4499
  94. package/dist/chunk-MD6KDHVE.cjs +0 -237
  95. package/dist/chunk-MEASWI2Y.js +0 -126
  96. package/dist/chunk-MPXBVFHQ.js +0 -768
  97. package/dist/chunk-N5FTS757.cjs +0 -415
  98. package/dist/chunk-NCUKG4SK.cjs +0 -3075
  99. package/dist/chunk-NDQNIJEH.js +0 -1715
  100. package/dist/chunk-NOZZ46QU.js +0 -168
  101. package/dist/chunk-OFKWH2IP.js +0 -449
  102. package/dist/chunk-PHENW4MQ.js +0 -65
  103. package/dist/chunk-PMGODDJA.cjs +0 -319
  104. package/dist/chunk-Q4QX3AET.cjs +0 -1505
  105. package/dist/chunk-Q56TT7IL.js +0 -483
  106. package/dist/chunk-Q5JT3YML.cjs +0 -129
  107. package/dist/chunk-Q5SJOGHQ.cjs +0 -4256
  108. package/dist/chunk-QGKNANZ3.js +0 -3071
  109. package/dist/chunk-QLEAOI3Q.cjs +0 -424
  110. package/dist/chunk-R7MA7QWV.js +0 -732
  111. package/dist/chunk-RVYPEYPX.js +0 -678
  112. package/dist/chunk-S2N5TNMA.js +0 -1855
  113. package/dist/chunk-S565K7NK.js +0 -752
  114. package/dist/chunk-SDAMZIRE.js +0 -765
  115. package/dist/chunk-T36DDXSF.js +0 -4250
  116. package/dist/chunk-T4NKMBDL.js +0 -5474
  117. package/dist/chunk-T7LEXZUZ.cjs +0 -2526
  118. package/dist/chunk-TEWCN33Y.js +0 -694
  119. package/dist/chunk-TQSZUOW5.cjs +0 -793
  120. package/dist/chunk-TSH3MSQU.cjs +0 -129
  121. package/dist/chunk-UERJ3YJV.js +0 -504
  122. package/dist/chunk-UPJBDCVF.js +0 -1395
  123. package/dist/chunk-V3NN3HPP.js +0 -4462
  124. package/dist/chunk-VJ3L7CHT.cjs +0 -169
  125. package/dist/chunk-WB4Z63GG.js +0 -229
  126. package/dist/chunk-WDW67DZB.cjs +0 -9728
  127. package/dist/chunk-WGMEAYBG.js +0 -126
  128. package/dist/chunk-X4ZF6CNE.cjs +0 -473
  129. package/dist/chunk-X6SEAXAX.cjs +0 -3681
  130. package/dist/chunk-XCWFGZAA.js +0 -1043
  131. package/dist/chunk-XD6IYDUX.js +0 -903
  132. package/dist/chunk-XG23EUQX.cjs +0 -1717
  133. package/dist/chunk-XRKWN5PL.cjs +0 -173
  134. package/dist/chunk-XUILI4KB.cjs +0 -430
  135. package/dist/chunk-XUTX5CBW.js +0 -126
  136. package/dist/chunk-XWPNTWDN.cjs +0 -755
  137. package/dist/chunk-XXINBTZK.cjs +0 -633
  138. package/dist/chunk-YCXFCXDS.js +0 -1868
  139. package/dist/chunk-YQK5JNFK.js +0 -3725
  140. package/dist/chunk-YYXH45E2.js +0 -426
  141. package/dist/chunk-Z34RLXRA.cjs +0 -612
  142. package/dist/chunk-ZP4D3CSX.cjs +0 -72
  143. package/dist/cli/holoscript-runner.cjs +0 -2259
  144. package/dist/cli/holoscript-runner.js +0 -2234
  145. package/dist/codebase/index.cjs +0 -336
  146. package/dist/codebase/index.js +0 -331
  147. package/dist/compiler/agent-inference.cjs +0 -28
  148. package/dist/compiler/agent-inference.js +0 -5
  149. package/dist/compiler/android-xr.cjs +0 -19
  150. package/dist/compiler/android-xr.js +0 -9
  151. package/dist/compiler/android.cjs +0 -20
  152. package/dist/compiler/android.js +0 -10
  153. package/dist/compiler/ar.cjs +0 -20
  154. package/dist/compiler/ar.js +0 -8
  155. package/dist/compiler/babylon.cjs +0 -17
  156. package/dist/compiler/babylon.js +0 -11
  157. package/dist/compiler/coco.cjs +0 -27
  158. package/dist/compiler/coco.js +0 -4
  159. package/dist/compiler/domain-block-utils.cjs +0 -602
  160. package/dist/compiler/domain-block-utils.js +0 -8
  161. package/dist/compiler/dtdl.cjs +0 -24
  162. package/dist/compiler/dtdl.js +0 -8
  163. package/dist/compiler/gltf-pipeline.cjs +0 -39
  164. package/dist/compiler/gltf-pipeline.js +0 -4
  165. package/dist/compiler/godot.cjs +0 -15
  166. package/dist/compiler/godot.js +0 -9
  167. package/dist/compiler/incremental.cjs +0 -29
  168. package/dist/compiler/incremental.js +0 -4
  169. package/dist/compiler/index.cjs +0 -2578
  170. package/dist/compiler/index.js +0 -2383
  171. package/dist/compiler/ios.cjs +0 -20
  172. package/dist/compiler/ios.js +0 -10
  173. package/dist/compiler/multi-layer.cjs +0 -20
  174. package/dist/compiler/multi-layer.js +0 -11
  175. package/dist/compiler/nodetoy.cjs +0 -23
  176. package/dist/compiler/nodetoy.js +0 -4
  177. package/dist/compiler/openxr.cjs +0 -15
  178. package/dist/compiler/openxr.js +0 -9
  179. package/dist/compiler/playcanvas.cjs +0 -16
  180. package/dist/compiler/playcanvas.js +0 -10
  181. package/dist/compiler/r3f.cjs +0 -34
  182. package/dist/compiler/r3f.js +0 -12
  183. package/dist/compiler/remotion.cjs +0 -23
  184. package/dist/compiler/remotion.js +0 -4
  185. package/dist/compiler/reproducibility.cjs +0 -39
  186. package/dist/compiler/reproducibility.js +0 -4
  187. package/dist/compiler/sdf.cjs +0 -21
  188. package/dist/compiler/sdf.js +0 -9
  189. package/dist/compiler/semantic-scene.cjs +0 -31
  190. package/dist/compiler/semantic-scene.js +0 -4
  191. package/dist/compiler/state.cjs +0 -17
  192. package/dist/compiler/state.js +0 -7
  193. package/dist/compiler/trait-composition.cjs +0 -26
  194. package/dist/compiler/trait-composition.js +0 -5
  195. package/dist/compiler/unity.cjs +0 -15
  196. package/dist/compiler/unity.js +0 -9
  197. package/dist/compiler/unreal.cjs +0 -19
  198. package/dist/compiler/unreal.js +0 -9
  199. package/dist/compiler/urdf.cjs +0 -45
  200. package/dist/compiler/urdf.js +0 -9
  201. package/dist/compiler/usd-physics.cjs +0 -23
  202. package/dist/compiler/usd-physics.js +0 -6
  203. package/dist/compiler/visionos.cjs +0 -15
  204. package/dist/compiler/visionos.js +0 -9
  205. package/dist/compiler/vrchat.cjs +0 -19
  206. package/dist/compiler/vrchat.js +0 -9
  207. package/dist/compiler/vrr.cjs +0 -21
  208. package/dist/compiler/vrr.js +0 -9
  209. package/dist/compiler/wasm.cjs +0 -33
  210. package/dist/compiler/wasm.js +0 -9
  211. package/dist/compiler/webgpu.cjs +0 -15
  212. package/dist/compiler/webgpu.js +0 -9
  213. package/dist/debugger.cjs +0 -21
  214. package/dist/debugger.js +0 -8
  215. package/dist/entries/interop.cjs +0 -62
  216. package/dist/entries/interop.js +0 -5
  217. package/dist/entries/scripting.cjs +0 -68
  218. package/dist/entries/scripting.js +0 -11
  219. package/dist/index.cjs +0 -40921
  220. package/dist/index.js +0 -37763
  221. package/dist/math/vec3.cjs +0 -57
  222. package/dist/math/vec3.js +0 -4
  223. package/dist/ml-dsa-PHCWUBPX.cjs +0 -1178
  224. package/dist/ml-dsa-WYLJHJO6.js +0 -1178
  225. package/dist/parser.cjs +0 -27
  226. package/dist/parser.js +0 -10
  227. package/dist/playwright-5OSAPTNH.js +0 -98660
  228. package/dist/playwright-RL6GY4F7.cjs +0 -98673
  229. package/dist/runtime.cjs +0 -16
  230. package/dist/runtime.js +0 -7
  231. package/dist/storage/index.cjs +0 -37
  232. package/dist/storage/index.js +0 -4
  233. package/dist/traits/index.cjs +0 -14649
  234. package/dist/traits/index.js +0 -12243
  235. package/dist/type-checker.cjs +0 -18
  236. package/dist/type-checker.js +0 -5
@@ -1,3725 +0,0 @@
1
- import { init_CompilerBase, init_ANSNamespace, ANSCapabilityPath, escapeStringValue } from './chunk-6XSERL6L.js';
2
- import { __esm } from './chunk-2CWOLHTE.js';
3
-
4
- // src/compiler/DomainBlockCompilerMixin.ts
5
- function esc(value, target) {
6
- return escapeStringValue(value, target);
7
- }
8
- function compileMaterialBlock(block) {
9
- const type = block.keyword === "unlit_material" ? "unlit" : block.keyword === "shader" ? "shader" : "pbr";
10
- const textureMaps = {};
11
- const otherProps = {};
12
- for (const [key, value] of Object.entries(block.properties || {})) {
13
- if (key.endsWith("_map")) {
14
- textureMaps[key] = String(value);
15
- } else {
16
- otherProps[key] = value;
17
- }
18
- }
19
- return {
20
- name: block.name || "unnamed",
21
- type,
22
- baseColor: otherProps.baseColor,
23
- roughness: otherProps.roughness,
24
- metallic: otherProps.metallic,
25
- opacity: otherProps.opacity,
26
- ior: otherProps.ior,
27
- emissiveColor: otherProps.emissive_color,
28
- emissiveIntensity: otherProps.emissive_intensity,
29
- textureMaps,
30
- traits: block.traits || []
31
- };
32
- }
33
- function compilePhysicsBlock(block) {
34
- const colliders = [];
35
- const forceFields = [];
36
- const joints = [];
37
- let rigidbody;
38
- for (const child of block.children || []) {
39
- const c = child;
40
- if (c.type !== "DomainBlock") continue;
41
- const kw = c.keyword;
42
- if (kw === "collider" || kw === "trigger") {
43
- colliders.push({
44
- type: kw,
45
- shape: c.name,
46
- // shape stored as name for collider blocks
47
- properties: c.properties || {}
48
- });
49
- } else if (kw === "rigidbody") {
50
- rigidbody = { properties: c.properties || {} };
51
- } else if ([
52
- "force_field",
53
- "gravity_zone",
54
- "wind_zone",
55
- "buoyancy_zone",
56
- "magnetic_field",
57
- "drag_zone"
58
- ].includes(kw)) {
59
- forceFields.push({
60
- keyword: kw,
61
- name: c.name,
62
- properties: c.properties || {}
63
- });
64
- } else {
65
- joints.push({
66
- keyword: kw,
67
- name: c.name,
68
- properties: c.properties || {}
69
- });
70
- }
71
- }
72
- return {
73
- keyword: block.keyword,
74
- name: block.name,
75
- properties: block.properties || {},
76
- colliders: colliders.length > 0 ? colliders : void 0,
77
- rigidbody,
78
- forceFields: forceFields.length > 0 ? forceFields : void 0,
79
- joints: joints.length > 0 ? joints : void 0
80
- };
81
- }
82
- function compileParticleBlock(block) {
83
- const modules = [];
84
- for (const child of block.children || []) {
85
- const c = child;
86
- if (c.type === "DomainBlock") {
87
- modules.push({
88
- type: c.keyword,
89
- properties: c.properties || {}
90
- });
91
- }
92
- }
93
- return {
94
- keyword: block.keyword,
95
- name: block.name || "unnamed",
96
- traits: block.traits || [],
97
- properties: block.properties || {},
98
- modules
99
- };
100
- }
101
- function compilePostProcessingBlock(block) {
102
- const effects = [];
103
- for (const child of block.children || []) {
104
- const c = child;
105
- if (c.type === "DomainBlock") {
106
- effects.push({
107
- type: c.keyword,
108
- properties: c.properties || {}
109
- });
110
- }
111
- }
112
- return {
113
- keyword: block.keyword,
114
- name: block.name,
115
- effects
116
- };
117
- }
118
- function compileAudioSourceBlock(block) {
119
- return {
120
- keyword: block.keyword,
121
- name: block.name || "unnamed",
122
- traits: block.traits || [],
123
- properties: block.properties || {}
124
- };
125
- }
126
- function compileWeatherBlock(block) {
127
- const layers = [];
128
- for (const child of block.children || []) {
129
- const c = child;
130
- if (c.type === "DomainBlock") {
131
- layers.push({
132
- type: c.keyword,
133
- properties: c.properties || {}
134
- });
135
- }
136
- }
137
- return {
138
- keyword: block.keyword,
139
- name: block.name,
140
- traits: block.traits || [],
141
- properties: block.properties || {},
142
- layers
143
- };
144
- }
145
- function particlesToR3F(ps, tier) {
146
- const scale = tier?.particleScale ?? 1;
147
- const props = [];
148
- if (ps.properties.rate)
149
- props.push(`rate={${Math.round(ps.properties.rate * scale)}}`);
150
- if (ps.properties.max_particles)
151
- props.push(`maxParticles={${Math.round(ps.properties.max_particles * scale)}}`);
152
- if (ps.properties.start_lifetime) {
153
- const lt = ps.properties.start_lifetime;
154
- props.push(Array.isArray(lt) ? `lifetime={[${lt.join(", ")}]}` : `lifetime={${lt}}`);
155
- }
156
- if (ps.properties.start_speed) {
157
- const sp = ps.properties.start_speed;
158
- props.push(Array.isArray(sp) ? `speed={[${sp.join(", ")}]}` : `speed={${sp}}`);
159
- }
160
- if (ps.properties.gravity_modifier !== void 0) {
161
- props.push(`gravityModifier={${ps.properties.gravity_modifier}}`);
162
- }
163
- const isLooping = ps.traits.includes("looping");
164
- if (isLooping) props.push("loop");
165
- const modulesJSX = ps.modules.map((m) => {
166
- const mProps = Object.entries(m.properties).map(([k, v]) => {
167
- const camel = k.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
168
- return typeof v === "string" ? `${camel}="${v}"` : `${camel}={${JSON.stringify(v)}}`;
169
- }).join(" ");
170
- return ` <${m.type} ${mProps} />`;
171
- }).join("\n");
172
- return [`<ParticleSystem name="${ps.name}" ${props.join(" ")}>`, modulesJSX, "</ParticleSystem>"].filter(Boolean).join("\n");
173
- }
174
- function postProcessingToR3F(pp) {
175
- const effectsJSX = pp.effects.map((e) => {
176
- const componentName = e.type.split("_").map((w) => w[0].toUpperCase() + w.slice(1)).join("");
177
- const props = Object.entries(e.properties).map(([k, v]) => {
178
- const camel = k.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
179
- return typeof v === "string" ? `${camel}="${v}"` : `${camel}={${JSON.stringify(v)}}`;
180
- }).join(" ");
181
- return ` <${componentName} ${props} />`;
182
- }).join("\n");
183
- return ["<EffectComposer>", effectsJSX, "</EffectComposer>"].join("\n");
184
- }
185
- function audioSourceToR3F(audio) {
186
- const spatialBlend = typeof audio.properties.spatial_blend === "number" ? audio.properties.spatial_blend : 0;
187
- const isSpatial = audio.traits.includes("spatial") || spatialBlend > 0;
188
- const tag = isSpatial ? "PositionalAudio" : "Audio";
189
- const props = [];
190
- if (audio.properties.clip) props.push(`url="${audio.properties.clip}"`);
191
- if (audio.properties.volume !== void 0) props.push(`volume={${audio.properties.volume}}`);
192
- if (audio.properties.loop !== void 0) props.push(`loop={${audio.properties.loop}}`);
193
- if (isSpatial && audio.properties.max_distance) {
194
- props.push(`distance={${audio.properties.max_distance}}`);
195
- }
196
- if (audio.properties.play_on_awake) props.push("autoplay");
197
- return `<${tag} name="${audio.name}" ${props.join(" ")} />`;
198
- }
199
- function weatherToUSD(weather) {
200
- const lines = [`def Scope "${weather.name || "Weather"}" {`];
201
- for (const [key, value] of Object.entries(weather.properties)) {
202
- lines.push(
203
- ` custom ${typeof value === "number" ? "float" : "string"} ${key} = ${JSON.stringify(value)}`
204
- );
205
- }
206
- for (const layer of weather.layers) {
207
- lines.push(` def Scope "${layer.type}" {`);
208
- for (const [key, value] of Object.entries(layer.properties)) {
209
- const usdType = typeof value === "number" ? "float" : typeof value === "boolean" ? "bool" : Array.isArray(value) ? "float3" : "string";
210
- const usdVal = Array.isArray(value) ? `(${value.join(", ")})` : JSON.stringify(value);
211
- lines.push(` custom ${usdType} ${key} = ${usdVal}`);
212
- }
213
- lines.push(" }");
214
- }
215
- lines.push("}");
216
- return lines.join("\n");
217
- }
218
- function materialToR3F(mat, tier) {
219
- const shaderLevel = tier?.shaderComplexity ?? "physical";
220
- if (shaderLevel === "basic" && mat.type !== "unlit") {
221
- const props2 = [
222
- mat.baseColor ? `color="${mat.baseColor}"` : "",
223
- mat.opacity !== void 0 ? `opacity={${mat.opacity}} transparent` : ""
224
- ].filter(Boolean).join(" ");
225
- return `<meshBasicMaterial ${props2} />`;
226
- }
227
- if (mat.type === "unlit") {
228
- const props2 = [
229
- mat.emissiveColor ? `emissive="${mat.emissiveColor}"` : "",
230
- mat.emissiveIntensity ? `emissiveIntensity={${mat.emissiveIntensity}}` : "",
231
- mat.opacity !== void 0 ? `opacity={${mat.opacity}} transparent` : ""
232
- ].filter(Boolean).join(" ");
233
- return `<meshBasicMaterial ${props2} />`;
234
- }
235
- const props = [
236
- mat.baseColor ? `color="${mat.baseColor}"` : "",
237
- mat.roughness !== void 0 ? `roughness={${mat.roughness}}` : "",
238
- mat.metallic !== void 0 ? `metalness={${mat.metallic}}` : "",
239
- mat.opacity !== void 0 ? `opacity={${mat.opacity}} transparent` : "",
240
- mat.emissiveColor ? `emissive="${mat.emissiveColor}"` : "",
241
- mat.emissiveIntensity ? `emissiveIntensity={${mat.emissiveIntensity}}` : ""
242
- ].filter(Boolean).join(" ");
243
- const textures = Object.entries(mat.textureMaps).map(([type, path]) => {
244
- const propName = type.replace(/_map$/, "Map").replace(/^albedo/, "");
245
- return `${propName}={useTexture("${path}")}`;
246
- }).join(" ");
247
- return `<meshStandardMaterial ${props} ${textures} />`;
248
- }
249
- function materialToUSD(mat) {
250
- const lines = [
251
- `def Material "${mat.name}" {`,
252
- ` token outputs:surface.connect = <${mat.name}/PBRShader.outputs:surface>`,
253
- ` def Shader "PBRShader" {`,
254
- ` uniform token info:id = "UsdPreviewSurface"`
255
- ];
256
- if (mat.baseColor)
257
- lines.push(` color3f inputs:diffuseColor = (${hexToRGB(mat.baseColor)})`);
258
- if (mat.roughness !== void 0) lines.push(` float inputs:roughness = ${mat.roughness}`);
259
- if (mat.metallic !== void 0) lines.push(` float inputs:metallic = ${mat.metallic}`);
260
- if (mat.opacity !== void 0) lines.push(` float inputs:opacity = ${mat.opacity}`);
261
- if (mat.ior !== void 0) lines.push(` float inputs:ior = ${mat.ior}`);
262
- if (mat.emissiveColor) {
263
- const rgb = hexToRGB(mat.emissiveColor).split(", ").map(Number);
264
- const intensity = mat.emissiveIntensity ?? 1;
265
- const scaled = rgb.map((c) => Math.min(1, c * intensity));
266
- lines.push(` color3f inputs:emissiveColor = (${scaled.join(", ")})`);
267
- }
268
- lines.push(` token outputs:surface`);
269
- lines.push(` }`);
270
- const texEntries = Object.entries(mat.textureMaps);
271
- if (texEntries.length > 0) {
272
- const TEX_MAP = {
273
- albedo_map: { input: "diffuseColor", type: "rgb" },
274
- normal_map: { input: "normal", type: "rgb" },
275
- roughness_map: { input: "roughness", type: "r" },
276
- metallic_map: { input: "metallic", type: "r" },
277
- ao_map: { input: "occlusion", type: "r" },
278
- emission_map: { input: "emissiveColor", type: "rgb" },
279
- displacement_map: { input: "displacement", type: "r" }
280
- };
281
- lines.push(` def Shader "stReader" {`);
282
- lines.push(` uniform token info:id = "UsdPrimvarReader_float2"`);
283
- lines.push(` token inputs:varname = "st"`);
284
- lines.push(` float2 outputs:result`);
285
- lines.push(` }`);
286
- for (const [channel, path] of texEntries) {
287
- const mapping = TEX_MAP[channel];
288
- if (!mapping) continue;
289
- const readerName = `${mapping.input}Texture`;
290
- lines.push(` def Shader "${readerName}" {`);
291
- lines.push(` uniform token info:id = "UsdUVTexture"`);
292
- lines.push(` asset inputs:file = @textures/${path}@`);
293
- lines.push(` float2 inputs:st.connect = <${mat.name}/stReader.outputs:result>`);
294
- if (mapping.type === "rgb") {
295
- lines.push(` color3f outputs:rgb`);
296
- } else {
297
- lines.push(` float outputs:r`);
298
- }
299
- lines.push(` }`);
300
- }
301
- }
302
- lines.push(`}`);
303
- return lines.join("\n");
304
- }
305
- function materialToGLTF(mat) {
306
- const gltfMat = { name: mat.name };
307
- if (mat.type === "pbr" || mat.type === "shader") {
308
- gltfMat.pbrMetallicRoughness = {
309
- baseColorFactor: mat.baseColor ? hexToRGBA(mat.baseColor, mat.opacity ?? 1) : [1, 1, 1, 1],
310
- metallicFactor: mat.metallic ?? 0,
311
- roughnessFactor: mat.roughness ?? 0.5
312
- };
313
- }
314
- if (mat.emissiveColor) {
315
- gltfMat.emissiveFactor = hexToRGB(mat.emissiveColor).split(", ").map(Number);
316
- }
317
- return gltfMat;
318
- }
319
- function jointKeywordToURDF(keyword) {
320
- switch (keyword) {
321
- case "hinge":
322
- return "revolute";
323
- case "slider":
324
- case "prismatic":
325
- return "prismatic";
326
- case "ball_socket":
327
- return "ball";
328
- case "fixed_joint":
329
- return "fixed";
330
- case "d6_joint":
331
- return "floating";
332
- case "spring_joint":
333
- return "revolute";
334
- // closest URDF equivalent
335
- default:
336
- return "fixed";
337
- }
338
- }
339
- function colliderToURDF(collider) {
340
- const shape = collider.shape || "box";
341
- const props = collider.properties;
342
- const lines = [" <collision>"];
343
- switch (shape) {
344
- case "sphere":
345
- lines.push(` <geometry><sphere radius="${props.radius || 0.5}"/></geometry>`);
346
- break;
347
- case "capsule":
348
- lines.push(
349
- ` <geometry><cylinder radius="${props.radius || 0.5}" length="${props.height || 1}"/></geometry>`
350
- );
351
- break;
352
- case "box":
353
- default: {
354
- const size = Array.isArray(props.size) ? props.size.join(" ") : "1 1 1";
355
- lines.push(` <geometry><box size="${size}"/></geometry>`);
356
- break;
357
- }
358
- }
359
- lines.push(" </collision>");
360
- return lines.join("\n");
361
- }
362
- function rigidbodyToURDF(rb) {
363
- const mass = rb.properties.mass ?? 1;
364
- const inertiaValues = Array.isArray(rb.properties.inertia) ? rb.properties.inertia : void 0;
365
- return [
366
- " <inertial>",
367
- ` <mass value="${mass}"/>`,
368
- inertiaValues ? ` <inertia ixx="${inertiaValues[0] || 0}" iyy="${inertiaValues[1] || 0}" izz="${inertiaValues[2] || 0}" ixy="0" ixz="0" iyz="0"/>` : ` <inertia ixx="0.01" iyy="0.01" izz="0.01" ixy="0" ixz="0" iyz="0"/>`,
369
- " </inertial>"
370
- ].join("\n");
371
- }
372
- function physicsToURDF(physics) {
373
- const parts = [];
374
- if (physics.keyword === "articulation") {
375
- const joints = (physics.joints || []).map((j) => {
376
- const props = j.properties;
377
- const limitsValues = Array.isArray(props.limits) ? props.limits : void 0;
378
- return [
379
- ` <joint name="${j.name}" type="${jointKeywordToURDF(j.keyword)}">`,
380
- props.axis ? ` <axis xyz="${Array.isArray(props.axis) ? props.axis.join(" ") : "0 0 1"}"/>` : "",
381
- limitsValues ? ` <limit lower="${limitsValues[0]}" upper="${limitsValues[1]}"/>` : "",
382
- props.damping ? ` <dynamics damping="${props.damping}"/>` : "",
383
- ` </joint>`
384
- ].filter(Boolean).join("\n");
385
- });
386
- parts.push(...joints);
387
- }
388
- if (physics.colliders) {
389
- for (const collider of physics.colliders) {
390
- parts.push(colliderToURDF(collider));
391
- }
392
- }
393
- if (physics.rigidbody) {
394
- parts.push(rigidbodyToURDF(physics.rigidbody));
395
- }
396
- if (physics.forceFields) {
397
- for (const ff of physics.forceFields) {
398
- parts.push(
399
- ` <!-- ${ff.keyword} "${ff.name || ""}" strength="${ff.properties.strength || 0}" -->`
400
- );
401
- }
402
- }
403
- if (parts.length > 0) return parts.join("\n");
404
- return `<!-- ${physics.keyword} ${physics.name || ""} -->`;
405
- }
406
- function materialToUnity(mat, varPrefix) {
407
- const lines = [];
408
- lines.push(`// Material: ${mat.name}`);
409
- lines.push(
410
- `var ${varPrefix}Mat = new Material(Shader.Find("${mat.type === "unlit" ? "Unlit/Color" : "Standard"}"));`
411
- );
412
- if (mat.baseColor) lines.push(`${varPrefix}Mat.color = ${hexToUnityColor(mat.baseColor)};`);
413
- if (mat.roughness !== void 0)
414
- lines.push(`${varPrefix}Mat.SetFloat("_Smoothness", ${(1 - mat.roughness).toFixed(3)}f);`);
415
- if (mat.metallic !== void 0)
416
- lines.push(`${varPrefix}Mat.SetFloat("_Metallic", ${mat.metallic}f);`);
417
- if (mat.opacity !== void 0 && mat.opacity < 1) {
418
- lines.push(`${varPrefix}Mat.SetFloat("_Mode", 3); // Transparent`);
419
- lines.push(
420
- `${varPrefix}Mat.color = new Color(${varPrefix}Mat.color.r, ${varPrefix}Mat.color.g, ${varPrefix}Mat.color.b, ${mat.opacity}f);`
421
- );
422
- }
423
- if (mat.emissiveColor) {
424
- lines.push(`${varPrefix}Mat.EnableKeyword("_EMISSION");`);
425
- lines.push(
426
- `${varPrefix}Mat.SetColor("_EmissionColor", ${hexToUnityColor(mat.emissiveColor)}${mat.emissiveIntensity ? ` * ${mat.emissiveIntensity}f` : ""});`
427
- );
428
- }
429
- for (const [mapType, path] of Object.entries(mat.textureMaps)) {
430
- const shaderProp = mapType === "albedo_map" ? "_MainTex" : mapType === "normal_map" ? "_BumpMap" : mapType === "metallic_map" ? "_MetallicGlossMap" : mapType === "roughness_map" ? "_SpecGlossMap" : mapType === "emission_map" ? "_EmissionMap" : mapType === "occlusion_map" ? "_OcclusionMap" : `_${mapType.replace(/_map$/, "")}`;
431
- lines.push(
432
- `${varPrefix}Mat.SetTexture("${shaderProp}", Resources.Load<Texture2D>("${path}"));`
433
- );
434
- }
435
- return lines.join("\n");
436
- }
437
- function physicsToUnity(physics, varPrefix) {
438
- const lines = [];
439
- lines.push(`// Physics: ${physics.keyword} "${physics.name || ""}"`);
440
- if (physics.rigidbody) {
441
- lines.push(`var ${varPrefix}RB = ${varPrefix}GO.AddComponent<Rigidbody>();`);
442
- const rb = physics.rigidbody.properties;
443
- if (rb.mass !== void 0) lines.push(`${varPrefix}RB.mass = ${rb.mass}f;`);
444
- if (rb.drag !== void 0) lines.push(`${varPrefix}RB.drag = ${rb.drag}f;`);
445
- if (rb.angular_damping !== void 0)
446
- lines.push(`${varPrefix}RB.angularDrag = ${rb.angular_damping}f;`);
447
- if (rb.use_gravity === false) lines.push(`${varPrefix}RB.useGravity = false;`);
448
- }
449
- if (physics.colliders) {
450
- for (let i = 0; i < physics.colliders.length; i++) {
451
- const c = physics.colliders[i];
452
- const shape = c.shape || "box";
453
- const colVar = `${varPrefix}Col${i}`;
454
- if (shape === "sphere") {
455
- lines.push(`var ${colVar} = ${varPrefix}GO.AddComponent<SphereCollider>();`);
456
- if (c.properties.radius) lines.push(`${colVar}.radius = ${c.properties.radius}f;`);
457
- } else if (shape === "capsule") {
458
- lines.push(`var ${colVar} = ${varPrefix}GO.AddComponent<CapsuleCollider>();`);
459
- if (c.properties.radius) lines.push(`${colVar}.radius = ${c.properties.radius}f;`);
460
- if (c.properties.height) lines.push(`${colVar}.height = ${c.properties.height}f;`);
461
- } else {
462
- lines.push(`var ${colVar} = ${varPrefix}GO.AddComponent<BoxCollider>();`);
463
- if (c.properties.size && Array.isArray(c.properties.size)) {
464
- lines.push(`${colVar}.size = new Vector3(${c.properties.size.join("f, ")}f);`);
465
- }
466
- }
467
- if (c.type === "trigger") lines.push(`${colVar}.isTrigger = true;`);
468
- }
469
- }
470
- if (physics.forceFields) {
471
- for (const ff of physics.forceFields) {
472
- if (ff.keyword === "wind_zone") {
473
- lines.push(`var ${varPrefix}Wind = ${varPrefix}GO.AddComponent<WindZone>();`);
474
- if (ff.properties.strength)
475
- lines.push(`${varPrefix}Wind.windMain = ${ff.properties.strength}f;`);
476
- } else {
477
- lines.push(`// ${ff.keyword} "${ff.name || ""}": ${JSON.stringify(ff.properties)}`);
478
- }
479
- }
480
- }
481
- if (physics.joints) {
482
- for (const j of physics.joints) {
483
- lines.push(`// Joint: ${j.keyword} "${j.name || ""}" \u2014 use ConfigurableJoint or HingeJoint`);
484
- }
485
- }
486
- return lines.join("\n");
487
- }
488
- function particlesToUnity(ps, varPrefix) {
489
- const lines = [];
490
- lines.push(`// Particles: ${ps.name}`);
491
- lines.push(`var ${varPrefix}PS = ${varPrefix}GO.AddComponent<ParticleSystem>();`);
492
- lines.push(`var ${varPrefix}Main = ${varPrefix}PS.main;`);
493
- if (ps.properties.max_particles)
494
- lines.push(`${varPrefix}Main.maxParticles = ${ps.properties.max_particles};`);
495
- if (ps.properties.start_lifetime) {
496
- const lt = ps.properties.start_lifetime;
497
- lines.push(`${varPrefix}Main.startLifetime = ${Array.isArray(lt) ? lt[0] : lt}f;`);
498
- }
499
- if (ps.properties.start_speed) {
500
- const sp = ps.properties.start_speed;
501
- lines.push(`${varPrefix}Main.startSpeed = ${Array.isArray(sp) ? sp[0] : sp}f;`);
502
- }
503
- if (ps.properties.gravity_modifier !== void 0) {
504
- lines.push(`${varPrefix}Main.gravityModifier = ${ps.properties.gravity_modifier}f;`);
505
- }
506
- if (ps.traits.includes("looping")) lines.push(`${varPrefix}Main.loop = true;`);
507
- for (const m of ps.modules) {
508
- lines.push(`// Module: ${m.type} \u2014 ${JSON.stringify(m.properties)}`);
509
- }
510
- return lines.join("\n");
511
- }
512
- function postProcessingToUnity(pp) {
513
- const lines = [];
514
- lines.push("// Post-Processing (URP Volume Profile)");
515
- for (const e of pp.effects) {
516
- const className = e.type.split("_").map((w) => w[0].toUpperCase() + w.slice(1)).join("");
517
- lines.push(`// Effect: ${className}`);
518
- for (const [k, v] of Object.entries(e.properties)) {
519
- lines.push(`// ${k} = ${JSON.stringify(v)}`);
520
- }
521
- }
522
- return lines.join("\n");
523
- }
524
- function audioSourceToUnity(audio, varPrefix) {
525
- const lines = [];
526
- lines.push(`// Audio: ${audio.name} (${audio.keyword})`);
527
- if (audio.keyword === "reverb_zone") {
528
- lines.push(`var ${varPrefix}Reverb = ${varPrefix}GO.AddComponent<AudioReverbZone>();`);
529
- if (audio.properties.min_distance)
530
- lines.push(`${varPrefix}Reverb.minDistance = ${audio.properties.min_distance}f;`);
531
- if (audio.properties.max_distance)
532
- lines.push(`${varPrefix}Reverb.maxDistance = ${audio.properties.max_distance}f;`);
533
- } else {
534
- lines.push(`var ${varPrefix}AS = ${varPrefix}GO.AddComponent<AudioSource>();`);
535
- if (audio.properties.clip)
536
- lines.push(
537
- `${varPrefix}AS.clip = Resources.Load<AudioClip>("Audio/${audio.properties.clip}");`
538
- );
539
- if (audio.properties.volume !== void 0)
540
- lines.push(`${varPrefix}AS.volume = ${audio.properties.volume}f;`);
541
- if (audio.properties.loop !== void 0)
542
- lines.push(`${varPrefix}AS.loop = ${audio.properties.loop};`);
543
- if (audio.properties.spatial_blend !== void 0)
544
- lines.push(`${varPrefix}AS.spatialBlend = ${audio.properties.spatial_blend}f;`);
545
- if (audio.properties.max_distance)
546
- lines.push(`${varPrefix}AS.maxDistance = ${audio.properties.max_distance}f;`);
547
- if (audio.traits.includes("spatial") || audio.traits.includes("hrtf")) {
548
- lines.push(`${varPrefix}AS.spatialBlend = 1.0f;`);
549
- }
550
- if (audio.properties.play_on_awake) lines.push(`${varPrefix}AS.playOnAwake = true;`);
551
- }
552
- return lines.join("\n");
553
- }
554
- function weatherToUnity(weather) {
555
- const lines = [];
556
- lines.push(`// Weather: ${weather.keyword} "${weather.name || ""}"`);
557
- for (const layer of weather.layers) {
558
- lines.push(`// Layer: ${layer.type} \u2014 ${JSON.stringify(layer.properties)}`);
559
- }
560
- if (weather.properties.intensity !== void 0) {
561
- lines.push(`// Intensity: ${weather.properties.intensity}`);
562
- }
563
- return lines.join("\n");
564
- }
565
- function materialToUnreal(mat, varPrefix) {
566
- const lines = [];
567
- lines.push(`// Material: ${mat.name}`);
568
- lines.push(`UMaterialInstanceDynamic* ${varPrefix}Mat = UMaterialInstanceDynamic::Create(`);
569
- lines.push(
570
- ` LoadObject<UMaterial>(nullptr, TEXT("/Game/Materials/M_${mat.type === "unlit" ? "Unlit" : "PBR"}")), this);`
571
- );
572
- if (mat.baseColor) {
573
- const [r, g, b] = hexToRGBTuple(mat.baseColor);
574
- lines.push(
575
- `${varPrefix}Mat->SetVectorParameterValue(TEXT("BaseColor"), FLinearColor(${r}f, ${g}f, ${b}f));`
576
- );
577
- }
578
- if (mat.roughness !== void 0)
579
- lines.push(`${varPrefix}Mat->SetScalarParameterValue(TEXT("Roughness"), ${mat.roughness}f);`);
580
- if (mat.metallic !== void 0)
581
- lines.push(`${varPrefix}Mat->SetScalarParameterValue(TEXT("Metallic"), ${mat.metallic}f);`);
582
- if (mat.opacity !== void 0)
583
- lines.push(`${varPrefix}Mat->SetScalarParameterValue(TEXT("Opacity"), ${mat.opacity}f);`);
584
- if (mat.emissiveColor) {
585
- const [r, g, b] = hexToRGBTuple(mat.emissiveColor);
586
- const intensity = mat.emissiveIntensity ?? 1;
587
- lines.push(
588
- `${varPrefix}Mat->SetVectorParameterValue(TEXT("EmissiveColor"), FLinearColor(${r * intensity}f, ${g * intensity}f, ${b * intensity}f));`
589
- );
590
- }
591
- for (const [mapType, path] of Object.entries(mat.textureMaps)) {
592
- lines.push(
593
- `${varPrefix}Mat->SetTextureParameterValue(TEXT("${mapType}"), LoadObject<UTexture2D>(nullptr, TEXT("/Game/Textures/${path}")));`
594
- );
595
- }
596
- return lines.join("\n");
597
- }
598
- function physicsToUnreal(physics, varPrefix) {
599
- const lines = [];
600
- lines.push(`// Physics: ${physics.keyword} "${physics.name || ""}"`);
601
- if (physics.rigidbody) {
602
- const rb = physics.rigidbody.properties;
603
- lines.push(`${varPrefix}Mesh->SetSimulatePhysics(true);`);
604
- if (rb.mass !== void 0)
605
- lines.push(`${varPrefix}Mesh->SetMassOverrideInKg(NAME_None, ${rb.mass}f);`);
606
- if (rb.drag !== void 0) lines.push(`${varPrefix}Mesh->SetLinearDamping(${rb.drag}f);`);
607
- if (rb.angular_damping !== void 0)
608
- lines.push(`${varPrefix}Mesh->SetAngularDamping(${rb.angular_damping}f);`);
609
- if (rb.use_gravity === false) lines.push(`${varPrefix}Mesh->SetEnableGravity(false);`);
610
- }
611
- if (physics.colliders) {
612
- for (const c of physics.colliders) {
613
- const shape = c.shape || "box";
614
- if (shape === "sphere") {
615
- lines.push(
616
- `auto* ${varPrefix}Sphere = CreateDefaultSubobject<USphereComponent>(TEXT("${varPrefix}Sphere"));`
617
- );
618
- if (c.properties.radius)
619
- lines.push(`${varPrefix}Sphere->SetSphereRadius(${c.properties.radius}f);`);
620
- } else if (shape === "capsule") {
621
- lines.push(
622
- `auto* ${varPrefix}Capsule = CreateDefaultSubobject<UCapsuleComponent>(TEXT("${varPrefix}Capsule"));`
623
- );
624
- } else {
625
- lines.push(
626
- `auto* ${varPrefix}Box = CreateDefaultSubobject<UBoxComponent>(TEXT("${varPrefix}Box"));`
627
- );
628
- }
629
- }
630
- }
631
- if (physics.forceFields) {
632
- for (const ff of physics.forceFields) {
633
- lines.push(
634
- `// Force field: ${ff.keyword} "${ff.name || ""}" \u2014 ${JSON.stringify(ff.properties)}`
635
- );
636
- }
637
- }
638
- if (physics.joints) {
639
- for (const j of physics.joints) {
640
- lines.push(
641
- `auto* ${varPrefix}Constraint = CreateDefaultSubobject<UPhysicsConstraintComponent>(TEXT("${j.name || varPrefix + "Joint"}"));`
642
- );
643
- lines.push(`// Joint type: ${j.keyword} \u2014 configure constraint limits`);
644
- }
645
- }
646
- return lines.join("\n");
647
- }
648
- function particlesToUnreal(ps, varPrefix) {
649
- const lines = [];
650
- lines.push(`// Niagara Particles: ${ps.name}`);
651
- lines.push(
652
- `auto* ${varPrefix}Niagara = CreateDefaultSubobject<UNiagaraComponent>(TEXT("${ps.name}"));`
653
- );
654
- lines.push(`${varPrefix}Niagara->SetupAttachment(RootComponent);`);
655
- if (ps.properties.rate)
656
- lines.push(`${varPrefix}Niagara->SetVariableFloat(TEXT("SpawnRate"), ${ps.properties.rate}f);`);
657
- if (ps.properties.start_lifetime)
658
- lines.push(
659
- `${varPrefix}Niagara->SetVariableFloat(TEXT("Lifetime"), ${Array.isArray(ps.properties.start_lifetime) ? ps.properties.start_lifetime[0] : ps.properties.start_lifetime}f);`
660
- );
661
- if (ps.traits.includes("looping"))
662
- lines.push(`${varPrefix}Niagara->SetVariableBool(TEXT("Looping"), true);`);
663
- for (const m of ps.modules) {
664
- lines.push(`// Module: ${m.type} \u2014 ${JSON.stringify(m.properties)}`);
665
- }
666
- return lines.join("\n");
667
- }
668
- function postProcessingToUnreal(pp, varPrefix) {
669
- const lines = [];
670
- lines.push(`// Post-Processing: ${pp.keyword}`);
671
- lines.push(
672
- `auto* ${varPrefix}PP = CreateDefaultSubobject<UPostProcessComponent>(TEXT("PostProcess"));`
673
- );
674
- lines.push(`${varPrefix}PP->SetupAttachment(RootComponent);`);
675
- for (const e of pp.effects) {
676
- if (e.type === "bloom") {
677
- lines.push(`${varPrefix}PP->Settings.bOverride_BloomIntensity = true;`);
678
- if (e.properties.intensity)
679
- lines.push(`${varPrefix}PP->Settings.BloomIntensity = ${e.properties.intensity}f;`);
680
- if (e.properties.threshold)
681
- lines.push(`${varPrefix}PP->Settings.BloomThreshold = ${e.properties.threshold}f;`);
682
- } else if (e.type === "depth_of_field") {
683
- lines.push(`${varPrefix}PP->Settings.bOverride_DepthOfFieldFocalDistance = true;`);
684
- if (e.properties.focal_distance)
685
- lines.push(
686
- `${varPrefix}PP->Settings.DepthOfFieldFocalDistance = ${e.properties.focal_distance}f;`
687
- );
688
- } else {
689
- lines.push(`// Effect: ${e.type} \u2014 ${JSON.stringify(e.properties)}`);
690
- }
691
- }
692
- return lines.join("\n");
693
- }
694
- function audioSourceToUnreal(audio, varPrefix) {
695
- const lines = [];
696
- lines.push(`// Audio: ${audio.name} (${audio.keyword})`);
697
- lines.push(
698
- `auto* ${varPrefix}Audio = CreateDefaultSubobject<UAudioComponent>(TEXT("${audio.name}"));`
699
- );
700
- lines.push(`${varPrefix}Audio->SetupAttachment(RootComponent);`);
701
- if (audio.properties.clip)
702
- lines.push(
703
- `${varPrefix}Audio->SetSound(LoadObject<USoundWave>(nullptr, TEXT("/Game/Audio/${audio.properties.clip}")));`
704
- );
705
- if (audio.properties.volume !== void 0)
706
- lines.push(`${varPrefix}Audio->SetVolumeMultiplier(${audio.properties.volume}f);`);
707
- if (audio.properties.loop !== void 0)
708
- lines.push(`${varPrefix}Audio->bIsLooping = ${audio.properties.loop ? "true" : "false"};`);
709
- if (audio.traits.includes("spatial") || typeof audio.properties.spatial_blend === "number" && audio.properties.spatial_blend > 0) {
710
- lines.push(`${varPrefix}Audio->bOverrideAttenuation = true;`);
711
- if (audio.properties.max_distance)
712
- lines.push(
713
- `${varPrefix}Audio->AttenuationOverrides.FalloffDistance = ${audio.properties.max_distance}f;`
714
- );
715
- }
716
- if (audio.properties.play_on_awake) lines.push(`${varPrefix}Audio->bAutoActivate = true;`);
717
- return lines.join("\n");
718
- }
719
- function weatherToUnreal(weather) {
720
- const lines = [];
721
- lines.push(`// Weather: ${weather.keyword} "${weather.name || ""}"`);
722
- lines.push("// Use UltraDynamicSky or custom weather system");
723
- for (const layer of weather.layers) {
724
- lines.push(`// Layer: ${layer.type} \u2014 ${JSON.stringify(layer.properties)}`);
725
- }
726
- return lines.join("\n");
727
- }
728
- function materialToGodot(mat, varPrefix) {
729
- const lines = [];
730
- lines.push(`# Material: ${mat.name}`);
731
- if (mat.type === "unlit") {
732
- lines.push(`var ${varPrefix}_mat = StandardMaterial3D.new()`);
733
- lines.push(`${varPrefix}_mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED`);
734
- } else {
735
- lines.push(`var ${varPrefix}_mat = StandardMaterial3D.new()`);
736
- }
737
- if (mat.baseColor) lines.push(`${varPrefix}_mat.albedo_color = Color.html("${mat.baseColor}")`);
738
- if (mat.roughness !== void 0) lines.push(`${varPrefix}_mat.roughness = ${mat.roughness}`);
739
- if (mat.metallic !== void 0) lines.push(`${varPrefix}_mat.metallic = ${mat.metallic}`);
740
- if (mat.opacity !== void 0 && mat.opacity < 1) {
741
- lines.push(`${varPrefix}_mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA`);
742
- lines.push(`${varPrefix}_mat.albedo_color.a = ${mat.opacity}`);
743
- }
744
- if (mat.emissiveColor) {
745
- lines.push(`${varPrefix}_mat.emission_enabled = true`);
746
- lines.push(`${varPrefix}_mat.emission = Color.html("${mat.emissiveColor}")`);
747
- if (mat.emissiveIntensity)
748
- lines.push(`${varPrefix}_mat.emission_energy_multiplier = ${mat.emissiveIntensity}`);
749
- }
750
- for (const [mapType, path] of Object.entries(mat.textureMaps)) {
751
- const prop = mapType === "albedo_map" ? "albedo_texture" : mapType === "normal_map" ? "normal_texture" : mapType === "metallic_map" ? "metallic_texture" : mapType === "roughness_map" ? "roughness_texture" : mapType === "emission_map" ? "emission_texture" : `${mapType.replace(/_map$/, "_texture")}`;
752
- lines.push(`${varPrefix}_mat.${prop} = load("res://${path}")`);
753
- }
754
- return lines.join("\n");
755
- }
756
- function physicsToGodot(physics, varPrefix) {
757
- const lines = [];
758
- lines.push(`# Physics: ${physics.keyword} "${physics.name || ""}"`);
759
- if (physics.rigidbody) {
760
- const rb = physics.rigidbody.properties;
761
- lines.push(`var ${varPrefix}_rb = RigidBody3D.new()`);
762
- if (rb.mass !== void 0) lines.push(`${varPrefix}_rb.mass = ${rb.mass}`);
763
- if (rb.drag !== void 0) lines.push(`${varPrefix}_rb.linear_damp = ${rb.drag}`);
764
- if (rb.angular_damping !== void 0)
765
- lines.push(`${varPrefix}_rb.angular_damp = ${rb.angular_damping}`);
766
- if (rb.use_gravity === false) lines.push(`${varPrefix}_rb.gravity_scale = 0.0`);
767
- }
768
- if (physics.colliders) {
769
- for (let i = 0; i < physics.colliders.length; i++) {
770
- const c = physics.colliders[i];
771
- const shape = c.shape || "box";
772
- if (shape === "sphere") {
773
- lines.push(`var ${varPrefix}_col${i} = CollisionShape3D.new()`);
774
- lines.push(`${varPrefix}_col${i}.shape = SphereShape3D.new()`);
775
- if (c.properties.radius)
776
- lines.push(`${varPrefix}_col${i}.shape.radius = ${c.properties.radius}`);
777
- } else if (shape === "capsule") {
778
- lines.push(`var ${varPrefix}_col${i} = CollisionShape3D.new()`);
779
- lines.push(`${varPrefix}_col${i}.shape = CapsuleShape3D.new()`);
780
- } else {
781
- lines.push(`var ${varPrefix}_col${i} = CollisionShape3D.new()`);
782
- lines.push(`${varPrefix}_col${i}.shape = BoxShape3D.new()`);
783
- }
784
- }
785
- }
786
- if (physics.forceFields) {
787
- for (const ff of physics.forceFields) {
788
- lines.push(
789
- `# Force field: ${ff.keyword} "${ff.name || ""}" \u2014 ${JSON.stringify(ff.properties)}`
790
- );
791
- }
792
- }
793
- if (physics.joints) {
794
- for (const j of physics.joints) {
795
- const jointType = j.keyword === "hinge" ? "HingeJoint3D" : j.keyword === "slider" ? "SliderJoint3D" : "Generic6DOFJoint3D";
796
- lines.push(`var ${varPrefix}_joint = ${jointType}.new()`);
797
- lines.push(`# Joint: ${j.keyword} "${j.name || ""}" \u2014 ${JSON.stringify(j.properties)}`);
798
- }
799
- }
800
- return lines.join("\n");
801
- }
802
- function particlesToGodot(ps, varPrefix) {
803
- const lines = [];
804
- lines.push(`# Particles: ${ps.name}`);
805
- lines.push(`var ${varPrefix}_particles = GPUParticles3D.new()`);
806
- lines.push(`${varPrefix}_particles.name = "${ps.name}"`);
807
- if (ps.properties.max_particles)
808
- lines.push(`${varPrefix}_particles.amount = ${ps.properties.max_particles}`);
809
- if (ps.properties.start_lifetime) {
810
- const lt = Array.isArray(ps.properties.start_lifetime) ? ps.properties.start_lifetime[0] : ps.properties.start_lifetime;
811
- lines.push(`${varPrefix}_particles.lifetime = ${lt}`);
812
- }
813
- if (ps.traits.includes("looping")) lines.push(`${varPrefix}_particles.one_shot = false`);
814
- else lines.push(`${varPrefix}_particles.one_shot = true`);
815
- for (const m of ps.modules) {
816
- lines.push(`# Module: ${m.type} \u2014 ${JSON.stringify(m.properties)}`);
817
- }
818
- return lines.join("\n");
819
- }
820
- function postProcessingToGodot(pp) {
821
- const lines = [];
822
- lines.push(`# Post-Processing: ${pp.keyword} (use WorldEnvironment)`);
823
- lines.push("var env = WorldEnvironment.new()");
824
- lines.push("var environment = Environment.new()");
825
- for (const e of pp.effects) {
826
- if (e.type === "bloom" || e.type === "glow") {
827
- lines.push("environment.glow_enabled = true");
828
- if (e.properties.intensity)
829
- lines.push(`environment.glow_intensity = ${e.properties.intensity}`);
830
- if (e.properties.threshold) lines.push(`environment.glow_bloom = ${e.properties.threshold}`);
831
- } else if (e.type === "fog") {
832
- lines.push("environment.fog_enabled = true");
833
- if (e.properties.density) lines.push(`environment.fog_density = ${e.properties.density}`);
834
- } else {
835
- lines.push(`# Effect: ${e.type} \u2014 ${JSON.stringify(e.properties)}`);
836
- }
837
- }
838
- lines.push("env.environment = environment");
839
- return lines.join("\n");
840
- }
841
- function audioSourceToGodot(audio, varPrefix) {
842
- const lines = [];
843
- lines.push(`# Audio: ${audio.name} (${audio.keyword})`);
844
- const isSpatial = audio.traits.includes("spatial") || typeof audio.properties.spatial_blend === "number" && audio.properties.spatial_blend > 0;
845
- const nodeType = isSpatial ? "AudioStreamPlayer3D" : "AudioStreamPlayer";
846
- lines.push(`var ${varPrefix}_audio = ${nodeType}.new()`);
847
- lines.push(`${varPrefix}_audio.name = "${audio.name}"`);
848
- if (audio.properties.clip)
849
- lines.push(`${varPrefix}_audio.stream = load("res://${audio.properties.clip}")`);
850
- if (audio.properties.volume !== void 0)
851
- lines.push(`${varPrefix}_audio.volume_db = linear_to_db(${audio.properties.volume})`);
852
- if (isSpatial && audio.properties.max_distance) {
853
- lines.push(`${varPrefix}_audio.max_distance = ${audio.properties.max_distance}`);
854
- }
855
- if (audio.properties.play_on_awake) lines.push(`${varPrefix}_audio.autoplay = true`);
856
- return lines.join("\n");
857
- }
858
- function weatherToGodot(weather) {
859
- const lines = [];
860
- lines.push(`# Weather: ${weather.keyword} "${weather.name || ""}"`);
861
- for (const layer of weather.layers) {
862
- lines.push(`# Layer: ${layer.type} \u2014 ${JSON.stringify(layer.properties)}`);
863
- }
864
- return lines.join("\n");
865
- }
866
- function materialToVisionOS(mat, varPrefix) {
867
- const lines = [];
868
- lines.push(`// Material: ${mat.name}`);
869
- if (mat.type === "unlit") {
870
- lines.push(`var ${varPrefix}Mat = UnlitMaterial()`);
871
- if (mat.baseColor)
872
- lines.push(`${varPrefix}Mat.color = .init(tint: ${hexToSwiftColor(mat.baseColor)})`);
873
- } else {
874
- lines.push(`var ${varPrefix}Mat = PhysicallyBasedMaterial()`);
875
- if (mat.baseColor)
876
- lines.push(`${varPrefix}Mat.baseColor = .init(tint: ${hexToSwiftColor(mat.baseColor)})`);
877
- if (mat.roughness !== void 0)
878
- lines.push(`${varPrefix}Mat.roughness = .init(floatLiteral: ${mat.roughness})`);
879
- if (mat.metallic !== void 0)
880
- lines.push(`${varPrefix}Mat.metallic = .init(floatLiteral: ${mat.metallic})`);
881
- if (mat.opacity !== void 0 && mat.opacity < 1)
882
- lines.push(
883
- `${varPrefix}Mat.blending = .transparent(opacity: .init(floatLiteral: ${mat.opacity}))`
884
- );
885
- if (mat.emissiveColor) {
886
- lines.push(
887
- `${varPrefix}Mat.emissiveColor = .init(color: ${hexToSwiftColor(mat.emissiveColor)})`
888
- );
889
- if (mat.emissiveIntensity)
890
- lines.push(`${varPrefix}Mat.emissiveIntensity = ${mat.emissiveIntensity}`);
891
- }
892
- }
893
- for (const [mapType, path] of Object.entries(mat.textureMaps)) {
894
- const prop = mapType === "albedo_map" ? "baseColor" : mapType === "normal_map" ? "normal" : mapType === "metallic_map" ? "metallic" : mapType === "roughness_map" ? "roughness" : mapType;
895
- lines.push(`${varPrefix}Mat.${prop} = .init(texture: .init(try! .load(named: "${path}")))`);
896
- }
897
- return lines.join("\n");
898
- }
899
- function physicsToVisionOS(physics, varPrefix) {
900
- const lines = [];
901
- lines.push(`// Physics: ${physics.keyword} "${physics.name || ""}"`);
902
- if (physics.colliders) {
903
- for (const c of physics.colliders) {
904
- const shape = c.shape || "box";
905
- if (shape === "sphere") {
906
- lines.push(
907
- `${varPrefix}Entity.components.set(CollisionComponent(shapes: [.generateSphere(radius: ${c.properties.radius || 0.5})]))`
908
- );
909
- } else if (shape === "capsule") {
910
- lines.push(
911
- `${varPrefix}Entity.components.set(CollisionComponent(shapes: [.generateCapsule(height: ${c.properties.height || 1}, radius: ${c.properties.radius || 0.25})]))`
912
- );
913
- } else {
914
- const size = c.properties.size && Array.isArray(c.properties.size) ? c.properties.size : [1, 1, 1];
915
- lines.push(
916
- `${varPrefix}Entity.components.set(CollisionComponent(shapes: [.generateBox(size: [${size.join(", ")}])]))`
917
- );
918
- }
919
- }
920
- }
921
- if (physics.rigidbody) {
922
- const rb = physics.rigidbody.properties;
923
- lines.push(
924
- `var ${varPrefix}Physics = PhysicsBodyComponent(massProperties: .init(mass: ${rb.mass ?? 1}), mode: .dynamic)`
925
- );
926
- if (rb.drag !== void 0) lines.push(`${varPrefix}Physics.linearDamping = ${rb.drag}`);
927
- if (rb.angular_damping !== void 0)
928
- lines.push(`${varPrefix}Physics.angularDamping = ${rb.angular_damping}`);
929
- lines.push(`${varPrefix}Entity.components.set(${varPrefix}Physics)`);
930
- }
931
- if (physics.joints) {
932
- for (const j of physics.joints) {
933
- lines.push(`// Joint: ${j.keyword} "${j.name || ""}" \u2014 use PhysicsJoint`);
934
- }
935
- }
936
- return lines.join("\n");
937
- }
938
- function particlesToVisionOS(ps, varPrefix) {
939
- const lines = [];
940
- lines.push(`// Particles: ${ps.name}`);
941
- lines.push(`var ${varPrefix}Particles = ParticleEmitterComponent()`);
942
- if (ps.properties.rate) lines.push(`${varPrefix}Particles.birthRate = ${ps.properties.rate}`);
943
- if (ps.properties.start_lifetime) {
944
- const lt = Array.isArray(ps.properties.start_lifetime) ? ps.properties.start_lifetime[0] : ps.properties.start_lifetime;
945
- lines.push(`${varPrefix}Particles.lifeSpan = ${lt}`);
946
- }
947
- if (ps.traits.includes("looping")) lines.push(`${varPrefix}Particles.isEmitting = true`);
948
- lines.push(`${varPrefix}Entity.components.set(${varPrefix}Particles)`);
949
- return lines.join("\n");
950
- }
951
- function audioSourceToVisionOS(audio, varPrefix) {
952
- const lines = [];
953
- lines.push(`// Audio: ${audio.name} (${audio.keyword})`);
954
- const isSpatial = audio.traits.includes("spatial") || typeof audio.properties.spatial_blend === "number" && audio.properties.spatial_blend > 0;
955
- if (isSpatial) {
956
- lines.push(`let ${varPrefix}Audio = Entity()`);
957
- lines.push(`${varPrefix}Audio.spatialAudio = SpatialAudioComponent()`);
958
- if (audio.properties.max_distance)
959
- lines.push(
960
- `${varPrefix}Audio.spatialAudio?.distanceAttenuation = .rolloff(factor: .custom(${audio.properties.max_distance}))`
961
- );
962
- }
963
- lines.push(
964
- `let ${varPrefix}Resource = try! AudioFileResource.load(named: "${audio.properties.clip || audio.name}")`
965
- );
966
- lines.push(`let ${varPrefix}Controller = ${varPrefix}Entity.prepareAudio(${varPrefix}Resource)`);
967
- if (audio.properties.volume !== void 0)
968
- lines.push(
969
- `${varPrefix}Controller.gain = AudioPlaybackController.Decibel(${audio.properties.volume})`
970
- );
971
- if (audio.properties.play_on_awake) lines.push(`${varPrefix}Controller.play()`);
972
- return lines.join("\n");
973
- }
974
- function materialToAndroidXR(mat, varPrefix) {
975
- const lines = [];
976
- lines.push(`// Material: ${mat.name}`);
977
- if (mat.type === "unlit") {
978
- lines.push(`val ${varPrefix}MatBuilder = MaterialInstance.Builder()`);
979
- lines.push(
980
- ` .setParameter("baseColor", ${mat.baseColor ? hexToFilamentColor(mat.baseColor) : "Float4(1f, 1f, 1f, 1f)"})`
981
- );
982
- if (mat.opacity !== void 0) lines.push(` .setParameter("alpha", ${mat.opacity}f)`);
983
- lines.push(`val ${varPrefix}Mat = ${varPrefix}MatBuilder.build(engine)`);
984
- } else {
985
- lines.push(`val ${varPrefix}MatBuilder = MaterialInstance.Builder()`);
986
- if (mat.baseColor) {
987
- lines.push(` .setParameter("baseColor", ${hexToFilamentColor(mat.baseColor)})`);
988
- }
989
- if (mat.roughness !== void 0)
990
- lines.push(` .setParameter("roughness", ${mat.roughness}f)`);
991
- if (mat.metallic !== void 0) lines.push(` .setParameter("metallic", ${mat.metallic}f)`);
992
- if (mat.opacity !== void 0 && mat.opacity < 1) {
993
- lines.push(` .setParameter("alpha", ${mat.opacity}f)`);
994
- }
995
- if (mat.emissiveColor) {
996
- const [er, eg, eb] = hexToRGBTuple(mat.emissiveColor);
997
- const intensity = mat.emissiveIntensity ?? 1;
998
- lines.push(
999
- ` .setParameter("emissive", Float4(${er * intensity}f, ${eg * intensity}f, ${eb * intensity}f, 1f))`
1000
- );
1001
- }
1002
- lines.push(`val ${varPrefix}Mat = ${varPrefix}MatBuilder.build(engine)`);
1003
- }
1004
- for (const [mapType, path] of Object.entries(mat.textureMaps)) {
1005
- const paramName = mapType === "albedo_map" ? "baseColorMap" : mapType === "normal_map" ? "normalMap" : mapType === "metallic_map" ? "metallicMap" : mapType === "roughness_map" ? "roughnessMap" : mapType === "emission_map" ? "emissiveMap" : mapType === "occlusion_map" ? "aoMap" : mapType.replace(/_map$/, "Map");
1006
- lines.push(`// Texture: ${paramName} -> "${path}"`);
1007
- lines.push(
1008
- `val ${varPrefix}Tex_${paramName} = Texture.Builder().build(engine) // load from "${path}"`
1009
- );
1010
- lines.push(
1011
- `${varPrefix}Mat.setParameter("${paramName}", ${varPrefix}Tex_${paramName}, TextureSampler())`
1012
- );
1013
- }
1014
- return lines.join("\n");
1015
- }
1016
- function physicsToAndroidXR(physics, varPrefix) {
1017
- const lines = [];
1018
- lines.push(`// Physics: ${physics.keyword} "${physics.name || ""}"`);
1019
- if (physics.colliders) {
1020
- for (let i = 0; i < physics.colliders.length; i++) {
1021
- const c = physics.colliders[i];
1022
- const shape = c.shape || "box";
1023
- const colVar = `${varPrefix}Col${i}`;
1024
- if (shape === "sphere") {
1025
- lines.push(`val ${colVar} = SphereCollider(engine, ${c.properties.radius || 0.5}f)`);
1026
- } else if (shape === "capsule") {
1027
- lines.push(
1028
- `val ${colVar} = CapsuleCollider(engine, ${c.properties.radius || 0.25}f, ${c.properties.height || 1}f)`
1029
- );
1030
- } else {
1031
- const size = c.properties.size && Array.isArray(c.properties.size) ? c.properties.size : [1, 1, 1];
1032
- lines.push(
1033
- `val ${colVar} = BoxCollider(engine, Float3(${size[0]}f, ${size[1]}f, ${size[2]}f))`
1034
- );
1035
- }
1036
- if (c.type === "trigger") lines.push(`${colVar}.isTrigger = true`);
1037
- lines.push(`${varPrefix}Entity.addComponent(${colVar})`);
1038
- }
1039
- }
1040
- if (physics.rigidbody) {
1041
- const rb = physics.rigidbody.properties;
1042
- lines.push(`val ${varPrefix}RB = RigidBodyComponent()`);
1043
- if (rb.mass !== void 0) lines.push(`${varPrefix}RB.mass = ${rb.mass}f`);
1044
- if (rb.drag !== void 0) lines.push(`${varPrefix}RB.linearDamping = ${rb.drag}f`);
1045
- if (rb.angular_damping !== void 0)
1046
- lines.push(`${varPrefix}RB.angularDamping = ${rb.angular_damping}f`);
1047
- if (rb.use_gravity === false) lines.push(`${varPrefix}RB.isGravityEnabled = false`);
1048
- lines.push(`${varPrefix}Entity.addComponent(${varPrefix}RB)`);
1049
- }
1050
- if (physics.forceFields) {
1051
- for (const ff of physics.forceFields) {
1052
- if (ff.keyword === "wind_zone") {
1053
- lines.push(`// Wind zone: "${ff.name || ""}" strength=${ff.properties.strength || 0}`);
1054
- lines.push(`// Implement via custom force application in physics update loop`);
1055
- } else {
1056
- lines.push(
1057
- `// Force field: ${ff.keyword} "${ff.name || ""}" \u2014 ${JSON.stringify(ff.properties)}`
1058
- );
1059
- }
1060
- }
1061
- }
1062
- if (physics.joints) {
1063
- for (const j of physics.joints) {
1064
- lines.push(`// Joint: ${j.keyword} "${j.name || ""}" \u2014 configure via PhysicsConstraint`);
1065
- if (j.properties.axis) {
1066
- const axis = Array.isArray(j.properties.axis) ? j.properties.axis : [0, 0, 1];
1067
- lines.push(`// Axis: Float3(${axis[0]}f, ${axis[1]}f, ${axis[2]}f)`);
1068
- }
1069
- }
1070
- }
1071
- return lines.join("\n");
1072
- }
1073
- function particlesToAndroidXR(ps, varPrefix) {
1074
- const lines = [];
1075
- lines.push(`// Particles: ${ps.name}`);
1076
- lines.push(`val ${varPrefix}ParticleEntity = xrSession.scene.createEntity("${ps.name}")`);
1077
- lines.push(`// Configure particle system via Filament ParticleSystem or custom emitter`);
1078
- if (ps.properties.rate) lines.push(`val ${varPrefix}EmitRate = ${ps.properties.rate}f`);
1079
- if (ps.properties.max_particles)
1080
- lines.push(`val ${varPrefix}MaxParticles = ${ps.properties.max_particles}`);
1081
- if (ps.properties.start_lifetime) {
1082
- const lt = Array.isArray(ps.properties.start_lifetime) ? ps.properties.start_lifetime[0] : ps.properties.start_lifetime;
1083
- lines.push(`val ${varPrefix}Lifetime = ${lt}f`);
1084
- }
1085
- if (ps.properties.start_speed) {
1086
- const sp = Array.isArray(ps.properties.start_speed) ? ps.properties.start_speed[0] : ps.properties.start_speed;
1087
- lines.push(`val ${varPrefix}Speed = ${sp}f`);
1088
- }
1089
- if (ps.properties.gravity_modifier !== void 0) {
1090
- lines.push(`val ${varPrefix}GravityMod = ${ps.properties.gravity_modifier}f`);
1091
- }
1092
- if (ps.traits.includes("looping")) lines.push(`val ${varPrefix}Looping = true`);
1093
- if (ps.traits.includes("gpu")) lines.push(`// GPU particles: use compute shader pipeline`);
1094
- for (const m of ps.modules) {
1095
- lines.push(`// Module: ${m.type} \u2014 ${JSON.stringify(m.properties)}`);
1096
- }
1097
- return lines.join("\n");
1098
- }
1099
- function audioSourceToAndroidXR(audio, varPrefix) {
1100
- const lines = [];
1101
- lines.push(`// Audio: ${audio.name} (${audio.keyword})`);
1102
- const isSpatial = audio.traits.includes("spatial") || audio.traits.includes("hrtf") || typeof audio.properties.spatial_blend === "number" && audio.properties.spatial_blend > 0;
1103
- if (audio.keyword === "reverb_zone") {
1104
- lines.push(`// Reverb zone: "${audio.name}" \u2014 implement via AudioEffect.EFFECT_TYPE_REVERB`);
1105
- if (audio.properties.min_distance)
1106
- lines.push(`// minDistance = ${audio.properties.min_distance}`);
1107
- if (audio.properties.max_distance)
1108
- lines.push(`// maxDistance = ${audio.properties.max_distance}`);
1109
- return lines.join("\n");
1110
- }
1111
- lines.push(`val ${varPrefix}AudioEntity = xrSession.scene.createEntity("${audio.name}")`);
1112
- if (isSpatial) {
1113
- lines.push(
1114
- `val ${varPrefix}SpatialTrack = SpatialAudioTrack(xrSession, ${varPrefix}AudioEntity)`
1115
- );
1116
- if (audio.properties.max_distance) {
1117
- lines.push(`// Spatial falloff distance: ${audio.properties.max_distance}`);
1118
- }
1119
- }
1120
- if (audio.properties.clip) {
1121
- lines.push(
1122
- `val ${varPrefix}SoundId = soundPool.load(context, R.raw.${audio.properties.clip.toString().replace(/[^a-zA-Z0-9_]/g, "_")}, 1)`
1123
- );
1124
- }
1125
- if (audio.properties.volume !== void 0)
1126
- lines.push(`val ${varPrefix}Volume = ${audio.properties.volume}f`);
1127
- if (audio.properties.loop !== void 0)
1128
- lines.push(
1129
- `val ${varPrefix}Loop = ${audio.properties.loop ? "1" : "0"} // -1 = loop, 0 = once`
1130
- );
1131
- if (audio.properties.play_on_awake || audio.properties.clip) {
1132
- lines.push(`soundPool.setOnLoadCompleteListener { pool, id, _ ->`);
1133
- lines.push(
1134
- ` if (id == ${varPrefix}SoundId) pool.play(id, ${audio.properties.volume ?? 1}f, ${audio.properties.volume ?? 1}f, 1, ${audio.properties.loop ? "-1" : "0"}, 1.0f)`
1135
- );
1136
- lines.push(`}`);
1137
- }
1138
- return lines.join("\n");
1139
- }
1140
- function weatherToAndroidXR(weather) {
1141
- const lines = [];
1142
- lines.push(`// Weather: ${weather.keyword} "${weather.name || ""}"`);
1143
- lines.push("// Implement weather via Filament IndirectLight + custom particle emitters");
1144
- for (const [key, value] of Object.entries(weather.properties)) {
1145
- lines.push(`// ${key} = ${JSON.stringify(value)}`);
1146
- }
1147
- for (const layer of weather.layers) {
1148
- lines.push(`// Layer: ${layer.type}`);
1149
- if (layer.type === "rain" || layer.type === "snow") {
1150
- lines.push(
1151
- `// Use GPU particle emitter for ${layer.type} \u2014 rate=${layer.properties.rate || "default"}, intensity=${layer.properties.intensity || "default"}`
1152
- );
1153
- } else if (layer.type === "wind") {
1154
- lines.push(
1155
- `// Apply force to particle systems: strength=${layer.properties.strength || "default"}, direction=${JSON.stringify(layer.properties.direction) || "default"}`
1156
- );
1157
- } else if (layer.type === "fog" || layer.type === "fog_layer") {
1158
- lines.push(
1159
- `// Configure Filament fog: density=${layer.properties.density || "default"}, color=${layer.properties.color || "default"}`
1160
- );
1161
- } else if (layer.type === "lightning") {
1162
- lines.push(`// Lightning flash: frequency=${layer.properties.frequency || "default"}`);
1163
- } else if (layer.type === "clouds") {
1164
- lines.push(`// Volumetric clouds: coverage=${layer.properties.coverage || "default"}`);
1165
- } else {
1166
- for (const [k, v] of Object.entries(layer.properties)) {
1167
- lines.push(`// ${k} = ${JSON.stringify(v)}`);
1168
- }
1169
- }
1170
- }
1171
- return lines.join("\n");
1172
- }
1173
- function hexToFilamentColor(hex) {
1174
- const [r, g, b] = hexToRGBTuple(hex);
1175
- return `Float4(${r}f, ${g}f, ${b}f, 1f)`;
1176
- }
1177
- function materialToBabylon(mat, varPrefix) {
1178
- const lines = [];
1179
- lines.push(`// Material: ${mat.name}`);
1180
- if (mat.type === "unlit") {
1181
- lines.push(`const ${varPrefix}Mat = new BABYLON.StandardMaterial("${mat.name}", scene);`);
1182
- lines.push(`${varPrefix}Mat.disableLighting = true;`);
1183
- if (mat.emissiveColor)
1184
- lines.push(
1185
- `${varPrefix}Mat.emissiveColor = BABYLON.Color3.FromHexString("${mat.emissiveColor}");`
1186
- );
1187
- } else {
1188
- lines.push(`const ${varPrefix}Mat = new BABYLON.PBRMaterial("${mat.name}", scene);`);
1189
- if (mat.baseColor)
1190
- lines.push(`${varPrefix}Mat.albedoColor = BABYLON.Color3.FromHexString("${mat.baseColor}");`);
1191
- if (mat.roughness !== void 0) lines.push(`${varPrefix}Mat.roughness = ${mat.roughness};`);
1192
- if (mat.metallic !== void 0) lines.push(`${varPrefix}Mat.metallic = ${mat.metallic};`);
1193
- if (mat.opacity !== void 0 && mat.opacity < 1) {
1194
- lines.push(`${varPrefix}Mat.alpha = ${mat.opacity};`);
1195
- }
1196
- if (mat.emissiveColor) {
1197
- lines.push(
1198
- `${varPrefix}Mat.emissiveColor = BABYLON.Color3.FromHexString("${mat.emissiveColor}");`
1199
- );
1200
- if (mat.emissiveIntensity)
1201
- lines.push(`${varPrefix}Mat.emissiveIntensity = ${mat.emissiveIntensity};`);
1202
- }
1203
- if (mat.ior !== void 0) lines.push(`${varPrefix}Mat.indexOfRefraction = ${mat.ior};`);
1204
- }
1205
- for (const [mapType, path] of Object.entries(mat.textureMaps)) {
1206
- const prop = mapType === "albedo_map" ? "albedoTexture" : mapType === "normal_map" ? "bumpTexture" : mapType === "metallic_map" ? "metallicTexture" : mapType === "roughness_map" ? "microSurfaceTexture" : mapType === "emission_map" ? "emissiveTexture" : mapType === "occlusion_map" ? "ambientTexture" : `${mapType.replace(/_map$/, "Texture")}`;
1207
- lines.push(`${varPrefix}Mat.${prop} = new BABYLON.Texture("${path}", scene);`);
1208
- }
1209
- return lines.join("\n");
1210
- }
1211
- function physicsToBabylon(physics, varPrefix) {
1212
- const lines = [];
1213
- lines.push(`// Physics: ${physics.keyword} "${physics.name || ""}"`);
1214
- if (physics.rigidbody) {
1215
- const rb = physics.rigidbody.properties;
1216
- lines.push(
1217
- `const ${varPrefix}Aggregate = new BABYLON.PhysicsAggregate(${varPrefix}Mesh, BABYLON.PhysicsShapeType.BOX, {`
1218
- );
1219
- if (rb.mass !== void 0) lines.push(` mass: ${rb.mass},`);
1220
- if (rb.drag !== void 0) lines.push(` linearDamping: ${rb.drag},`);
1221
- if (rb.angular_damping !== void 0) lines.push(` angularDamping: ${rb.angular_damping},`);
1222
- lines.push("}, scene);");
1223
- }
1224
- if (physics.colliders) {
1225
- for (const c of physics.colliders) {
1226
- const shape = c.shape || "box";
1227
- const shapeType = shape === "sphere" ? "SPHERE" : shape === "capsule" ? "CAPSULE" : "BOX";
1228
- lines.push(`// Collider: ${shape} \u2014 PhysicsShapeType.${shapeType}`);
1229
- }
1230
- }
1231
- if (physics.joints) {
1232
- for (const j of physics.joints) {
1233
- const jointType = j.keyword === "hinge" ? "HingeConstraint" : j.keyword === "slider" ? "SliderConstraint" : j.keyword === "ball_socket" ? "BallAndSocketConstraint" : "Physics6DoFConstraint";
1234
- lines.push(`// Joint: ${j.keyword} \u2014 BABYLON.${jointType}`);
1235
- }
1236
- }
1237
- return lines.join("\n");
1238
- }
1239
- function particlesToBabylon(ps, varPrefix) {
1240
- const lines = [];
1241
- lines.push(`// Particles: ${ps.name}`);
1242
- const useGPU = ps.traits.includes("gpu");
1243
- if (useGPU) {
1244
- lines.push(
1245
- `const ${varPrefix}PS = new BABYLON.GPUParticleSystem("${ps.name}", { capacity: ${ps.properties.max_particles || 1e3} }, scene);`
1246
- );
1247
- } else {
1248
- lines.push(
1249
- `const ${varPrefix}PS = new BABYLON.ParticleSystem("${ps.name}", ${ps.properties.max_particles || 1e3}, scene);`
1250
- );
1251
- }
1252
- if (ps.properties.rate) lines.push(`${varPrefix}PS.emitRate = ${ps.properties.rate};`);
1253
- if (ps.properties.start_lifetime) {
1254
- const lt = ps.properties.start_lifetime;
1255
- if (Array.isArray(lt)) {
1256
- lines.push(`${varPrefix}PS.minLifeTime = ${lt[0]};`);
1257
- lines.push(`${varPrefix}PS.maxLifeTime = ${lt[1] || lt[0]};`);
1258
- } else {
1259
- lines.push(`${varPrefix}PS.minLifeTime = ${lt};`);
1260
- lines.push(`${varPrefix}PS.maxLifeTime = ${lt};`);
1261
- }
1262
- }
1263
- if (ps.properties.start_speed) {
1264
- const sp = ps.properties.start_speed;
1265
- if (Array.isArray(sp)) {
1266
- lines.push(`${varPrefix}PS.minEmitPower = ${sp[0]};`);
1267
- lines.push(`${varPrefix}PS.maxEmitPower = ${sp[1] || sp[0]};`);
1268
- } else {
1269
- lines.push(`${varPrefix}PS.minEmitPower = ${sp};`);
1270
- lines.push(`${varPrefix}PS.maxEmitPower = ${sp};`);
1271
- }
1272
- }
1273
- if (ps.properties.gravity_modifier !== void 0) {
1274
- const gravMod = typeof ps.properties.gravity_modifier === "number" ? ps.properties.gravity_modifier : 1;
1275
- lines.push(`${varPrefix}PS.gravity = new BABYLON.Vector3(0, ${ -9.81 * gravMod}, 0);`);
1276
- }
1277
- lines.push(`${varPrefix}PS.start();`);
1278
- return lines.join("\n");
1279
- }
1280
- function postProcessingToBabylon(pp) {
1281
- const lines = [];
1282
- lines.push(`// Post-Processing: ${pp.keyword}`);
1283
- lines.push(
1284
- 'const pipeline = new BABYLON.DefaultRenderingPipeline("default", true, scene, [camera]);'
1285
- );
1286
- for (const e of pp.effects) {
1287
- if (e.type === "bloom") {
1288
- lines.push("pipeline.bloomEnabled = true;");
1289
- if (e.properties.intensity) lines.push(`pipeline.bloomWeight = ${e.properties.intensity};`);
1290
- if (e.properties.threshold)
1291
- lines.push(`pipeline.bloomThreshold = ${e.properties.threshold};`);
1292
- } else if (e.type === "depth_of_field") {
1293
- lines.push("pipeline.depthOfFieldEnabled = true;");
1294
- if (e.properties.focal_length)
1295
- lines.push(`pipeline.depthOfField.focalLength = ${e.properties.focal_length};`);
1296
- } else if (e.type === "chromatic_aberration") {
1297
- lines.push("pipeline.chromaticAberrationEnabled = true;");
1298
- if (e.properties.amount)
1299
- lines.push(`pipeline.chromaticAberration.aberrationAmount = ${e.properties.amount};`);
1300
- } else if (e.type === "vignette") {
1301
- lines.push("pipeline.imageProcessing.vignetteEnabled = true;");
1302
- if (e.properties.weight)
1303
- lines.push(`pipeline.imageProcessing.vignetteWeight = ${e.properties.weight};`);
1304
- } else {
1305
- lines.push(`// Effect: ${e.type} \u2014 ${JSON.stringify(e.properties)}`);
1306
- }
1307
- }
1308
- return lines.join("\n");
1309
- }
1310
- function audioSourceToBabylon(audio, varPrefix) {
1311
- const lines = [];
1312
- lines.push(`// Audio: ${audio.name} (${audio.keyword})`);
1313
- const isSpatial = audio.traits.includes("spatial") || typeof audio.properties.spatial_blend === "number" && audio.properties.spatial_blend > 0;
1314
- lines.push(
1315
- `const ${varPrefix}Sound = new BABYLON.Sound("${audio.name}", "${audio.properties.clip || ""}", scene, null, {`
1316
- );
1317
- if (audio.properties.loop !== void 0) lines.push(` loop: ${audio.properties.loop},`);
1318
- if (audio.properties.volume !== void 0) lines.push(` volume: ${audio.properties.volume},`);
1319
- if (isSpatial) lines.push(" spatialSound: true,");
1320
- if (audio.properties.play_on_awake) lines.push(" autoplay: true,");
1321
- if (isSpatial && audio.properties.max_distance)
1322
- lines.push(` maxDistance: ${audio.properties.max_distance},`);
1323
- lines.push("});");
1324
- return lines.join("\n");
1325
- }
1326
- function materialToPlayCanvas(mat, varPrefix) {
1327
- const lines = [];
1328
- lines.push(`// Material: ${mat.name}`);
1329
- lines.push(`const ${varPrefix}Mat = new pc.StandardMaterial();`);
1330
- lines.push(`${varPrefix}Mat.name = "${mat.name}";`);
1331
- if (mat.baseColor)
1332
- lines.push(`${varPrefix}Mat.diffuse = new pc.Color().fromString("${mat.baseColor}");`);
1333
- if (mat.roughness !== void 0)
1334
- lines.push(`${varPrefix}Mat.gloss = ${1 - mat.roughness}; // roughness inverted`);
1335
- if (mat.metallic !== void 0) lines.push(`${varPrefix}Mat.metalness = ${mat.metallic};`);
1336
- if (mat.metallic !== void 0) lines.push(`${varPrefix}Mat.useMetalness = true;`);
1337
- if (mat.opacity !== void 0 && mat.opacity < 1) {
1338
- lines.push(`${varPrefix}Mat.opacity = ${mat.opacity};`);
1339
- lines.push(`${varPrefix}Mat.blendType = pc.BLEND_NORMAL;`);
1340
- }
1341
- if (mat.emissiveColor) {
1342
- lines.push(`${varPrefix}Mat.emissive = new pc.Color().fromString("${mat.emissiveColor}");`);
1343
- if (mat.emissiveIntensity)
1344
- lines.push(`${varPrefix}Mat.emissiveIntensity = ${mat.emissiveIntensity};`);
1345
- }
1346
- lines.push(`${varPrefix}Mat.update();`);
1347
- return lines.join("\n");
1348
- }
1349
- function physicsToPlayCanvas(physics, varPrefix) {
1350
- const lines = [];
1351
- lines.push(`// Physics: ${physics.keyword} "${physics.name || ""}"`);
1352
- if (physics.rigidbody) {
1353
- const rb = physics.rigidbody.properties;
1354
- lines.push(`${varPrefix}Entity.addComponent("rigidbody", {`);
1355
- lines.push(` type: "dynamic",`);
1356
- if (rb.mass !== void 0) lines.push(` mass: ${rb.mass},`);
1357
- if (rb.drag !== void 0) lines.push(` linearDamping: ${rb.drag},`);
1358
- if (rb.angular_damping !== void 0) lines.push(` angularDamping: ${rb.angular_damping},`);
1359
- lines.push("});");
1360
- }
1361
- if (physics.colliders) {
1362
- for (const c of physics.colliders) {
1363
- const shape = c.shape || "box";
1364
- lines.push(`${varPrefix}Entity.addComponent("collision", {`);
1365
- lines.push(` type: "${shape}",`);
1366
- if (c.properties.radius) lines.push(` radius: ${c.properties.radius},`);
1367
- if (c.properties.height) lines.push(` height: ${c.properties.height},`);
1368
- if (c.properties.size && Array.isArray(c.properties.size)) {
1369
- lines.push(
1370
- ` halfExtents: new pc.Vec3(${c.properties.size.map((s) => s / 2).join(", ")}),`
1371
- );
1372
- }
1373
- lines.push("});");
1374
- }
1375
- }
1376
- return lines.join("\n");
1377
- }
1378
- function particlesToPlayCanvas(ps, varPrefix) {
1379
- const lines = [];
1380
- lines.push(`// Particles: ${ps.name}`);
1381
- lines.push(`${varPrefix}Entity.addComponent("particlesystem", {`);
1382
- if (ps.properties.max_particles) lines.push(` numParticles: ${ps.properties.max_particles},`);
1383
- if (ps.properties.rate) lines.push(` rate: ${ps.properties.rate},`);
1384
- if (ps.properties.start_lifetime)
1385
- lines.push(
1386
- ` lifetime: ${Array.isArray(ps.properties.start_lifetime) ? ps.properties.start_lifetime[0] : ps.properties.start_lifetime},`
1387
- );
1388
- if (ps.properties.start_speed)
1389
- lines.push(
1390
- ` emitterExtents: new pc.Vec3(${Array.isArray(ps.properties.start_speed) ? ps.properties.start_speed[0] : ps.properties.start_speed}, 0, 0),`
1391
- );
1392
- lines.push(` loop: ${ps.traits.includes("looping")},`);
1393
- lines.push("});");
1394
- return lines.join("\n");
1395
- }
1396
- function audioSourceToPlayCanvas(audio, varPrefix) {
1397
- const lines = [];
1398
- lines.push(`// Audio: ${audio.name} (${audio.keyword})`);
1399
- lines.push(`${varPrefix}Entity.addComponent("sound", {`);
1400
- lines.push(
1401
- ` positional: ${audio.traits.includes("spatial") || typeof audio.properties.spatial_blend === "number" && audio.properties.spatial_blend > 0},`
1402
- );
1403
- if (audio.properties.volume !== void 0) lines.push(` volume: ${audio.properties.volume},`);
1404
- if (audio.properties.max_distance) lines.push(` maxDistance: ${audio.properties.max_distance},`);
1405
- lines.push("});");
1406
- if (audio.properties.clip) {
1407
- lines.push(
1408
- `${varPrefix}Entity.sound.addSlot("${audio.name}", { asset: app.assets.find("${audio.properties.clip}"),`
1409
- );
1410
- if (audio.properties.loop !== void 0) lines.push(` loop: ${audio.properties.loop},`);
1411
- if (audio.properties.play_on_awake) lines.push(" autoPlay: true,");
1412
- lines.push("});");
1413
- }
1414
- return lines.join("\n");
1415
- }
1416
- function materialToSDF(mat) {
1417
- const lines = [];
1418
- lines.push(`<material>`);
1419
- lines.push(` <script><name>${mat.name}</name></script>`);
1420
- if (mat.baseColor) {
1421
- const [r, g, b] = hexToRGBTuple(mat.baseColor);
1422
- lines.push(` <ambient>${r} ${g} ${b} 1</ambient>`);
1423
- lines.push(` <diffuse>${r} ${g} ${b} ${mat.opacity ?? 1}</diffuse>`);
1424
- }
1425
- if (mat.metallic !== void 0 && mat.metallic > 0.5) {
1426
- lines.push(` <specular>0.8 0.8 0.8 1</specular>`);
1427
- }
1428
- if (mat.emissiveColor) {
1429
- const [r, g, b] = hexToRGBTuple(mat.emissiveColor);
1430
- lines.push(` <emissive>${r} ${g} ${b} 1</emissive>`);
1431
- }
1432
- lines.push(`</material>`);
1433
- return lines.join("\n");
1434
- }
1435
- function physicsToSDF(physics) {
1436
- const lines = [];
1437
- if (physics.rigidbody) {
1438
- const rb = physics.rigidbody.properties;
1439
- lines.push("<inertial>");
1440
- lines.push(` <mass>${rb.mass ?? 1}</mass>`);
1441
- lines.push("</inertial>");
1442
- }
1443
- if (physics.colliders) {
1444
- for (const c of physics.colliders) {
1445
- const shape = c.shape || "box";
1446
- lines.push('<collision name="collision">');
1447
- lines.push(" <geometry>");
1448
- if (shape === "sphere") {
1449
- lines.push(` <sphere><radius>${c.properties.radius || 0.5}</radius></sphere>`);
1450
- } else if (shape === "capsule" || shape === "cylinder") {
1451
- lines.push(
1452
- ` <cylinder><radius>${c.properties.radius || 0.5}</radius><length>${c.properties.height || 1}</length></cylinder>`
1453
- );
1454
- } else {
1455
- const size = c.properties.size && Array.isArray(c.properties.size) ? c.properties.size : [1, 1, 1];
1456
- lines.push(` <box><size>${size.join(" ")}</size></box>`);
1457
- }
1458
- lines.push(" </geometry>");
1459
- lines.push("</collision>");
1460
- }
1461
- }
1462
- if (physics.joints) {
1463
- for (const j of physics.joints) {
1464
- const sdfType = j.keyword === "hinge" ? "revolute" : j.keyword === "slider" ? "prismatic" : j.keyword === "ball_socket" ? "ball" : j.keyword === "fixed_joint" ? "fixed" : "revolute";
1465
- lines.push(`<joint name="${j.name || "joint"}" type="${sdfType}">`);
1466
- if (j.properties.axis) {
1467
- const axis = Array.isArray(j.properties.axis) ? j.properties.axis : [0, 0, 1];
1468
- lines.push(` <axis><xyz>${axis.join(" ")}</xyz></axis>`);
1469
- }
1470
- if (j.properties.limits) {
1471
- const limVals = Array.isArray(j.properties.limits) ? j.properties.limits : void 0;
1472
- if (limVals)
1473
- lines.push(
1474
- ` <axis><limit><lower>${limVals[0]}</lower><upper>${limVals[1]}</upper></limit></axis>`
1475
- );
1476
- }
1477
- lines.push("</joint>");
1478
- }
1479
- }
1480
- return lines.join("\n");
1481
- }
1482
- function materialToVRChat(mat, varPrefix) {
1483
- const lines = [];
1484
- lines.push(`// VRChat Material: ${mat.name}`);
1485
- lines.push(`var ${varPrefix}Mat = new Material(Shader.Find("VRChat/Mobile/Standard Lite"));`);
1486
- if (mat.baseColor)
1487
- lines.push(`${varPrefix}Mat.SetColor("_Color", ${hexToUnityColor(mat.baseColor)});`);
1488
- if (mat.roughness !== void 0)
1489
- lines.push(`${varPrefix}Mat.SetFloat("_Glossiness", ${(1 - mat.roughness).toFixed(3)}f);`);
1490
- if (mat.metallic !== void 0)
1491
- lines.push(`${varPrefix}Mat.SetFloat("_Metallic", ${mat.metallic}f);`);
1492
- if (mat.emissiveColor) {
1493
- lines.push(`${varPrefix}Mat.EnableKeyword("_EMISSION");`);
1494
- lines.push(
1495
- `${varPrefix}Mat.SetColor("_EmissionColor", ${hexToUnityColor(mat.emissiveColor)});`
1496
- );
1497
- }
1498
- return lines.join("\n");
1499
- }
1500
- function particlesToUSD(ps) {
1501
- const lines = [];
1502
- lines.push(`def Scope "Particles_${ps.name.replace(/[^a-zA-Z0-9_]/g, "_")}" {`);
1503
- lines.push(` custom string holoscript:type = "particle_system"`);
1504
- if (ps.properties.rate) lines.push(` custom float holoscript:rate = ${ps.properties.rate}`);
1505
- if (ps.properties.max_particles)
1506
- lines.push(` custom int holoscript:maxParticles = ${ps.properties.max_particles}`);
1507
- if (ps.properties.start_lifetime)
1508
- lines.push(
1509
- ` custom float holoscript:lifetime = ${Array.isArray(ps.properties.start_lifetime) ? ps.properties.start_lifetime[0] : ps.properties.start_lifetime}`
1510
- );
1511
- for (const m of ps.modules) {
1512
- lines.push(` def Scope "${m.type}" {`);
1513
- for (const [k, v] of Object.entries(m.properties)) {
1514
- const usdType = typeof v === "number" ? "float" : typeof v === "boolean" ? "bool" : "string";
1515
- lines.push(` custom ${usdType} ${k} = ${JSON.stringify(v)}`);
1516
- }
1517
- lines.push(" }");
1518
- }
1519
- lines.push("}");
1520
- return lines.join("\n");
1521
- }
1522
- function postProcessingToUSD(pp) {
1523
- const lines = [];
1524
- lines.push(`def Scope "PostProcessing" {`);
1525
- for (const e of pp.effects) {
1526
- lines.push(` def Scope "${e.type}" {`);
1527
- for (const [k, v] of Object.entries(e.properties)) {
1528
- const usdType = typeof v === "number" ? "float" : typeof v === "boolean" ? "bool" : "string";
1529
- lines.push(` custom ${usdType} ${k} = ${JSON.stringify(v)}`);
1530
- }
1531
- lines.push(" }");
1532
- }
1533
- lines.push("}");
1534
- return lines.join("\n");
1535
- }
1536
- function audioSourceToUSD(audio) {
1537
- const lines = [];
1538
- lines.push(`def Scope "Audio_${audio.name.replace(/[^a-zA-Z0-9_]/g, "_")}" {`);
1539
- lines.push(` custom string holoscript:type = "${audio.keyword}"`);
1540
- if (audio.properties.clip) lines.push(` asset holoscript:clip = @${audio.properties.clip}@`);
1541
- if (audio.properties.volume !== void 0)
1542
- lines.push(` custom float holoscript:volume = ${audio.properties.volume}`);
1543
- if (audio.properties.loop !== void 0)
1544
- lines.push(` custom bool holoscript:loop = ${audio.properties.loop}`);
1545
- if (audio.properties.spatial_blend !== void 0)
1546
- lines.push(` custom float holoscript:spatialBlend = ${audio.properties.spatial_blend}`);
1547
- lines.push("}");
1548
- return lines.join("\n");
1549
- }
1550
- function physicsToR3F(physics) {
1551
- const lines = [];
1552
- if (physics.rigidbody) {
1553
- const rb = physics.rigidbody.properties;
1554
- const bodyType = rb.use_gravity === false ? "kinematicPosition" : "dynamic";
1555
- lines.push(
1556
- `<RigidBody type="${bodyType}"${rb.mass ? ` mass={${rb.mass}}` : ""}${rb.drag ? ` linearDamping={${rb.drag}}` : ""}${rb.angular_damping ? ` angularDamping={${rb.angular_damping}}` : ""}>`
1557
- );
1558
- }
1559
- if (physics.colliders) {
1560
- for (const c of physics.colliders) {
1561
- const shape = c.shape || "cuboid";
1562
- const r3fShape = shape === "box" ? "cuboid" : shape === "sphere" ? "ball" : shape;
1563
- const args = shape === "sphere" && c.properties.radius ? ` args={[${c.properties.radius}]}` : "";
1564
- lines.push(
1565
- ` <${c.type === "trigger" ? "CuboidCollider sensor" : `${capitalizeFirst(r3fShape)}Collider`}${args} />`
1566
- );
1567
- }
1568
- }
1569
- if (physics.rigidbody) {
1570
- lines.push("</RigidBody>");
1571
- }
1572
- if (physics.joints) {
1573
- for (const j of physics.joints) {
1574
- lines.push(
1575
- `{/* Joint: ${j.keyword} "${j.name || ""}" \u2014 use useRevoluteJoint/useSphericalJoint */}`
1576
- );
1577
- }
1578
- }
1579
- if (physics.forceFields) {
1580
- for (const ff of physics.forceFields) {
1581
- lines.push(
1582
- `{/* Force field: ${ff.keyword} "${ff.name || ""}" \u2014 ${JSON.stringify(ff.properties)} */}`
1583
- );
1584
- }
1585
- }
1586
- return lines.join("\n");
1587
- }
1588
- function weatherToR3F(weather) {
1589
- const lines = [];
1590
- lines.push(`{/* Weather: ${weather.keyword} "${weather.name || ""}" */}`);
1591
- for (const layer of weather.layers) {
1592
- const componentName = capitalizeFirst(layer.type);
1593
- const props = Object.entries(layer.properties).map(([k, v]) => {
1594
- const camel = k.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
1595
- return typeof v === "string" ? `${camel}="${v}"` : `${camel}={${JSON.stringify(v)}}`;
1596
- }).join(" ");
1597
- lines.push(`<${componentName} ${props} />`);
1598
- }
1599
- return lines.join("\n");
1600
- }
1601
- function materialToWebGPU(mat, varPrefix) {
1602
- const lines = [];
1603
- lines.push(`// Material: ${mat.name}`);
1604
- lines.push(`const ${varPrefix}MaterialData = new Float32Array([`);
1605
- if (mat.baseColor) {
1606
- const [r, g, b] = hexToRGBTuple(mat.baseColor);
1607
- lines.push(` ${r}, ${g}, ${b}, ${mat.opacity ?? 1}, // baseColor + opacity`);
1608
- } else {
1609
- lines.push(" 1.0, 1.0, 1.0, 1.0, // baseColor + opacity");
1610
- }
1611
- lines.push(
1612
- ` ${mat.roughness ?? 0.5}, ${mat.metallic ?? 0}, ${mat.ior ?? 1.5}, 0.0, // roughness, metallic, ior, pad`
1613
- );
1614
- if (mat.emissiveColor) {
1615
- const [r, g, b] = hexToRGBTuple(mat.emissiveColor);
1616
- lines.push(` ${r}, ${g}, ${b}, ${mat.emissiveIntensity ?? 1}, // emissive + intensity`);
1617
- } else {
1618
- lines.push(" 0.0, 0.0, 0.0, 0.0, // emissive + intensity");
1619
- }
1620
- lines.push("]);");
1621
- lines.push(`const ${varPrefix}MaterialBuffer = device.createBuffer({`);
1622
- lines.push(` size: ${varPrefix}MaterialData.byteLength,`);
1623
- lines.push(" usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,");
1624
- lines.push("});");
1625
- lines.push(`device.queue.writeBuffer(${varPrefix}MaterialBuffer, 0, ${varPrefix}MaterialData);`);
1626
- return lines.join("\n");
1627
- }
1628
- function hexToRGBTuple(hex) {
1629
- const h = hex.replace("#", "");
1630
- return [
1631
- parseFloat((parseInt(h.substring(0, 2), 16) / 255).toFixed(3)),
1632
- parseFloat((parseInt(h.substring(2, 4), 16) / 255).toFixed(3)),
1633
- parseFloat((parseInt(h.substring(4, 6), 16) / 255).toFixed(3))
1634
- ];
1635
- }
1636
- function hexToUnityColor(hex) {
1637
- const [r, g, b] = hexToRGBTuple(hex);
1638
- return `new Color(${r}f, ${g}f, ${b}f)`;
1639
- }
1640
- function hexToSwiftColor(hex) {
1641
- return `.init(red: 0x${hex.slice(1, 3)}, green: 0x${hex.slice(3, 5)}, blue: 0x${hex.slice(5, 7)})`;
1642
- }
1643
- function capitalizeFirst(s) {
1644
- return s.charAt(0).toUpperCase() + s.slice(1);
1645
- }
1646
- function compileNarrativeBlock(block) {
1647
- const chapters = [];
1648
- let hasChoices = false;
1649
- for (const child of block.children || []) {
1650
- const c = child;
1651
- if (c.type !== "DomainBlock") continue;
1652
- const kw = c.keyword;
1653
- if (kw === "chapter" || kw === "act" || kw === "scene") {
1654
- const chapter = compileChapterBlock(c);
1655
- if (chapter.choices && chapter.choices.length > 0) hasChoices = true;
1656
- chapters.push(chapter);
1657
- } else if (kw === "dialogue_tree") {
1658
- const dialogueLines = [];
1659
- const choices = [];
1660
- for (const dc of c.children || []) {
1661
- const dck = dc.keyword;
1662
- if (dck === "line" || dck === "dialogue") {
1663
- dialogueLines.push(compileDialogueLine(dc));
1664
- } else if (dck === "choice") {
1665
- choices.push(compileChoiceNode(dc));
1666
- hasChoices = true;
1667
- }
1668
- }
1669
- chapters.push({
1670
- name: c.name || "dialogue",
1671
- dialogueLines: dialogueLines.length > 0 ? dialogueLines : void 0,
1672
- choices: choices.length > 0 ? choices : void 0
1673
- });
1674
- }
1675
- }
1676
- const props = block.properties || {};
1677
- const narrativeType = hasChoices ? "branching" : props.type === "open_world" ? "open_world" : "linear";
1678
- return {
1679
- name: block.name || "unnamed",
1680
- type: narrativeType,
1681
- chapters,
1682
- startChapter: props.start_chapter || props.startChapter,
1683
- variables: props.variables
1684
- };
1685
- }
1686
- function compileChapterBlock(block) {
1687
- const props = block.properties || {};
1688
- const dialogueLines = [];
1689
- const choices = [];
1690
- const cutsceneActions = [];
1691
- for (const child of block.children || []) {
1692
- const c = child;
1693
- const kw = c.keyword;
1694
- if (kw === "line" || kw === "dialogue") {
1695
- dialogueLines.push(compileDialogueLine(c));
1696
- } else if (kw === "choice") {
1697
- choices.push(compileChoiceNode(c));
1698
- } else if (kw === "cutscene" || kw === "camera" || kw === "action" || kw === "wait" || kw === "effect" || kw === "audio") {
1699
- cutsceneActions.push(compileCutsceneAction(c));
1700
- }
1701
- }
1702
- return {
1703
- name: block.name || "unnamed",
1704
- trigger: props.trigger || props.on_enter,
1705
- dialogueLines: dialogueLines.length > 0 ? dialogueLines : void 0,
1706
- choices: choices.length > 0 ? choices : void 0,
1707
- onComplete: props.on_complete || props.next,
1708
- cutsceneActions: cutsceneActions.length > 0 ? cutsceneActions : void 0
1709
- };
1710
- }
1711
- function compileDialogueLine(block) {
1712
- const props = block.properties || {};
1713
- return {
1714
- speaker: props.speaker || props.character,
1715
- text: props.text || props.content || block.name || "",
1716
- emotion: props.emotion,
1717
- duration: props.duration,
1718
- voiceClip: props.voice_clip || props.voiceClip || props.audio
1719
- };
1720
- }
1721
- function compileChoiceNode(block) {
1722
- const props = block.properties || {};
1723
- return {
1724
- text: props.text || block.name || "",
1725
- condition: props.condition,
1726
- nextChapter: props.next || props.next_chapter || props.goto,
1727
- action: props.action
1728
- };
1729
- }
1730
- function compileCutsceneAction(block) {
1731
- const props = block.properties || {};
1732
- const kw = block.keyword;
1733
- const type = kw === "camera" || kw === "camera_move" ? "camera_move" : kw === "action" || kw === "character_action" ? "character_action" : kw === "wait" ? "wait" : kw === "audio" ? "audio" : "effect";
1734
- return {
1735
- type,
1736
- target: props.target || block.name,
1737
- params: { ...props },
1738
- duration: props.duration
1739
- };
1740
- }
1741
- function narrativeToUnity(narrative) {
1742
- const lines = [];
1743
- const safeName = narrative.name.replace(/[^a-zA-Z0-9_]/g, "_");
1744
- lines.push(`// StoryWeaver Narrative: ${narrative.name}`);
1745
- lines.push(`[CreateAssetMenu(menuName = "StoryWeaver/${safeName}")]`);
1746
- lines.push(`public class ${safeName}Narrative : ScriptableObject {`);
1747
- lines.push(` public NarrativeType type = NarrativeType.${capitalizeFirst(narrative.type)};`);
1748
- if (narrative.startChapter) {
1749
- lines.push(` public string startChapter = "${narrative.startChapter}";`);
1750
- }
1751
- lines.push("");
1752
- for (const chapter of narrative.chapters) {
1753
- lines.push(` [Header("${chapter.name}")]`);
1754
- lines.push(` public Chapter ${chapter.name.replace(/[^a-zA-Z0-9_]/g, "_")} = new Chapter {`);
1755
- if (chapter.trigger) lines.push(` trigger = "${chapter.trigger}",`);
1756
- if (chapter.onComplete) lines.push(` onComplete = "${chapter.onComplete}",`);
1757
- if (chapter.dialogueLines && chapter.dialogueLines.length > 0) {
1758
- lines.push(" dialogueLines = new DialogueLine[] {");
1759
- for (const dl of chapter.dialogueLines) {
1760
- const parts = [`text = "${dl.text}"`];
1761
- if (dl.speaker) parts.push(`speaker = "${dl.speaker}"`);
1762
- if (dl.emotion) parts.push(`emotion = "${dl.emotion}"`);
1763
- if (dl.duration) parts.push(`duration = ${dl.duration}f`);
1764
- if (dl.voiceClip) parts.push(`voiceClip = "${dl.voiceClip}"`);
1765
- lines.push(` new DialogueLine { ${parts.join(", ")} },`);
1766
- }
1767
- lines.push(" },");
1768
- }
1769
- if (chapter.choices && chapter.choices.length > 0) {
1770
- lines.push(" choices = new Choice[] {");
1771
- for (const ch of chapter.choices) {
1772
- const parts = [`text = "${ch.text}"`];
1773
- if (ch.nextChapter) parts.push(`nextChapter = "${ch.nextChapter}"`);
1774
- if (ch.condition) parts.push(`condition = "${ch.condition}"`);
1775
- if (ch.action) parts.push(`action = "${ch.action}"`);
1776
- lines.push(` new Choice { ${parts.join(", ")} },`);
1777
- }
1778
- lines.push(" },");
1779
- }
1780
- lines.push(" };");
1781
- }
1782
- lines.push("}");
1783
- return lines.join("\n");
1784
- }
1785
- function narrativeToGodot(narrative) {
1786
- const lines = [];
1787
- const safeName = narrative.name.replace(/[^a-zA-Z0-9_]/g, "_");
1788
- lines.push(`# StoryWeaver Narrative: ${narrative.name}`);
1789
- lines.push("extends Node");
1790
- lines.push(`class_name ${safeName}Narrative`);
1791
- lines.push("");
1792
- lines.push("signal chapter_started(chapter_name: String)");
1793
- lines.push("signal chapter_complete(chapter_name: String)");
1794
- lines.push("signal dialogue_line(speaker: String, text: String, emotion: String)");
1795
- lines.push("signal choice_presented(choices: Array)");
1796
- lines.push("");
1797
- lines.push(`var narrative_type: String = "${narrative.type}"`);
1798
- lines.push(
1799
- `var current_chapter: String = "${narrative.startChapter || narrative.chapters[0]?.name || ""}"`
1800
- );
1801
- lines.push("");
1802
- lines.push("var chapters: Dictionary = {");
1803
- for (const chapter of narrative.chapters) {
1804
- const chKey = chapter.name.replace(/[^a-zA-Z0-9_]/g, "_");
1805
- lines.push(` "${chKey}": {`);
1806
- if (chapter.trigger) lines.push(` "trigger": "${chapter.trigger}",`);
1807
- if (chapter.onComplete) lines.push(` "on_complete": "${chapter.onComplete}",`);
1808
- if (chapter.dialogueLines && chapter.dialogueLines.length > 0) {
1809
- lines.push(' "dialogue": [');
1810
- for (const dl of chapter.dialogueLines) {
1811
- lines.push(
1812
- ` {"speaker": "${dl.speaker || ""}", "text": "${dl.text}", "emotion": "${dl.emotion || "neutral"}"},`
1813
- );
1814
- }
1815
- lines.push(" ],");
1816
- }
1817
- if (chapter.choices && chapter.choices.length > 0) {
1818
- lines.push(' "choices": [');
1819
- for (const ch of chapter.choices) {
1820
- lines.push(` {"text": "${ch.text}", "next": "${ch.nextChapter || ""}"},`);
1821
- }
1822
- lines.push(" ],");
1823
- }
1824
- lines.push(" },");
1825
- }
1826
- lines.push("}");
1827
- lines.push("");
1828
- lines.push("func advance_chapter(chapter_name: String) -> void:");
1829
- lines.push(" current_chapter = chapter_name");
1830
- lines.push(" chapter_started.emit(chapter_name)");
1831
- lines.push(" if chapters.has(chapter_name):");
1832
- lines.push(" var ch = chapters[chapter_name]");
1833
- lines.push(' if ch.has("dialogue"):');
1834
- lines.push(' for line in ch["dialogue"]:');
1835
- lines.push(' dialogue_line.emit(line["speaker"], line["text"], line["emotion"])');
1836
- lines.push(' if ch.has("choices"):');
1837
- lines.push(' choice_presented.emit(ch["choices"])');
1838
- lines.push(' elif ch.has("on_complete"):');
1839
- lines.push(" chapter_complete.emit(chapter_name)");
1840
- lines.push(' advance_chapter(ch["on_complete"])');
1841
- return lines.join("\n");
1842
- }
1843
- function narrativeToVRChat(narrative) {
1844
- const lines = [];
1845
- const safeName = narrative.name.replace(/[^a-zA-Z0-9_]/g, "_");
1846
- lines.push(`// StoryWeaver Narrative: ${narrative.name} (VRChat UdonSharp)`);
1847
- lines.push("[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]");
1848
- lines.push(`public class ${safeName}Narrative : UdonSharpBehaviour {`);
1849
- lines.push(" [UdonSynced] public int currentChapter = 0;");
1850
- lines.push(
1851
- ` private string[] chapterNames = new string[] { ${narrative.chapters.map((c) => `"${esc(c.name, "CSharp")}"`).join(", ")} };`
1852
- );
1853
- lines.push("");
1854
- for (let i = 0; i < narrative.chapters.length; i++) {
1855
- const chapter = narrative.chapters[i];
1856
- if (chapter.trigger) {
1857
- lines.push(` // Trigger for chapter "${chapter.name}": ${chapter.trigger}`);
1858
- }
1859
- }
1860
- lines.push("");
1861
- lines.push(" public void AdvanceChapter() {");
1862
- lines.push(" if (!Networking.IsOwner(gameObject)) {");
1863
- lines.push(" Networking.SetOwner(Networking.LocalPlayer, gameObject);");
1864
- lines.push(" }");
1865
- lines.push(" currentChapter++;");
1866
- lines.push(
1867
- " if (currentChapter >= chapterNames.Length) currentChapter = chapterNames.Length - 1;"
1868
- );
1869
- lines.push(" RequestSerialization();");
1870
- lines.push(" }");
1871
- lines.push("");
1872
- lines.push(" public override void OnDeserialization() {");
1873
- lines.push(" // Sync chapter state across all players");
1874
- lines.push(" UpdateNarrativeUI();");
1875
- lines.push(" }");
1876
- lines.push("");
1877
- lines.push(" private void UpdateNarrativeUI() {");
1878
- for (let i = 0; i < narrative.chapters.length; i++) {
1879
- const chapter = narrative.chapters[i];
1880
- if (chapter.dialogueLines && chapter.dialogueLines.length > 0) {
1881
- const dl = chapter.dialogueLines[0];
1882
- lines.push(` if (currentChapter == ${i}) {`);
1883
- lines.push(` // ${dl.speaker || "Narrator"}: "${dl.text}"`);
1884
- lines.push(" }");
1885
- }
1886
- }
1887
- lines.push(" }");
1888
- lines.push("}");
1889
- return lines.join("\n");
1890
- }
1891
- function narrativeToR3F(narrative) {
1892
- const lines = [];
1893
- const safeName = narrative.name.replace(/[^a-zA-Z0-9_]/g, "_");
1894
- lines.push(`// StoryWeaver Narrative: ${narrative.name} (R3F/React)`);
1895
- lines.push(`export const ${safeName}NarrativeData = {`);
1896
- lines.push(` name: "${narrative.name}",`);
1897
- lines.push(` type: "${narrative.type}",`);
1898
- if (narrative.startChapter) lines.push(` startChapter: "${narrative.startChapter}",`);
1899
- lines.push(" chapters: [");
1900
- for (const chapter of narrative.chapters) {
1901
- lines.push(" {");
1902
- lines.push(` name: "${chapter.name}",`);
1903
- if (chapter.trigger) lines.push(` trigger: "${chapter.trigger}",`);
1904
- if (chapter.onComplete) lines.push(` onComplete: "${chapter.onComplete}",`);
1905
- if (chapter.dialogueLines && chapter.dialogueLines.length > 0) {
1906
- lines.push(" dialogueLines: [");
1907
- for (const dl of chapter.dialogueLines) {
1908
- const parts = [`text: "${dl.text}"`];
1909
- if (dl.speaker) parts.push(`speaker: "${dl.speaker}"`);
1910
- if (dl.emotion) parts.push(`emotion: "${dl.emotion}"`);
1911
- if (dl.duration) parts.push(`duration: ${dl.duration}`);
1912
- lines.push(` { ${parts.join(", ")} },`);
1913
- }
1914
- lines.push(" ],");
1915
- }
1916
- if (chapter.choices && chapter.choices.length > 0) {
1917
- lines.push(" choices: [");
1918
- for (const ch of chapter.choices) {
1919
- const parts = [`text: "${ch.text}"`];
1920
- if (ch.nextChapter) parts.push(`nextChapter: "${ch.nextChapter}"`);
1921
- if (ch.condition) parts.push(`condition: "${ch.condition}"`);
1922
- lines.push(` { ${parts.join(", ")} },`);
1923
- }
1924
- lines.push(" ],");
1925
- }
1926
- lines.push(" },");
1927
- }
1928
- lines.push(" ],");
1929
- lines.push("};");
1930
- return lines.join("\n");
1931
- }
1932
- function narrativeToUSDA(narrative) {
1933
- const lines = [];
1934
- const safeName = narrative.name.replace(/[^a-zA-Z0-9_]/g, "_");
1935
- lines.push(`def Scope "Narrative_${safeName}" {`);
1936
- lines.push(` custom string holoscript:narrativeType = "${narrative.type}"`);
1937
- if (narrative.startChapter) {
1938
- lines.push(` custom string holoscript:startChapter = "${narrative.startChapter}"`);
1939
- }
1940
- for (const chapter of narrative.chapters) {
1941
- const chName = chapter.name.replace(/[^a-zA-Z0-9_]/g, "_");
1942
- lines.push(` def Scope "Chapter_${chName}" {`);
1943
- lines.push(` custom string holoscript:chapterName = "${chapter.name}"`);
1944
- if (chapter.trigger)
1945
- lines.push(` custom string holoscript:trigger = "${chapter.trigger}"`);
1946
- if (chapter.onComplete)
1947
- lines.push(` custom string holoscript:onComplete = "${chapter.onComplete}"`);
1948
- if (chapter.dialogueLines) {
1949
- for (let i = 0; i < chapter.dialogueLines.length; i++) {
1950
- const dl = chapter.dialogueLines[i];
1951
- lines.push(` def Scope "Dialogue_${i}" {`);
1952
- lines.push(` custom string holoscript:text = "${dl.text}"`);
1953
- if (dl.speaker)
1954
- lines.push(` custom string holoscript:speaker = "${dl.speaker}"`);
1955
- if (dl.emotion)
1956
- lines.push(` custom string holoscript:emotion = "${dl.emotion}"`);
1957
- if (dl.duration)
1958
- lines.push(` custom float holoscript:duration = ${dl.duration}`);
1959
- lines.push(" }");
1960
- }
1961
- }
1962
- if (chapter.choices) {
1963
- for (let i = 0; i < chapter.choices.length; i++) {
1964
- const ch = chapter.choices[i];
1965
- lines.push(` def Scope "Choice_${i}" {`);
1966
- lines.push(` custom string holoscript:text = "${ch.text}"`);
1967
- if (ch.nextChapter)
1968
- lines.push(` custom string holoscript:nextChapter = "${ch.nextChapter}"`);
1969
- if (ch.condition)
1970
- lines.push(` custom string holoscript:condition = "${ch.condition}"`);
1971
- lines.push(" }");
1972
- }
1973
- }
1974
- if (chapter.cutsceneActions) {
1975
- for (let i = 0; i < chapter.cutsceneActions.length; i++) {
1976
- const ca = chapter.cutsceneActions[i];
1977
- lines.push(` def Scope "CutsceneAction_${i}" {`);
1978
- lines.push(` custom string holoscript:actionType = "${ca.type}"`);
1979
- if (ca.target) lines.push(` custom string holoscript:target = "${ca.target}"`);
1980
- if (ca.duration)
1981
- lines.push(` custom float holoscript:duration = ${ca.duration}`);
1982
- lines.push(" }");
1983
- }
1984
- }
1985
- lines.push(" }");
1986
- }
1987
- lines.push("}");
1988
- return lines.join("\n");
1989
- }
1990
- function compilePaymentBlock(block) {
1991
- const props = block.properties || {};
1992
- const paywallType = block.keyword === "subscription" ? "subscription" : block.keyword === "tip_jar" ? "tip" : block.keyword === "per_use" || props.per_use ? "per_use" : "one_time";
1993
- const gatedContent = [];
1994
- if (props.gated_content && Array.isArray(props.gated_content)) {
1995
- gatedContent.push(...props.gated_content);
1996
- } else if (typeof props.gated_content === "string") {
1997
- gatedContent.push(props.gated_content);
1998
- }
1999
- for (const child of block.children || []) {
2000
- const c = child;
2001
- if (c.name) gatedContent.push(c.name);
2002
- }
2003
- let revenueSplit;
2004
- if (props.revenue_split && typeof props.revenue_split === "object") {
2005
- const rs = props.revenue_split;
2006
- revenueSplit = {
2007
- creator: rs.creator ?? 80,
2008
- platform: rs.platform ?? 10,
2009
- agent: rs.agent ?? 10
2010
- };
2011
- }
2012
- return {
2013
- name: block.name || "unnamed",
2014
- price: props.price ?? 0,
2015
- asset: props.asset ?? "USDC",
2016
- network: props.network ?? "base",
2017
- recipient: props.recipient || props.wallet || "",
2018
- description: props.description || props.message,
2019
- type: paywallType,
2020
- gatedContent: gatedContent.length > 0 ? gatedContent : void 0,
2021
- revenueSplit
2022
- };
2023
- }
2024
- function paymentToUnity(paywall) {
2025
- const lines = [];
2026
- const safeName = paywall.name.replace(/[^a-zA-Z0-9_]/g, "_");
2027
- lines.push(`// x402 Paywall: ${paywall.name}`);
2028
- lines.push(`[CreateAssetMenu(menuName = "x402/${safeName}")]`);
2029
- lines.push(`public class ${safeName}Paywall : ScriptableObject {`);
2030
- lines.push(` public decimal price = ${paywall.price}m;`);
2031
- lines.push(` public string asset = "${paywall.asset}";`);
2032
- lines.push(` public string network = "${paywall.network}";`);
2033
- lines.push(` public string recipientWallet = "${paywall.recipient}";`);
2034
- lines.push(` public string paywallType = "${paywall.type}";`);
2035
- if (paywall.description) {
2036
- lines.push(` public string description = "${paywall.description}";`);
2037
- }
2038
- if (paywall.gatedContent && paywall.gatedContent.length > 0) {
2039
- lines.push(
2040
- ` public string[] gatedObjects = new string[] { ${paywall.gatedContent.map((g) => `"${esc(g, "CSharp")}"`).join(", ")} };`
2041
- );
2042
- }
2043
- if (paywall.revenueSplit) {
2044
- lines.push(
2045
- ` // Revenue split: ${paywall.revenueSplit.creator}% Creator, ${paywall.revenueSplit.platform}% Platform, ${paywall.revenueSplit.agent}% Agent`
2046
- );
2047
- }
2048
- lines.push("");
2049
- lines.push(" public bool IsUnlocked { get; private set; }");
2050
- lines.push("");
2051
- lines.push(" public async Task<bool> RequestPayment() {");
2052
- lines.push(" // HTTP 402 payment flow via x402 protocol");
2053
- lines.push(" var response = await Http.Get(paymentEndpoint);");
2054
- lines.push(" if (response.StatusCode == 402) {");
2055
- lines.push(" var challenge = JsonUtility.FromJson<PaymentChallenge>(response.Body);");
2056
- lines.push(" return await ProcessPayment(challenge);");
2057
- lines.push(" }");
2058
- lines.push(" return false;");
2059
- lines.push(" }");
2060
- lines.push("}");
2061
- return lines.join("\n");
2062
- }
2063
- function paymentToGodot(paywall) {
2064
- const lines = [];
2065
- const safeName = paywall.name.replace(/[^a-zA-Z0-9_]/g, "_");
2066
- lines.push(`# x402 Paywall: ${paywall.name}`);
2067
- lines.push("extends Node");
2068
- lines.push(`class_name ${safeName}Paywall`);
2069
- lines.push("");
2070
- lines.push("signal payment_required(price: float, asset: String)");
2071
- lines.push("signal payment_verified(tx_hash: String)");
2072
- lines.push("signal access_granted");
2073
- lines.push("");
2074
- lines.push(`var price: float = ${paywall.price}`);
2075
- lines.push(`var asset: String = "${paywall.asset}"`);
2076
- lines.push(`var network: String = "${paywall.network}"`);
2077
- lines.push(`var recipient: String = "${paywall.recipient}"`);
2078
- lines.push(`var paywall_type: String = "${paywall.type}"`);
2079
- lines.push("var is_unlocked: bool = false");
2080
- if (paywall.gatedContent && paywall.gatedContent.length > 0) {
2081
- lines.push(
2082
- `var gated_objects: Array = [${paywall.gatedContent.map((g) => `"${esc(g, "GDScript")}"`).join(", ")}]`
2083
- );
2084
- }
2085
- lines.push("");
2086
- lines.push("func request_payment() -> void:");
2087
- lines.push(" payment_required.emit(price, asset)");
2088
- lines.push("");
2089
- lines.push("func verify_payment(tx_hash: String) -> void:");
2090
- lines.push(" payment_verified.emit(tx_hash)");
2091
- lines.push(" is_unlocked = true");
2092
- lines.push(" access_granted.emit()");
2093
- if (paywall.gatedContent && paywall.gatedContent.length > 0) {
2094
- lines.push(" for obj_name in gated_objects:");
2095
- lines.push(" var node = get_node_or_null(obj_name)");
2096
- lines.push(" if node: node.visible = true");
2097
- }
2098
- return lines.join("\n");
2099
- }
2100
- function paymentToVRChat(paywall) {
2101
- const lines = [];
2102
- const safeName = paywall.name.replace(/[^a-zA-Z0-9_]/g, "_");
2103
- lines.push(`// x402 Paywall: ${paywall.name} (VRChat UdonSharp)`);
2104
- lines.push("[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]");
2105
- lines.push(`public class ${safeName}Paywall : UdonSharpBehaviour {`);
2106
- lines.push(" [UdonSynced] public bool isUnlocked = false;");
2107
- lines.push(` public float price = ${paywall.price}f;`);
2108
- lines.push(` public string asset = "${paywall.asset}";`);
2109
- lines.push(` public string network = "${paywall.network}";`);
2110
- lines.push(` public string paymentUrl = "https://hololand.app/pay/${safeName}";`);
2111
- if (paywall.gatedContent && paywall.gatedContent.length > 0) {
2112
- lines.push(" public GameObject[] gatedObjects;");
2113
- }
2114
- lines.push("");
2115
- lines.push(" public override void Interact() {");
2116
- lines.push(" if (!isUnlocked) {");
2117
- lines.push(" VRCUrl url = new VRCUrl(paymentUrl);");
2118
- lines.push(" }");
2119
- lines.push(" }");
2120
- lines.push("");
2121
- lines.push(" public void OnPaymentVerified() {");
2122
- lines.push(" if (!Networking.IsOwner(gameObject)) {");
2123
- lines.push(" Networking.SetOwner(Networking.LocalPlayer, gameObject);");
2124
- lines.push(" }");
2125
- lines.push(" isUnlocked = true;");
2126
- lines.push(" RequestSerialization();");
2127
- lines.push(" }");
2128
- lines.push("");
2129
- lines.push(" public override void OnDeserialization() {");
2130
- if (paywall.gatedContent && paywall.gatedContent.length > 0) {
2131
- lines.push(" foreach (var obj in gatedObjects) {");
2132
- lines.push(" if (obj != null) obj.SetActive(isUnlocked);");
2133
- lines.push(" }");
2134
- }
2135
- lines.push(" }");
2136
- lines.push("}");
2137
- return lines.join("\n");
2138
- }
2139
- function paymentToR3F(paywall) {
2140
- const lines = [];
2141
- const safeName = paywall.name.replace(/[^a-zA-Z0-9_]/g, "_");
2142
- lines.push(`// x402 Paywall: ${paywall.name} (R3F/React)`);
2143
- lines.push(`export const ${safeName}PaywallConfig = {`);
2144
- lines.push(` name: "${paywall.name}",`);
2145
- lines.push(` price: ${paywall.price},`);
2146
- lines.push(` asset: "${paywall.asset}",`);
2147
- lines.push(` network: "${paywall.network}",`);
2148
- lines.push(` recipient: "${paywall.recipient}",`);
2149
- lines.push(` type: "${paywall.type}",`);
2150
- if (paywall.description) {
2151
- lines.push(` description: "${paywall.description}",`);
2152
- }
2153
- if (paywall.gatedContent && paywall.gatedContent.length > 0) {
2154
- lines.push(
2155
- ` gatedContent: [${paywall.gatedContent.map((g) => `"${esc(g, "TypeScript")}"`).join(", ")}],`
2156
- );
2157
- }
2158
- if (paywall.revenueSplit) {
2159
- lines.push(
2160
- ` revenueSplit: { creator: ${paywall.revenueSplit.creator}, platform: ${paywall.revenueSplit.platform}, agent: ${paywall.revenueSplit.agent} },`
2161
- );
2162
- }
2163
- lines.push("};");
2164
- return lines.join("\n");
2165
- }
2166
- function paymentToUSDA(paywall) {
2167
- const lines = [];
2168
- const safeName = paywall.name.replace(/[^a-zA-Z0-9_]/g, "_");
2169
- lines.push(`def Scope "Paywall_${safeName}" {`);
2170
- lines.push(` custom string holoscript:paywallType = "${paywall.type}"`);
2171
- lines.push(` custom float holoscript:price = ${paywall.price}`);
2172
- lines.push(` custom string holoscript:asset = "${paywall.asset}"`);
2173
- lines.push(` custom string holoscript:network = "${paywall.network}"`);
2174
- if (paywall.recipient) {
2175
- lines.push(` custom string holoscript:recipient = "${paywall.recipient}"`);
2176
- }
2177
- if (paywall.description) {
2178
- lines.push(` custom string holoscript:description = "${paywall.description}"`);
2179
- }
2180
- if (paywall.gatedContent && paywall.gatedContent.length > 0) {
2181
- lines.push(
2182
- ` custom string[] holoscript:gatedContent = [${paywall.gatedContent.map((g) => `"${esc(g, "USD")}"`).join(", ")}]`
2183
- );
2184
- }
2185
- if (paywall.revenueSplit) {
2186
- lines.push(` custom float holoscript:revenueSplitCreator = ${paywall.revenueSplit.creator}`);
2187
- lines.push(
2188
- ` custom float holoscript:revenueSplitPlatform = ${paywall.revenueSplit.platform}`
2189
- );
2190
- lines.push(` custom float holoscript:revenueSplitAgent = ${paywall.revenueSplit.agent}`);
2191
- }
2192
- lines.push("}");
2193
- return lines.join("\n");
2194
- }
2195
- function compileHealthcareBlock(block) {
2196
- const props = block.properties || {};
2197
- let dicomWindow;
2198
- if (props.window_center != null || props.window_width != null) {
2199
- dicomWindow = {
2200
- center: props.window_center ?? 40,
2201
- width: props.window_width ?? 400
2202
- };
2203
- }
2204
- let vitalSigns;
2205
- if (Array.isArray(props.vital_signs)) {
2206
- vitalSigns = props.vital_signs;
2207
- } else if (typeof props.vital_signs === "string") {
2208
- vitalSigns = [props.vital_signs];
2209
- }
2210
- let alertThresholds;
2211
- if (props.alert_thresholds && typeof props.alert_thresholds === "object") {
2212
- alertThresholds = props.alert_thresholds;
2213
- }
2214
- const procedureSteps = [];
2215
- if (Array.isArray(props.steps)) {
2216
- procedureSteps.push(...props.steps);
2217
- }
2218
- for (const child of block.children || []) {
2219
- const c = child;
2220
- if (c.keyword === "step" && c.name) procedureSteps.push(c.name);
2221
- }
2222
- let displayFields;
2223
- if (Array.isArray(props.display_fields)) {
2224
- displayFields = props.display_fields;
2225
- }
2226
- return {
2227
- name: block.name || "unnamed",
2228
- keyword: block.keyword,
2229
- modality: props.modality,
2230
- bodySystem: props.body_system || props.bodySystem,
2231
- dicomWindow,
2232
- vitalSigns,
2233
- alertThresholds,
2234
- procedureSteps: procedureSteps.length > 0 ? procedureSteps : void 0,
2235
- displayFields,
2236
- traits: block.traits || [],
2237
- properties: props
2238
- };
2239
- }
2240
- function healthcareToR3F(healthcare) {
2241
- const safeName = healthcare.name.replace(/[^a-zA-Z0-9_]/g, "_");
2242
- const lines = [];
2243
- lines.push(`// Medical: ${healthcare.name} (${healthcare.keyword})`);
2244
- lines.push(`export const ${safeName}Config = {`);
2245
- lines.push(` name: "${healthcare.name}",`);
2246
- lines.push(` type: "${healthcare.keyword}",`);
2247
- if (healthcare.modality) {
2248
- lines.push(` modality: "${healthcare.modality}",`);
2249
- }
2250
- if (healthcare.bodySystem) {
2251
- lines.push(` bodySystem: "${healthcare.bodySystem}",`);
2252
- }
2253
- if (healthcare.dicomWindow) {
2254
- lines.push(
2255
- ` dicomWindow: { center: ${healthcare.dicomWindow.center}, width: ${healthcare.dicomWindow.width} },`
2256
- );
2257
- }
2258
- if (healthcare.vitalSigns) {
2259
- lines.push(
2260
- ` vitalSigns: [${healthcare.vitalSigns.map((v) => `"${esc(v, "TypeScript")}"`).join(", ")}],`
2261
- );
2262
- }
2263
- if (healthcare.alertThresholds) {
2264
- lines.push(` alertThresholds: ${JSON.stringify(healthcare.alertThresholds)},`);
2265
- }
2266
- if (healthcare.procedureSteps) {
2267
- lines.push(
2268
- ` steps: [${healthcare.procedureSteps.map((s) => `"${esc(s, "TypeScript")}"`).join(", ")}],`
2269
- );
2270
- }
2271
- lines.push("};");
2272
- return lines.join("\n");
2273
- }
2274
- function healthcareToUnity(healthcare) {
2275
- const safeName = healthcare.name.replace(/[^a-zA-Z0-9_]/g, "_");
2276
- const lines = [];
2277
- lines.push(`// Medical: ${healthcare.name}`);
2278
- lines.push(`public class ${safeName}Medical : MonoBehaviour {`);
2279
- lines.push(` public string medicalType = "${healthcare.keyword}";`);
2280
- if (healthcare.modality) {
2281
- lines.push(` public string modality = "${healthcare.modality}";`);
2282
- }
2283
- if (healthcare.bodySystem) {
2284
- lines.push(` public string bodySystem = "${healthcare.bodySystem}";`);
2285
- }
2286
- if (healthcare.dicomWindow) {
2287
- lines.push(` public float windowCenter = ${healthcare.dicomWindow.center}f;`);
2288
- lines.push(` public float windowWidth = ${healthcare.dicomWindow.width}f;`);
2289
- }
2290
- if (healthcare.vitalSigns) {
2291
- lines.push(
2292
- ` public string[] vitalSigns = new string[] { ${healthcare.vitalSigns.map((v) => `"${esc(v, "CSharp")}"`).join(", ")} };`
2293
- );
2294
- }
2295
- if (healthcare.procedureSteps) {
2296
- lines.push(
2297
- ` public string[] procedureSteps = new string[] { ${healthcare.procedureSteps.map((s) => `"${esc(s, "CSharp")}"`).join(", ")} };`
2298
- );
2299
- }
2300
- lines.push("");
2301
- if (healthcare.dicomWindow) {
2302
- lines.push(" // DICOM window-leveling shader uniforms");
2303
- lines.push(" void Start() {");
2304
- lines.push(" var renderer = GetComponent<Renderer>();");
2305
- lines.push(" if (renderer != null) {");
2306
- lines.push(
2307
- ` renderer.material.SetFloat("_WindowCenter", ${healthcare.dicomWindow.center}f);`
2308
- );
2309
- lines.push(
2310
- ` renderer.material.SetFloat("_WindowWidth", ${healthcare.dicomWindow.width}f);`
2311
- );
2312
- lines.push(" }");
2313
- lines.push(" }");
2314
- }
2315
- lines.push("}");
2316
- return lines.join("\n");
2317
- }
2318
- function healthcareToGodot(healthcare) {
2319
- const lines = [];
2320
- lines.push(`# Medical: ${healthcare.name}`);
2321
- lines.push("extends Node3D");
2322
- lines.push("");
2323
- lines.push(`@export var medical_type: String = "${healthcare.keyword}"`);
2324
- if (healthcare.modality) {
2325
- lines.push(`@export var modality: String = "${healthcare.modality}"`);
2326
- }
2327
- if (healthcare.bodySystem) {
2328
- lines.push(`@export var body_system: String = "${healthcare.bodySystem}"`);
2329
- }
2330
- if (healthcare.dicomWindow) {
2331
- lines.push(`@export var window_center: float = ${healthcare.dicomWindow.center}`);
2332
- lines.push(`@export var window_width: float = ${healthcare.dicomWindow.width}`);
2333
- }
2334
- if (healthcare.vitalSigns) {
2335
- lines.push(
2336
- `@export var vital_signs: PackedStringArray = [${healthcare.vitalSigns.map((v) => `"${esc(v, "GDScript")}"`).join(", ")}]`
2337
- );
2338
- }
2339
- if (healthcare.dicomWindow) {
2340
- lines.push("");
2341
- lines.push("signal window_level_changed(center: float, width: float)");
2342
- lines.push("");
2343
- lines.push("func set_window_level(center: float, width: float) -> void:");
2344
- lines.push(" window_center = center");
2345
- lines.push(" window_width = width");
2346
- lines.push(' var mat = get_node("MeshInstance3D").get_surface_override_material(0)');
2347
- lines.push(" if mat:");
2348
- lines.push(' mat.set_shader_parameter("window_center", center)');
2349
- lines.push(' mat.set_shader_parameter("window_width", width)');
2350
- lines.push(" window_level_changed.emit(center, width)");
2351
- }
2352
- return lines.join("\n");
2353
- }
2354
- function healthcareToVRChat(healthcare) {
2355
- const safeName = healthcare.name.replace(/[^a-zA-Z0-9_]/g, "_");
2356
- const lines = [];
2357
- lines.push(`// Medical: ${healthcare.name}`);
2358
- lines.push(`[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]`);
2359
- lines.push(`public class ${safeName}Medical : UdonSharpBehaviour {`);
2360
- lines.push(` public string medicalType = "${healthcare.keyword}";`);
2361
- if (healthcare.vitalSigns) {
2362
- lines.push(` [UdonSynced] public string vitalData = "";`);
2363
- }
2364
- if (healthcare.dicomWindow) {
2365
- lines.push(` [UdonSynced] public float windowCenter = ${healthcare.dicomWindow.center}f;`);
2366
- lines.push(` [UdonSynced] public float windowWidth = ${healthcare.dicomWindow.width}f;`);
2367
- }
2368
- lines.push("}");
2369
- return lines.join("\n");
2370
- }
2371
- function healthcareToUSDA(healthcare) {
2372
- const safeName = healthcare.name.replace(/[^a-zA-Z0-9_]/g, "_");
2373
- const lines = [];
2374
- lines.push(`def Scope "Medical_${safeName}" {`);
2375
- lines.push(` custom string holoscript:medicalType = "${healthcare.keyword}"`);
2376
- if (healthcare.modality) {
2377
- lines.push(` custom string holoscript:modality = "${healthcare.modality}"`);
2378
- }
2379
- if (healthcare.bodySystem) {
2380
- lines.push(` custom string holoscript:bodySystem = "${healthcare.bodySystem}"`);
2381
- }
2382
- if (healthcare.dicomWindow) {
2383
- lines.push(` custom float holoscript:dicomWindowCenter = ${healthcare.dicomWindow.center}`);
2384
- lines.push(` custom float holoscript:dicomWindowWidth = ${healthcare.dicomWindow.width}`);
2385
- }
2386
- lines.push("}");
2387
- return lines.join("\n");
2388
- }
2389
- function compileRoboticsBlock(block) {
2390
- const props = block.properties || {};
2391
- let jointLimits;
2392
- if (props.lower != null || props.upper != null || props.effort != null || props.velocity != null) {
2393
- jointLimits = {
2394
- lower: props.lower ?? -3.14159,
2395
- upper: props.upper ?? 3.14159,
2396
- effort: props.effort ?? 100,
2397
- velocity: props.velocity ?? 1
2398
- };
2399
- } else if (props.limits && typeof props.limits === "object") {
2400
- const lim = props.limits;
2401
- jointLimits = {
2402
- lower: lim.lower ?? -3.14159,
2403
- upper: lim.upper ?? 3.14159,
2404
- effort: lim.effort ?? 100,
2405
- velocity: lim.velocity ?? 1
2406
- };
2407
- }
2408
- let ros2;
2409
- if (props.ros2_package || props.ros2_node || props.ros2_topic) {
2410
- ros2 = {
2411
- packageName: props.ros2_package,
2412
- nodeType: props.ros2_node,
2413
- topicName: props.ros2_topic
2414
- };
2415
- }
2416
- return {
2417
- name: block.name || "unnamed",
2418
- keyword: block.keyword,
2419
- jointType: props.joint_type || props.type,
2420
- jointLimits,
2421
- driveType: props.drive_type || props.drive,
2422
- controllerType: props.controller_type || props.controller,
2423
- effectorType: props.effector_type || props.effector,
2424
- sensorType: props.sensor_type || props.sensor,
2425
- ros2,
2426
- safetyRating: props.safety_rating || props.safety,
2427
- traits: block.traits || [],
2428
- properties: props
2429
- };
2430
- }
2431
- function roboticsToR3F(robotics) {
2432
- const safeName = robotics.name.replace(/[^a-zA-Z0-9_]/g, "_");
2433
- const lines = [];
2434
- lines.push(`// Robotics: ${robotics.name} (${robotics.keyword})`);
2435
- lines.push(`export const ${safeName}Config = {`);
2436
- lines.push(` name: "${robotics.name}",`);
2437
- lines.push(` type: "${robotics.keyword}",`);
2438
- if (robotics.jointType) {
2439
- lines.push(` jointType: "${robotics.jointType}",`);
2440
- }
2441
- if (robotics.jointLimits) {
2442
- lines.push(
2443
- ` jointLimits: { lower: ${robotics.jointLimits.lower}, upper: ${robotics.jointLimits.upper}, effort: ${robotics.jointLimits.effort}, velocity: ${robotics.jointLimits.velocity} },`
2444
- );
2445
- }
2446
- if (robotics.driveType) {
2447
- lines.push(` driveType: "${robotics.driveType}",`);
2448
- }
2449
- if (robotics.controllerType) {
2450
- lines.push(` controllerType: "${robotics.controllerType}",`);
2451
- }
2452
- if (robotics.effectorType) {
2453
- lines.push(` effectorType: "${robotics.effectorType}",`);
2454
- }
2455
- if (robotics.sensorType) {
2456
- lines.push(` sensorType: "${robotics.sensorType}",`);
2457
- }
2458
- if (robotics.safetyRating) {
2459
- lines.push(` safetyRating: "${robotics.safetyRating}",`);
2460
- }
2461
- lines.push("};");
2462
- return lines.join("\n");
2463
- }
2464
- function roboticsToUnity(robotics) {
2465
- const safeName = robotics.name.replace(/[^a-zA-Z0-9_]/g, "_");
2466
- const lines = [];
2467
- lines.push(`// Robotics: ${robotics.name}`);
2468
- lines.push(`public class ${safeName}Robotics : MonoBehaviour {`);
2469
- lines.push(` public string roboticsType = "${robotics.keyword}";`);
2470
- if (robotics.jointType) {
2471
- lines.push(
2472
- ` public ArticulationJointType jointType = ArticulationJointType.${capitalizeFirst(robotics.jointType)};`
2473
- );
2474
- }
2475
- if (robotics.jointLimits) {
2476
- lines.push(` public float lowerLimit = ${robotics.jointLimits.lower}f;`);
2477
- lines.push(` public float upperLimit = ${robotics.jointLimits.upper}f;`);
2478
- lines.push(` public float effortLimit = ${robotics.jointLimits.effort}f;`);
2479
- lines.push(` public float velocityLimit = ${robotics.jointLimits.velocity}f;`);
2480
- }
2481
- if (robotics.driveType) {
2482
- lines.push(` public string driveType = "${robotics.driveType}";`);
2483
- }
2484
- if (robotics.controllerType) {
2485
- lines.push(` public string controllerType = "${robotics.controllerType}";`);
2486
- }
2487
- if (robotics.safetyRating) {
2488
- lines.push(` public string safetyRating = "${robotics.safetyRating}";`);
2489
- }
2490
- lines.push("");
2491
- if (robotics.jointLimits) {
2492
- lines.push(" void Start() {");
2493
- lines.push(" var body = GetComponent<ArticulationBody>();");
2494
- lines.push(" if (body != null) {");
2495
- lines.push(" var drive = body.xDrive;");
2496
- lines.push(` drive.lowerLimit = ${robotics.jointLimits.lower}f * Mathf.Rad2Deg;`);
2497
- lines.push(` drive.upperLimit = ${robotics.jointLimits.upper}f * Mathf.Rad2Deg;`);
2498
- lines.push(` drive.forceLimit = ${robotics.jointLimits.effort}f;`);
2499
- lines.push(" body.xDrive = drive;");
2500
- lines.push(" }");
2501
- lines.push(" }");
2502
- }
2503
- lines.push("}");
2504
- return lines.join("\n");
2505
- }
2506
- function roboticsToGodot(robotics) {
2507
- const lines = [];
2508
- lines.push(`# Robotics: ${robotics.name}`);
2509
- lines.push("extends Node3D");
2510
- lines.push("");
2511
- lines.push(`@export var robotics_type: String = "${robotics.keyword}"`);
2512
- if (robotics.jointType) {
2513
- lines.push(`@export var joint_type: String = "${robotics.jointType}"`);
2514
- }
2515
- if (robotics.jointLimits) {
2516
- lines.push(`@export var lower_limit: float = ${robotics.jointLimits.lower}`);
2517
- lines.push(`@export var upper_limit: float = ${robotics.jointLimits.upper}`);
2518
- lines.push(`@export var effort_limit: float = ${robotics.jointLimits.effort}`);
2519
- lines.push(`@export var velocity_limit: float = ${robotics.jointLimits.velocity}`);
2520
- }
2521
- if (robotics.driveType) {
2522
- lines.push(`@export var drive_type: String = "${robotics.driveType}"`);
2523
- }
2524
- if (robotics.controllerType) {
2525
- lines.push(`@export var controller_type: String = "${robotics.controllerType}"`);
2526
- }
2527
- if (robotics.safetyRating) {
2528
- lines.push(`@export var safety_rating: String = "${robotics.safetyRating}"`);
2529
- }
2530
- if (robotics.jointType === "revolute" || robotics.jointType === "continuous") {
2531
- lines.push("");
2532
- lines.push("signal joint_position_changed(angle_rad: float)");
2533
- lines.push("");
2534
- lines.push("var current_angle: float = 0.0");
2535
- lines.push("");
2536
- lines.push("func set_joint_angle(angle: float) -> void:");
2537
- if (robotics.jointLimits) {
2538
- lines.push(
2539
- ` angle = clampf(angle, ${robotics.jointLimits.lower}, ${robotics.jointLimits.upper})`
2540
- );
2541
- }
2542
- lines.push(" current_angle = angle");
2543
- lines.push(" rotation.x = angle");
2544
- lines.push(" joint_position_changed.emit(angle)");
2545
- }
2546
- return lines.join("\n");
2547
- }
2548
- function roboticsToVRChat(robotics) {
2549
- const safeName = robotics.name.replace(/[^a-zA-Z0-9_]/g, "_");
2550
- const lines = [];
2551
- lines.push(`// Robotics: ${robotics.name}`);
2552
- lines.push(`[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]`);
2553
- lines.push(`public class ${safeName}Robotics : UdonSharpBehaviour {`);
2554
- lines.push(` public string roboticsType = "${robotics.keyword}";`);
2555
- if (robotics.jointType) {
2556
- lines.push(` public string jointType = "${robotics.jointType}";`);
2557
- }
2558
- if (robotics.jointLimits) {
2559
- lines.push(` [UdonSynced] public float jointAngle = 0f;`);
2560
- lines.push(` public float lowerLimit = ${robotics.jointLimits.lower}f;`);
2561
- lines.push(` public float upperLimit = ${robotics.jointLimits.upper}f;`);
2562
- }
2563
- if (robotics.safetyRating) {
2564
- lines.push(` public string safetyRating = "${robotics.safetyRating}";`);
2565
- }
2566
- lines.push("}");
2567
- return lines.join("\n");
2568
- }
2569
- function roboticsToUSDA(robotics) {
2570
- const safeName = robotics.name.replace(/[^a-zA-Z0-9_]/g, "_");
2571
- const lines = [];
2572
- lines.push(`def Scope "Robotics_${safeName}" {`);
2573
- lines.push(` custom string holoscript:roboticsType = "${robotics.keyword}"`);
2574
- if (robotics.jointType) {
2575
- lines.push(` custom string holoscript:jointType = "${robotics.jointType}"`);
2576
- }
2577
- if (robotics.jointLimits) {
2578
- lines.push(` custom float holoscript:jointLower = ${robotics.jointLimits.lower}`);
2579
- lines.push(` custom float holoscript:jointUpper = ${robotics.jointLimits.upper}`);
2580
- lines.push(` custom float holoscript:jointEffort = ${robotics.jointLimits.effort}`);
2581
- lines.push(` custom float holoscript:jointVelocity = ${robotics.jointLimits.velocity}`);
2582
- }
2583
- if (robotics.driveType) {
2584
- lines.push(` custom string holoscript:driveType = "${robotics.driveType}"`);
2585
- }
2586
- if (robotics.safetyRating) {
2587
- lines.push(` custom string holoscript:safetyRating = "${robotics.safetyRating}"`);
2588
- }
2589
- lines.push("}");
2590
- return lines.join("\n");
2591
- }
2592
- function compileIoTBlock(block) {
2593
- const props = block.properties || {};
2594
- let telemetryFields;
2595
- if (Array.isArray(props.telemetry_fields)) {
2596
- telemetryFields = props.telemetry_fields;
2597
- } else if (typeof props.telemetry_fields === "string") {
2598
- telemetryFields = [props.telemetry_fields];
2599
- }
2600
- let bindings;
2601
- if (props.bindings && typeof props.bindings === "object") {
2602
- bindings = props.bindings;
2603
- }
2604
- return {
2605
- name: block.name || "unnamed",
2606
- keyword: block.keyword,
2607
- deviceType: props.device_type || props.type,
2608
- protocol: props.protocol,
2609
- telemetryFields,
2610
- updateInterval: props.update_interval,
2611
- twinModel: props.twin_model || props.model,
2612
- bindings,
2613
- traits: block.traits || [],
2614
- properties: props
2615
- };
2616
- }
2617
- function iotToR3F(iot) {
2618
- const safeName = iot.name.replace(/[^a-zA-Z0-9_]/g, "_");
2619
- const lines = [];
2620
- lines.push(`// IoT: ${iot.name} (${iot.keyword})`);
2621
- lines.push(`export const ${safeName}Config = {`);
2622
- lines.push(` name: "${iot.name}",`);
2623
- lines.push(` type: "${iot.keyword}",`);
2624
- if (iot.deviceType) lines.push(` deviceType: "${iot.deviceType}",`);
2625
- if (iot.protocol) lines.push(` protocol: "${esc(iot.protocol, "TypeScript")}",`);
2626
- if (iot.telemetryFields)
2627
- lines.push(
2628
- ` telemetryFields: [${iot.telemetryFields.map((f) => `"${esc(f, "TypeScript")}"`).join(", ")}],`
2629
- );
2630
- if (iot.updateInterval) lines.push(` updateInterval: ${iot.updateInterval},`);
2631
- if (iot.twinModel) lines.push(` twinModel: "${esc(iot.twinModel, "TypeScript")}",`);
2632
- lines.push("};");
2633
- return lines.join("\n");
2634
- }
2635
- function iotToUnity(iot) {
2636
- const safeName = iot.name.replace(/[^a-zA-Z0-9_]/g, "_");
2637
- const lines = [];
2638
- lines.push(`// IoT: ${iot.name}`);
2639
- lines.push(`public class ${safeName}IoT : MonoBehaviour {`);
2640
- lines.push(` public string deviceType = "${esc(iot.keyword, "CSharp")}";`);
2641
- if (iot.protocol) lines.push(` public string protocol = "${esc(iot.protocol, "CSharp")}";`);
2642
- if (iot.updateInterval)
2643
- lines.push(` public float updateInterval = ${iot.updateInterval / 1e3}f;`);
2644
- if (iot.telemetryFields)
2645
- lines.push(
2646
- ` public string[] telemetryFields = new string[] { ${iot.telemetryFields.map((f) => `"${esc(f, "CSharp")}"`).join(", ")} };`
2647
- );
2648
- if (iot.twinModel) lines.push(` public string twinModel = "${esc(iot.twinModel, "CSharp")}";`);
2649
- lines.push("}");
2650
- return lines.join("\n");
2651
- }
2652
- function iotToGodot(iot) {
2653
- const lines = [];
2654
- lines.push(`# IoT: ${iot.name}`);
2655
- lines.push("extends Node");
2656
- lines.push("");
2657
- lines.push(`@export var device_type: String = "${esc(iot.keyword, "GDScript")}"`);
2658
- if (iot.protocol) lines.push(`@export var protocol: String = "${esc(iot.protocol, "GDScript")}"`);
2659
- if (iot.updateInterval)
2660
- lines.push(`@export var update_interval: float = ${iot.updateInterval / 1e3}`);
2661
- if (iot.telemetryFields)
2662
- lines.push(
2663
- `@export var telemetry_fields: PackedStringArray = [${iot.telemetryFields.map((f) => `"${esc(f, "GDScript")}"`).join(", ")}]`
2664
- );
2665
- if (iot.twinModel)
2666
- lines.push(`@export var twin_model: String = "${esc(iot.twinModel, "GDScript")}"`);
2667
- lines.push("");
2668
- lines.push("signal telemetry_received(field: String, value: float)");
2669
- lines.push("signal connection_changed(connected: bool)");
2670
- return lines.join("\n");
2671
- }
2672
- function iotToVRChat(iot) {
2673
- const safeName = iot.name.replace(/[^a-zA-Z0-9_]/g, "_");
2674
- const lines = [];
2675
- lines.push(`// IoT: ${iot.name}`);
2676
- lines.push("[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]");
2677
- lines.push(`public class ${safeName}IoT : UdonSharpBehaviour {`);
2678
- lines.push(` public string deviceType = "${iot.keyword}";`);
2679
- if (iot.telemetryFields) lines.push(` [UdonSynced] public string telemetryData = "";`);
2680
- if (iot.updateInterval)
2681
- lines.push(` public float updateInterval = ${iot.updateInterval / 1e3}f;`);
2682
- lines.push("}");
2683
- return lines.join("\n");
2684
- }
2685
- function iotToUSDA(iot) {
2686
- const safeName = iot.name.replace(/[^a-zA-Z0-9_]/g, "_");
2687
- const lines = [];
2688
- lines.push(`def Scope "IoT_${safeName}" {`);
2689
- lines.push(` custom string holoscript:deviceType = "${iot.keyword}"`);
2690
- if (iot.protocol) lines.push(` custom string holoscript:protocol = "${iot.protocol}"`);
2691
- if (iot.updateInterval)
2692
- lines.push(` custom float holoscript:updateInterval = ${iot.updateInterval}`);
2693
- if (iot.twinModel) lines.push(` custom string holoscript:twinModel = "${iot.twinModel}"`);
2694
- lines.push("}");
2695
- return lines.join("\n");
2696
- }
2697
- function compileDataVizBlock(block) {
2698
- const props = block.properties || {};
2699
- let axes;
2700
- if (props.x_axis || props.y_axis || props.z_axis) {
2701
- axes = { x: props.x_axis, y: props.y_axis, z: props.z_axis };
2702
- } else if (props.axes && typeof props.axes === "object") {
2703
- const a = props.axes;
2704
- axes = {
2705
- x: a.x,
2706
- y: a.y,
2707
- z: a.z
2708
- };
2709
- }
2710
- let dimensions;
2711
- if (props.width != null || props.height != null) {
2712
- dimensions = { width: props.width ?? 400, height: props.height ?? 300 };
2713
- }
2714
- return {
2715
- name: block.name || "unnamed",
2716
- keyword: block.keyword,
2717
- chartType: props.chart_type || props.type,
2718
- dataSource: props.data_source || props.source,
2719
- axes,
2720
- aggregation: props.aggregation,
2721
- refreshInterval: props.refresh_interval,
2722
- dimensions,
2723
- traits: block.traits || [],
2724
- properties: props
2725
- };
2726
- }
2727
- function datavizToR3F(dv) {
2728
- const safeName = dv.name.replace(/[^a-zA-Z0-9_]/g, "_");
2729
- const lines = [];
2730
- lines.push(`// DataViz: ${dv.name} (${dv.keyword})`);
2731
- lines.push(`export const ${safeName}Config = {`);
2732
- lines.push(` name: "${dv.name}",`);
2733
- lines.push(` type: "${dv.keyword}",`);
2734
- if (dv.chartType) lines.push(` chartType: "${dv.chartType}",`);
2735
- if (dv.dataSource) lines.push(` dataSource: "${dv.dataSource}",`);
2736
- if (dv.axes) lines.push(` axes: ${JSON.stringify(dv.axes)},`);
2737
- if (dv.aggregation) lines.push(` aggregation: "${dv.aggregation}",`);
2738
- if (dv.refreshInterval) lines.push(` refreshInterval: ${dv.refreshInterval},`);
2739
- if (dv.dimensions)
2740
- lines.push(` dimensions: { width: ${dv.dimensions.width}, height: ${dv.dimensions.height} },`);
2741
- lines.push("};");
2742
- return lines.join("\n");
2743
- }
2744
- function datavizToUnity(dv) {
2745
- const safeName = dv.name.replace(/[^a-zA-Z0-9_]/g, "_");
2746
- const lines = [];
2747
- lines.push(`// DataViz: ${dv.name}`);
2748
- lines.push(`public class ${safeName}DataViz : MonoBehaviour {`);
2749
- lines.push(` public string vizType = "${dv.keyword}";`);
2750
- if (dv.chartType) lines.push(` public string chartType = "${dv.chartType}";`);
2751
- if (dv.dataSource) lines.push(` public string dataSource = "${dv.dataSource}";`);
2752
- if (dv.refreshInterval)
2753
- lines.push(` public float refreshInterval = ${dv.refreshInterval / 1e3}f;`);
2754
- if (dv.dimensions) {
2755
- lines.push(` public float width = ${dv.dimensions.width}f;`);
2756
- lines.push(` public float height = ${dv.dimensions.height}f;`);
2757
- }
2758
- lines.push("}");
2759
- return lines.join("\n");
2760
- }
2761
- function datavizToGodot(dv) {
2762
- const lines = [];
2763
- lines.push(`# DataViz: ${dv.name}`);
2764
- lines.push("extends Control");
2765
- lines.push("");
2766
- lines.push(`@export var viz_type: String = "${dv.keyword}"`);
2767
- if (dv.chartType) lines.push(`@export var chart_type: String = "${dv.chartType}"`);
2768
- if (dv.dataSource) lines.push(`@export var data_source: String = "${dv.dataSource}"`);
2769
- if (dv.refreshInterval)
2770
- lines.push(`@export var refresh_interval: float = ${dv.refreshInterval / 1e3}`);
2771
- if (dv.dimensions) {
2772
- lines.push(`@export var chart_width: float = ${dv.dimensions.width}`);
2773
- lines.push(`@export var chart_height: float = ${dv.dimensions.height}`);
2774
- }
2775
- lines.push("");
2776
- lines.push("signal data_updated(values: Array)");
2777
- return lines.join("\n");
2778
- }
2779
- function datavizToVRChat(dv) {
2780
- const safeName = dv.name.replace(/[^a-zA-Z0-9_]/g, "_");
2781
- const lines = [];
2782
- lines.push(`// DataViz: ${dv.name}`);
2783
- lines.push("[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]");
2784
- lines.push(`public class ${safeName}DataViz : UdonSharpBehaviour {`);
2785
- lines.push(` public string vizType = "${dv.keyword}";`);
2786
- if (dv.chartType) lines.push(` public string chartType = "${dv.chartType}";`);
2787
- if (dv.dataSource) lines.push(` [UdonSynced] public string dataJson = "";`);
2788
- lines.push("}");
2789
- return lines.join("\n");
2790
- }
2791
- function datavizToUSDA(dv) {
2792
- const safeName = dv.name.replace(/[^a-zA-Z0-9_]/g, "_");
2793
- const lines = [];
2794
- lines.push(`def Scope "DataViz_${safeName}" {`);
2795
- lines.push(` custom string holoscript:vizType = "${dv.keyword}"`);
2796
- if (dv.chartType) lines.push(` custom string holoscript:chartType = "${dv.chartType}"`);
2797
- if (dv.dataSource) lines.push(` custom string holoscript:dataSource = "${dv.dataSource}"`);
2798
- lines.push("}");
2799
- return lines.join("\n");
2800
- }
2801
- function compileEducationBlock(block) {
2802
- const props = block.properties || {};
2803
- let objectives;
2804
- if (Array.isArray(props.objectives)) objectives = props.objectives;
2805
- let prerequisites;
2806
- if (Array.isArray(props.prerequisites)) prerequisites = props.prerequisites;
2807
- let questions;
2808
- if (Array.isArray(props.questions)) {
2809
- questions = props.questions.map(
2810
- (q) => typeof q === "string" ? { question: q } : q
2811
- );
2812
- }
2813
- for (const child of block.children || []) {
2814
- const c = child;
2815
- if (c.keyword === "question" && c.name) {
2816
- if (!questions) questions = [];
2817
- questions.push({
2818
- question: c.name,
2819
- options: c.properties?.options,
2820
- answer: c.properties?.answer
2821
- });
2822
- }
2823
- }
2824
- return {
2825
- name: block.name || "unnamed",
2826
- keyword: block.keyword,
2827
- contentType: props.content_type || block.keyword,
2828
- difficulty: props.difficulty,
2829
- objectives,
2830
- questions,
2831
- prerequisites,
2832
- duration: props.duration,
2833
- traits: block.traits || [],
2834
- properties: props
2835
- };
2836
- }
2837
- function educationToR3F(edu) {
2838
- const safeName = edu.name.replace(/[^a-zA-Z0-9_]/g, "_");
2839
- const lines = [];
2840
- lines.push(`// Education: ${edu.name} (${edu.keyword})`);
2841
- lines.push(`export const ${safeName}Config = {`);
2842
- lines.push(` name: "${edu.name}",`);
2843
- lines.push(` type: "${edu.keyword}",`);
2844
- if (edu.difficulty) lines.push(` difficulty: "${esc(edu.difficulty, "TypeScript")}",`);
2845
- if (edu.objectives)
2846
- lines.push(
2847
- ` objectives: [${edu.objectives.map((o) => `"${esc(o, "TypeScript")}"`).join(", ")}],`
2848
- );
2849
- if (edu.duration) lines.push(` duration: ${edu.duration},`);
2850
- if (edu.questions) lines.push(` questions: ${JSON.stringify(edu.questions)},`);
2851
- if (edu.prerequisites)
2852
- lines.push(
2853
- ` prerequisites: [${edu.prerequisites.map((p) => `"${esc(p, "TypeScript")}"`).join(", ")}],`
2854
- );
2855
- lines.push("};");
2856
- return lines.join("\n");
2857
- }
2858
- function educationToUnity(edu) {
2859
- const safeName = edu.name.replace(/[^a-zA-Z0-9_]/g, "_");
2860
- const lines = [];
2861
- lines.push(`// Education: ${edu.name}`);
2862
- lines.push(`public class ${safeName}Education : MonoBehaviour {`);
2863
- lines.push(` public string contentType = "${esc(edu.keyword, "CSharp")}";`);
2864
- if (edu.difficulty)
2865
- lines.push(` public string difficulty = "${esc(edu.difficulty, "CSharp")}";`);
2866
- if (edu.duration) lines.push(` public int durationMinutes = ${edu.duration};`);
2867
- if (edu.objectives)
2868
- lines.push(
2869
- ` public string[] objectives = new string[] { ${edu.objectives.map((o) => `"${esc(o, "CSharp")}"`).join(", ")} };`
2870
- );
2871
- if (edu.questions) lines.push(` public int questionCount = ${edu.questions.length};`);
2872
- lines.push("}");
2873
- return lines.join("\n");
2874
- }
2875
- function educationToGodot(edu) {
2876
- const lines = [];
2877
- lines.push(`# Education: ${edu.name}`);
2878
- lines.push("extends Node");
2879
- lines.push("");
2880
- lines.push(`@export var content_type: String = "${esc(edu.keyword, "GDScript")}"`);
2881
- if (edu.difficulty)
2882
- lines.push(`@export var difficulty: String = "${esc(edu.difficulty, "GDScript")}"`);
2883
- if (edu.duration) lines.push(`@export var duration_minutes: int = ${edu.duration}`);
2884
- if (edu.objectives)
2885
- lines.push(
2886
- `@export var objectives: PackedStringArray = [${edu.objectives.map((o) => `"${esc(o, "GDScript")}"`).join(", ")}]`
2887
- );
2888
- lines.push("");
2889
- lines.push("signal lesson_completed(score: float)");
2890
- lines.push("signal quiz_submitted(answers: Dictionary)");
2891
- return lines.join("\n");
2892
- }
2893
- function educationToVRChat(edu) {
2894
- const safeName = edu.name.replace(/[^a-zA-Z0-9_]/g, "_");
2895
- const lines = [];
2896
- lines.push(`// Education: ${edu.name}`);
2897
- lines.push("[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]");
2898
- lines.push(`public class ${safeName}Education : UdonSharpBehaviour {`);
2899
- lines.push(` public string contentType = "${edu.keyword}";`);
2900
- if (edu.difficulty) lines.push(` public string difficulty = "${edu.difficulty}";`);
2901
- if (edu.questions) lines.push(` [UdonSynced] public int currentQuestion = 0;`);
2902
- lines.push("}");
2903
- return lines.join("\n");
2904
- }
2905
- function educationToUSDA(edu) {
2906
- const safeName = edu.name.replace(/[^a-zA-Z0-9_]/g, "_");
2907
- const lines = [];
2908
- lines.push(`def Scope "Education_${safeName}" {`);
2909
- lines.push(` custom string holoscript:contentType = "${edu.keyword}"`);
2910
- if (edu.difficulty) lines.push(` custom string holoscript:difficulty = "${edu.difficulty}"`);
2911
- if (edu.duration) lines.push(` custom int holoscript:durationMinutes = ${edu.duration}`);
2912
- lines.push("}");
2913
- return lines.join("\n");
2914
- }
2915
- function compileMusicBlock(block) {
2916
- const props = block.properties || {};
2917
- let timeSignature;
2918
- if (Array.isArray(props.time_signature) && props.time_signature.length === 2) {
2919
- timeSignature = props.time_signature;
2920
- }
2921
- let effects;
2922
- if (Array.isArray(props.effects)) effects = props.effects;
2923
- for (const child of block.children || []) {
2924
- const c = child;
2925
- if (c.keyword === "effect" && c.name) {
2926
- if (!effects) effects = [];
2927
- effects.push(c.name);
2928
- }
2929
- }
2930
- return {
2931
- name: block.name || "unnamed",
2932
- keyword: block.keyword,
2933
- instrumentType: props.instrument_type || props.type,
2934
- bpm: props.bpm,
2935
- timeSignature,
2936
- key: props.key,
2937
- effects,
2938
- pattern: props.pattern,
2939
- bars: props.bars,
2940
- traits: block.traits || [],
2941
- properties: props
2942
- };
2943
- }
2944
- function musicToR3F(music) {
2945
- const safeName = music.name.replace(/[^a-zA-Z0-9_]/g, "_");
2946
- const lines = [];
2947
- lines.push(`// Music: ${music.name} (${music.keyword})`);
2948
- lines.push(`export const ${safeName}Config = {`);
2949
- lines.push(` name: "${music.name}",`);
2950
- lines.push(` type: "${music.keyword}",`);
2951
- if (music.instrumentType) lines.push(` instrumentType: "${music.instrumentType}",`);
2952
- if (music.bpm) lines.push(` bpm: ${music.bpm},`);
2953
- if (music.timeSignature) lines.push(` timeSignature: [${music.timeSignature.join(", ")}],`);
2954
- if (music.key) lines.push(` key: "${esc(music.key, "TypeScript")}",`);
2955
- if (music.effects)
2956
- lines.push(` effects: [${music.effects.map((e) => `"${esc(e, "TypeScript")}"`).join(", ")}],`);
2957
- if (music.pattern) lines.push(` pattern: "${esc(music.pattern, "TypeScript")}",`);
2958
- if (music.bars) lines.push(` bars: ${music.bars},`);
2959
- lines.push("};");
2960
- return lines.join("\n");
2961
- }
2962
- function musicToUnity(music) {
2963
- const safeName = music.name.replace(/[^a-zA-Z0-9_]/g, "_");
2964
- const lines = [];
2965
- lines.push(`// Music: ${music.name}`);
2966
- lines.push(`public class ${safeName}Music : MonoBehaviour {`);
2967
- lines.push(` public string musicType = "${esc(music.keyword, "CSharp")}";`);
2968
- if (music.instrumentType)
2969
- lines.push(` public string instrumentType = "${esc(music.instrumentType, "CSharp")}";`);
2970
- if (music.bpm) lines.push(` public float bpm = ${music.bpm}f;`);
2971
- if (music.key) lines.push(` public string musicalKey = "${esc(music.key, "CSharp")}";`);
2972
- if (music.effects)
2973
- lines.push(
2974
- ` public string[] effects = new string[] { ${music.effects.map((e) => `"${esc(e, "CSharp")}"`).join(", ")} };`
2975
- );
2976
- lines.push("}");
2977
- return lines.join("\n");
2978
- }
2979
- function musicToGodot(music) {
2980
- const lines = [];
2981
- lines.push(`# Music: ${music.name}`);
2982
- lines.push("extends Node");
2983
- lines.push("");
2984
- lines.push(`@export var music_type: String = "${music.keyword}"`);
2985
- if (music.instrumentType)
2986
- lines.push(`@export var instrument_type: String = "${music.instrumentType}"`);
2987
- if (music.bpm) lines.push(`@export var bpm: float = ${music.bpm}`);
2988
- if (music.key) lines.push(`@export var musical_key: String = "${music.key}"`);
2989
- if (music.bars) lines.push(`@export var bars: int = ${music.bars}`);
2990
- lines.push("");
2991
- lines.push("signal beat(beat_number: int)");
2992
- lines.push("signal bar_changed(bar_number: int)");
2993
- return lines.join("\n");
2994
- }
2995
- function musicToVRChat(music) {
2996
- const safeName = music.name.replace(/[^a-zA-Z0-9_]/g, "_");
2997
- const lines = [];
2998
- lines.push(`// Music: ${music.name}`);
2999
- lines.push("[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]");
3000
- lines.push(`public class ${safeName}Music : UdonSharpBehaviour {`);
3001
- lines.push(` public string musicType = "${music.keyword}";`);
3002
- if (music.bpm) lines.push(` [UdonSynced] public float bpm = ${music.bpm}f;`);
3003
- if (music.instrumentType)
3004
- lines.push(` public string instrumentType = "${music.instrumentType}";`);
3005
- lines.push("}");
3006
- return lines.join("\n");
3007
- }
3008
- function musicToUSDA(music) {
3009
- const safeName = music.name.replace(/[^a-zA-Z0-9_]/g, "_");
3010
- const lines = [];
3011
- lines.push(`def Scope "Music_${safeName}" {`);
3012
- lines.push(` custom string holoscript:musicType = "${music.keyword}"`);
3013
- if (music.instrumentType)
3014
- lines.push(` custom string holoscript:instrumentType = "${music.instrumentType}"`);
3015
- if (music.bpm) lines.push(` custom float holoscript:bpm = ${music.bpm}`);
3016
- if (music.key) lines.push(` custom string holoscript:key = "${music.key}"`);
3017
- lines.push("}");
3018
- return lines.join("\n");
3019
- }
3020
- function compileArchitectureBlock(block) {
3021
- const props = block.properties || {};
3022
- return {
3023
- name: block.name || "unnamed",
3024
- keyword: block.keyword,
3025
- structureType: props.structure_type || block.keyword,
3026
- area: props.area,
3027
- height: props.height,
3028
- wallMaterial: props.wall_material || props.wall,
3029
- floorMaterial: props.floor_material || props.floor,
3030
- temperatureSetpoint: props.temperature_setpoint || props.temperature,
3031
- capacity: props.capacity,
3032
- buildingCode: props.building_code || props.code,
3033
- traits: block.traits || [],
3034
- properties: props
3035
- };
3036
- }
3037
- function architectureToR3F(arch) {
3038
- const safeName = arch.name.replace(/[^a-zA-Z0-9_]/g, "_");
3039
- const lines = [];
3040
- lines.push(`// Architecture: ${arch.name} (${arch.keyword})`);
3041
- lines.push(`export const ${safeName}Config = {`);
3042
- lines.push(` name: "${arch.name}",`);
3043
- lines.push(` type: "${arch.keyword}",`);
3044
- if (arch.area) lines.push(` area: ${arch.area},`);
3045
- if (arch.height) lines.push(` height: ${arch.height},`);
3046
- if (arch.wallMaterial) lines.push(` wallMaterial: "${arch.wallMaterial}",`);
3047
- if (arch.floorMaterial) lines.push(` floorMaterial: "${arch.floorMaterial}",`);
3048
- if (arch.capacity) lines.push(` capacity: ${arch.capacity},`);
3049
- if (arch.temperatureSetpoint) lines.push(` temperatureSetpoint: ${arch.temperatureSetpoint},`);
3050
- lines.push("};");
3051
- return lines.join("\n");
3052
- }
3053
- function architectureToUnity(arch) {
3054
- const safeName = arch.name.replace(/[^a-zA-Z0-9_]/g, "_");
3055
- const lines = [];
3056
- lines.push(`// Architecture: ${arch.name}`);
3057
- lines.push(`public class ${safeName}Architecture : MonoBehaviour {`);
3058
- lines.push(` public string structureType = "${arch.keyword}";`);
3059
- if (arch.area) lines.push(` public float area = ${arch.area}f;`);
3060
- if (arch.height) lines.push(` public float height = ${arch.height}f;`);
3061
- if (arch.wallMaterial) lines.push(` public string wallMaterial = "${arch.wallMaterial}";`);
3062
- if (arch.floorMaterial) lines.push(` public string floorMaterial = "${arch.floorMaterial}";`);
3063
- if (arch.capacity) lines.push(` public int capacity = ${arch.capacity};`);
3064
- if (arch.temperatureSetpoint)
3065
- lines.push(` public float temperatureSetpoint = ${arch.temperatureSetpoint}f;`);
3066
- lines.push("}");
3067
- return lines.join("\n");
3068
- }
3069
- function architectureToGodot(arch) {
3070
- const lines = [];
3071
- lines.push(`# Architecture: ${arch.name}`);
3072
- lines.push("extends Node3D");
3073
- lines.push("");
3074
- lines.push(`@export var structure_type: String = "${arch.keyword}"`);
3075
- if (arch.area) lines.push(`@export var area: float = ${arch.area}`);
3076
- if (arch.height) lines.push(`@export var height: float = ${arch.height}`);
3077
- if (arch.wallMaterial) lines.push(`@export var wall_material: String = "${arch.wallMaterial}"`);
3078
- if (arch.floorMaterial)
3079
- lines.push(`@export var floor_material: String = "${arch.floorMaterial}"`);
3080
- if (arch.capacity) lines.push(`@export var capacity: int = ${arch.capacity}`);
3081
- if (arch.temperatureSetpoint) {
3082
- lines.push(`@export var temperature_setpoint: float = ${arch.temperatureSetpoint}`);
3083
- lines.push("");
3084
- lines.push("signal temperature_changed(temp: float)");
3085
- }
3086
- return lines.join("\n");
3087
- }
3088
- function architectureToVRChat(arch) {
3089
- const safeName = arch.name.replace(/[^a-zA-Z0-9_]/g, "_");
3090
- const lines = [];
3091
- lines.push(`// Architecture: ${arch.name}`);
3092
- lines.push("[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]");
3093
- lines.push(`public class ${safeName}Architecture : UdonSharpBehaviour {`);
3094
- lines.push(` public string structureType = "${arch.keyword}";`);
3095
- if (arch.area) lines.push(` public float area = ${arch.area}f;`);
3096
- if (arch.height) lines.push(` public float height = ${arch.height}f;`);
3097
- if (arch.capacity) lines.push(` public int capacity = ${arch.capacity};`);
3098
- lines.push("}");
3099
- return lines.join("\n");
3100
- }
3101
- function architectureToUSDA(arch) {
3102
- const safeName = arch.name.replace(/[^a-zA-Z0-9_]/g, "_");
3103
- const lines = [];
3104
- lines.push(`def Scope "Architecture_${safeName}" {`);
3105
- lines.push(` custom string holoscript:structureType = "${arch.keyword}"`);
3106
- if (arch.area) lines.push(` custom float holoscript:area = ${arch.area}`);
3107
- if (arch.height) lines.push(` custom float holoscript:height = ${arch.height}`);
3108
- if (arch.wallMaterial)
3109
- lines.push(` custom string holoscript:wallMaterial = "${arch.wallMaterial}"`);
3110
- if (arch.capacity) lines.push(` custom int holoscript:capacity = ${arch.capacity}`);
3111
- lines.push("}");
3112
- return lines.join("\n");
3113
- }
3114
- function compileWeb3Block(block) {
3115
- const props = block.properties || {};
3116
- let functions;
3117
- if (Array.isArray(props.functions)) functions = props.functions;
3118
- for (const child of block.children || []) {
3119
- const c = child;
3120
- if (c.keyword === "function" && c.name) {
3121
- if (!functions) functions = [];
3122
- functions.push(c.name);
3123
- }
3124
- }
3125
- return {
3126
- name: block.name || "unnamed",
3127
- keyword: block.keyword,
3128
- standard: props.standard || props.token_standard,
3129
- network: props.network,
3130
- contractAddress: props.contract_address || props.address,
3131
- functions,
3132
- supply: props.supply || props.total_supply,
3133
- votingThreshold: props.voting_threshold || props.threshold,
3134
- traits: block.traits || [],
3135
- properties: props
3136
- };
3137
- }
3138
- function web3ToR3F(web3) {
3139
- const safeName = web3.name.replace(/[^a-zA-Z0-9_]/g, "_");
3140
- const lines = [];
3141
- lines.push(`// Web3: ${web3.name} (${web3.keyword})`);
3142
- lines.push(`export const ${safeName}Config = {`);
3143
- lines.push(` name: "${web3.name}",`);
3144
- lines.push(` type: "${web3.keyword}",`);
3145
- if (web3.standard) lines.push(` standard: "${web3.standard}",`);
3146
- if (web3.network) lines.push(` network: "${web3.network}",`);
3147
- if (web3.contractAddress)
3148
- lines.push(` contractAddress: "${esc(web3.contractAddress, "TypeScript")}",`);
3149
- if (web3.functions)
3150
- lines.push(
3151
- ` functions: [${web3.functions.map((f) => `"${esc(f, "TypeScript")}"`).join(", ")}],`
3152
- );
3153
- if (web3.supply) lines.push(` supply: ${web3.supply},`);
3154
- if (web3.votingThreshold) lines.push(` votingThreshold: ${web3.votingThreshold},`);
3155
- lines.push("};");
3156
- return lines.join("\n");
3157
- }
3158
- function web3ToUnity(web3) {
3159
- const safeName = web3.name.replace(/[^a-zA-Z0-9_]/g, "_");
3160
- const lines = [];
3161
- lines.push(`// Web3: ${web3.name}`);
3162
- lines.push(`public class ${safeName}Web3 : MonoBehaviour {`);
3163
- lines.push(` public string web3Type = "${web3.keyword}";`);
3164
- if (web3.standard) lines.push(` public string standard = "${web3.standard}";`);
3165
- if (web3.network) lines.push(` public string network = "${web3.network}";`);
3166
- if (web3.contractAddress)
3167
- lines.push(` public string contractAddress = "${web3.contractAddress}";`);
3168
- if (web3.supply) lines.push(` public long totalSupply = ${web3.supply};`);
3169
- lines.push("}");
3170
- return lines.join("\n");
3171
- }
3172
- function web3ToGodot(web3) {
3173
- const lines = [];
3174
- lines.push(`# Web3: ${web3.name}`);
3175
- lines.push("extends Node");
3176
- lines.push("");
3177
- lines.push(`@export var web3_type: String = "${web3.keyword}"`);
3178
- if (web3.standard) lines.push(`@export var standard: String = "${web3.standard}"`);
3179
- if (web3.network) lines.push(`@export var network: String = "${web3.network}"`);
3180
- if (web3.contractAddress)
3181
- lines.push(`@export var contract_address: String = "${web3.contractAddress}"`);
3182
- lines.push("");
3183
- lines.push("signal transaction_confirmed(tx_hash: String)");
3184
- lines.push("signal wallet_connected(address: String)");
3185
- return lines.join("\n");
3186
- }
3187
- function web3ToVRChat(web3) {
3188
- const safeName = web3.name.replace(/[^a-zA-Z0-9_]/g, "_");
3189
- const lines = [];
3190
- lines.push(`// Web3: ${web3.name}`);
3191
- lines.push("[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]");
3192
- lines.push(`public class ${safeName}Web3 : UdonSharpBehaviour {`);
3193
- lines.push(` public string web3Type = "${web3.keyword}";`);
3194
- if (web3.standard) lines.push(` public string standard = "${web3.standard}";`);
3195
- if (web3.network) lines.push(` public string network = "${web3.network}";`);
3196
- if (web3.contractAddress) lines.push(` [UdonSynced] public string walletState = "";`);
3197
- lines.push("}");
3198
- return lines.join("\n");
3199
- }
3200
- function web3ToUSDA(web3) {
3201
- const safeName = web3.name.replace(/[^a-zA-Z0-9_]/g, "_");
3202
- const lines = [];
3203
- lines.push(`def Scope "Web3_${safeName}" {`);
3204
- lines.push(` custom string holoscript:web3Type = "${web3.keyword}"`);
3205
- if (web3.standard) lines.push(` custom string holoscript:standard = "${web3.standard}"`);
3206
- if (web3.network) lines.push(` custom string holoscript:network = "${web3.network}"`);
3207
- if (web3.contractAddress)
3208
- lines.push(` custom string holoscript:contractAddress = "${web3.contractAddress}"`);
3209
- lines.push("}");
3210
- return lines.join("\n");
3211
- }
3212
- function compileProceduralBlock(block) {
3213
- const props = block.properties || {};
3214
- let scaleRange;
3215
- if (Array.isArray(props.scale_range) && props.scale_range.length === 2) {
3216
- scaleRange = props.scale_range;
3217
- }
3218
- let noise;
3219
- if (props.noise_type || props.octaves || props.frequency) {
3220
- noise = {
3221
- type: props.noise_type ?? "perlin",
3222
- octaves: props.octaves ?? 4,
3223
- frequency: props.frequency ?? 1,
3224
- amplitude: props.amplitude ?? 1
3225
- };
3226
- } else if (props.noise && typeof props.noise === "object") {
3227
- const n = props.noise;
3228
- noise = {
3229
- type: n.type ?? "perlin",
3230
- octaves: n.octaves ?? 4,
3231
- frequency: n.frequency ?? 1,
3232
- amplitude: n.amplitude ?? 1
3233
- };
3234
- }
3235
- return {
3236
- name: block.name || "unnamed",
3237
- keyword: block.keyword,
3238
- genType: props.gen_type || props.type || block.keyword,
3239
- seed: props.seed,
3240
- density: props.density,
3241
- scaleRange,
3242
- noise,
3243
- sourceMesh: props.source_mesh || props.source || props.mesh,
3244
- traits: block.traits || [],
3245
- properties: props
3246
- };
3247
- }
3248
- function proceduralToR3F(proc) {
3249
- const safeName = proc.name.replace(/[^a-zA-Z0-9_]/g, "_");
3250
- const lines = [];
3251
- lines.push(`// Procedural: ${proc.name} (${proc.keyword})`);
3252
- lines.push(`export const ${safeName}Config = {`);
3253
- lines.push(` name: "${proc.name}",`);
3254
- lines.push(` type: "${proc.keyword}",`);
3255
- if (proc.genType) lines.push(` genType: "${proc.genType}",`);
3256
- if (proc.seed != null) lines.push(` seed: ${proc.seed},`);
3257
- if (proc.density) lines.push(` density: ${proc.density},`);
3258
- if (proc.scaleRange) lines.push(` scaleRange: [${proc.scaleRange.join(", ")}],`);
3259
- if (proc.noise) lines.push(` noise: ${JSON.stringify(proc.noise)},`);
3260
- if (proc.sourceMesh) lines.push(` sourceMesh: "${proc.sourceMesh}",`);
3261
- lines.push("};");
3262
- return lines.join("\n");
3263
- }
3264
- function proceduralToUnity(proc) {
3265
- const safeName = proc.name.replace(/[^a-zA-Z0-9_]/g, "_");
3266
- const lines = [];
3267
- lines.push(`// Procedural: ${proc.name}`);
3268
- lines.push(`public class ${safeName}Procedural : MonoBehaviour {`);
3269
- lines.push(` public string genType = "${proc.keyword}";`);
3270
- if (proc.seed != null) lines.push(` public int seed = ${proc.seed};`);
3271
- if (proc.density) lines.push(` public float density = ${proc.density}f;`);
3272
- if (proc.scaleRange) {
3273
- lines.push(` public float scaleMin = ${proc.scaleRange[0]}f;`);
3274
- lines.push(` public float scaleMax = ${proc.scaleRange[1]}f;`);
3275
- }
3276
- if (proc.noise) {
3277
- lines.push(` public int octaves = ${proc.noise.octaves};`);
3278
- lines.push(` public float frequency = ${proc.noise.frequency}f;`);
3279
- lines.push(` public float amplitude = ${proc.noise.amplitude}f;`);
3280
- }
3281
- if (proc.sourceMesh) lines.push(` public string sourceMesh = "${proc.sourceMesh}";`);
3282
- lines.push("}");
3283
- return lines.join("\n");
3284
- }
3285
- function proceduralToGodot(proc) {
3286
- const lines = [];
3287
- lines.push(`# Procedural: ${proc.name}`);
3288
- lines.push("extends Node3D");
3289
- lines.push("");
3290
- lines.push(`@export var gen_type: String = "${proc.keyword}"`);
3291
- if (proc.seed != null) lines.push(`@export var seed: int = ${proc.seed}`);
3292
- if (proc.density) lines.push(`@export var density: float = ${proc.density}`);
3293
- if (proc.scaleRange) {
3294
- lines.push(`@export var scale_min: float = ${proc.scaleRange[0]}`);
3295
- lines.push(`@export var scale_max: float = ${proc.scaleRange[1]}`);
3296
- }
3297
- if (proc.noise) {
3298
- lines.push(`@export var octaves: int = ${proc.noise.octaves}`);
3299
- lines.push(`@export var frequency: float = ${proc.noise.frequency}`);
3300
- lines.push(`@export var amplitude: float = ${proc.noise.amplitude}`);
3301
- }
3302
- lines.push("");
3303
- lines.push("signal generation_complete(instance_count: int)");
3304
- return lines.join("\n");
3305
- }
3306
- function proceduralToVRChat(proc) {
3307
- const safeName = proc.name.replace(/[^a-zA-Z0-9_]/g, "_");
3308
- const lines = [];
3309
- lines.push(`// Procedural: ${proc.name}`);
3310
- lines.push("[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]");
3311
- lines.push(`public class ${safeName}Procedural : UdonSharpBehaviour {`);
3312
- lines.push(` public string genType = "${proc.keyword}";`);
3313
- if (proc.seed != null) lines.push(` [UdonSynced] public int seed = ${proc.seed};`);
3314
- if (proc.density) lines.push(` public float density = ${proc.density}f;`);
3315
- lines.push("}");
3316
- return lines.join("\n");
3317
- }
3318
- function proceduralToUSDA(proc) {
3319
- const safeName = proc.name.replace(/[^a-zA-Z0-9_]/g, "_");
3320
- const lines = [];
3321
- lines.push(`def Scope "Procedural_${safeName}" {`);
3322
- lines.push(` custom string holoscript:genType = "${proc.keyword}"`);
3323
- if (proc.seed != null) lines.push(` custom int holoscript:seed = ${proc.seed}`);
3324
- if (proc.density) lines.push(` custom float holoscript:density = ${proc.density}`);
3325
- if (proc.sourceMesh) lines.push(` custom string holoscript:sourceMesh = "${proc.sourceMesh}"`);
3326
- lines.push("}");
3327
- return lines.join("\n");
3328
- }
3329
- function compileRenderingBlock(block) {
3330
- const props = block.properties || {};
3331
- let lodLevels;
3332
- if (Array.isArray(props.levels)) {
3333
- lodLevels = props.levels.map(
3334
- (l) => typeof l === "object" && l !== null ? l : { distance: l }
3335
- );
3336
- }
3337
- for (const child of block.children || []) {
3338
- const c = child;
3339
- if (c.keyword === "level" || c.keyword === "lod_level") {
3340
- if (!lodLevels) lodLevels = [];
3341
- lodLevels.push({
3342
- distance: c.properties?.distance ?? 0,
3343
- mesh: c.name || void 0,
3344
- detail: c.properties?.detail
3345
- });
3346
- }
3347
- }
3348
- return {
3349
- name: block.name || "unnamed",
3350
- keyword: block.keyword,
3351
- lodLevels,
3352
- renderLayer: props.render_layer || props.layer,
3353
- shadowMode: props.shadow_mode || props.shadow,
3354
- cullingMode: props.culling_mode || props.culling,
3355
- sortOrder: props.sort_order,
3356
- traits: block.traits || [],
3357
- properties: props
3358
- };
3359
- }
3360
- function renderingToR3F(rendering) {
3361
- const safeName = rendering.name.replace(/[^a-zA-Z0-9_]/g, "_");
3362
- const lines = [];
3363
- lines.push(`// Rendering: ${rendering.name} (${rendering.keyword})`);
3364
- lines.push(`export const ${safeName}Config = {`);
3365
- lines.push(` name: "${rendering.name}",`);
3366
- lines.push(` type: "${rendering.keyword}",`);
3367
- if (rendering.lodLevels) lines.push(` lodLevels: ${JSON.stringify(rendering.lodLevels)},`);
3368
- if (rendering.renderLayer) lines.push(` renderLayer: "${rendering.renderLayer}",`);
3369
- if (rendering.shadowMode) lines.push(` shadowMode: "${rendering.shadowMode}",`);
3370
- if (rendering.cullingMode) lines.push(` cullingMode: "${rendering.cullingMode}",`);
3371
- if (rendering.sortOrder != null) lines.push(` sortOrder: ${rendering.sortOrder},`);
3372
- lines.push("};");
3373
- return lines.join("\n");
3374
- }
3375
- function renderingToUnity(rendering) {
3376
- const safeName = rendering.name.replace(/[^a-zA-Z0-9_]/g, "_");
3377
- const lines = [];
3378
- lines.push(`// Rendering: ${rendering.name}`);
3379
- lines.push(`public class ${safeName}Rendering : MonoBehaviour {`);
3380
- lines.push(` public string renderType = "${rendering.keyword}";`);
3381
- if (rendering.lodLevels) {
3382
- lines.push(" void Start() {");
3383
- lines.push(" var lodGroup = gameObject.AddComponent<LODGroup>();");
3384
- lines.push(` var lods = new LOD[${rendering.lodLevels.length}];`);
3385
- rendering.lodLevels.forEach((l, i) => {
3386
- const screenHeight = 1 / (1 + l.distance * 0.01);
3387
- lines.push(
3388
- ` lods[${i}] = new LOD(${screenHeight.toFixed(3)}f, GetComponentsInChildren<Renderer>());`
3389
- );
3390
- });
3391
- lines.push(" lodGroup.SetLODs(lods);");
3392
- lines.push(" }");
3393
- }
3394
- if (rendering.shadowMode) {
3395
- const mode = rendering.shadowMode === "none" ? "Off" : rendering.shadowMode === "cast" ? "On" : "TwoSided";
3396
- lines.push(` public ShadowCastingMode shadowMode = ShadowCastingMode.${mode};`);
3397
- }
3398
- lines.push("}");
3399
- return lines.join("\n");
3400
- }
3401
- function renderingToGodot(rendering) {
3402
- const lines = [];
3403
- lines.push(`# Rendering: ${rendering.name}`);
3404
- lines.push("extends Node3D");
3405
- lines.push("");
3406
- lines.push(`@export var render_type: String = "${rendering.keyword}"`);
3407
- if (rendering.shadowMode)
3408
- lines.push(`@export var shadow_mode: String = "${rendering.shadowMode}"`);
3409
- if (rendering.cullingMode)
3410
- lines.push(`@export var culling_mode: String = "${rendering.cullingMode}"`);
3411
- if (rendering.sortOrder != null)
3412
- lines.push(`@export var sort_order: int = ${rendering.sortOrder}`);
3413
- if (rendering.lodLevels) {
3414
- lines.push("");
3415
- for (let i = 0; i < rendering.lodLevels.length; i++) {
3416
- const l = rendering.lodLevels[i];
3417
- lines.push(`@export var lod${i}_distance: float = ${l.distance}`);
3418
- }
3419
- }
3420
- return lines.join("\n");
3421
- }
3422
- function renderingToVRChat(rendering) {
3423
- const safeName = rendering.name.replace(/[^a-zA-Z0-9_]/g, "_");
3424
- const lines = [];
3425
- lines.push(`// Rendering: ${rendering.name}`);
3426
- lines.push(`public class ${safeName}Rendering : UdonSharpBehaviour {`);
3427
- lines.push(` public string renderType = "${rendering.keyword}";`);
3428
- if (rendering.lodLevels) lines.push(` public int lodLevels = ${rendering.lodLevels.length};`);
3429
- if (rendering.shadowMode) lines.push(` public string shadowMode = "${rendering.shadowMode}";`);
3430
- lines.push("}");
3431
- return lines.join("\n");
3432
- }
3433
- function renderingToUSDA(rendering) {
3434
- const safeName = rendering.name.replace(/[^a-zA-Z0-9_]/g, "_");
3435
- const lines = [];
3436
- lines.push(`def Scope "Rendering_${safeName}" {`);
3437
- lines.push(` custom string holoscript:renderType = "${rendering.keyword}"`);
3438
- if (rendering.shadowMode)
3439
- lines.push(` custom string holoscript:shadowMode = "${rendering.shadowMode}"`);
3440
- if (rendering.cullingMode)
3441
- lines.push(` custom string holoscript:cullingMode = "${rendering.cullingMode}"`);
3442
- if (rendering.lodLevels)
3443
- lines.push(` custom int holoscript:lodLevels = ${rendering.lodLevels.length}`);
3444
- lines.push("}");
3445
- return lines.join("\n");
3446
- }
3447
- function compileNavigationBlock(block) {
3448
- const props = block.properties || {};
3449
- return {
3450
- name: block.name || "unnamed",
3451
- keyword: block.keyword,
3452
- agentRadius: props.agent_radius || props.radius,
3453
- agentHeight: props.agent_height || props.height,
3454
- maxSlope: props.max_slope || props.slope,
3455
- stepHeight: props.step_height || props.step,
3456
- speed: props.speed,
3457
- avoidancePriority: props.avoidance_priority || props.priority,
3458
- behaviorRoot: props.behavior_root || props.root_node,
3459
- traits: block.traits || [],
3460
- properties: props
3461
- };
3462
- }
3463
- function navigationToR3F(nav) {
3464
- const safeName = nav.name.replace(/[^a-zA-Z0-9_]/g, "_");
3465
- const lines = [];
3466
- lines.push(`// Navigation: ${nav.name} (${nav.keyword})`);
3467
- lines.push(`export const ${safeName}Config = {`);
3468
- lines.push(` name: "${nav.name}",`);
3469
- lines.push(` type: "${nav.keyword}",`);
3470
- if (nav.agentRadius) lines.push(` agentRadius: ${nav.agentRadius},`);
3471
- if (nav.agentHeight) lines.push(` agentHeight: ${nav.agentHeight},`);
3472
- if (nav.maxSlope) lines.push(` maxSlope: ${nav.maxSlope},`);
3473
- if (nav.stepHeight) lines.push(` stepHeight: ${nav.stepHeight},`);
3474
- if (nav.speed) lines.push(` speed: ${nav.speed},`);
3475
- if (nav.avoidancePriority != null) lines.push(` avoidancePriority: ${nav.avoidancePriority},`);
3476
- if (nav.behaviorRoot) lines.push(` behaviorRoot: "${nav.behaviorRoot}",`);
3477
- lines.push("};");
3478
- return lines.join("\n");
3479
- }
3480
- function navigationToUnity(nav) {
3481
- const safeName = nav.name.replace(/[^a-zA-Z0-9_]/g, "_");
3482
- const lines = [];
3483
- lines.push(`// Navigation: ${nav.name}`);
3484
- lines.push(`public class ${safeName}Navigation : MonoBehaviour {`);
3485
- lines.push(` public string navType = "${nav.keyword}";`);
3486
- lines.push(" void Start() {");
3487
- if (nav.keyword === "navmesh" || nav.keyword === "nav_mesh") {
3488
- lines.push(" var surface = gameObject.AddComponent<NavMeshSurface>();");
3489
- if (nav.agentRadius) lines.push(` // Agent radius: ${nav.agentRadius}`);
3490
- if (nav.maxSlope) lines.push(` // Max slope: ${nav.maxSlope} degrees`);
3491
- } else {
3492
- lines.push(" var agent = gameObject.AddComponent<NavMeshAgent>();");
3493
- if (nav.speed) lines.push(` agent.speed = ${nav.speed}f;`);
3494
- if (nav.agentRadius) lines.push(` agent.radius = ${nav.agentRadius}f;`);
3495
- if (nav.agentHeight) lines.push(` agent.height = ${nav.agentHeight}f;`);
3496
- if (nav.stepHeight) lines.push(` agent.baseOffset = ${nav.stepHeight}f;`);
3497
- if (nav.avoidancePriority != null)
3498
- lines.push(` agent.avoidancePriority = ${nav.avoidancePriority};`);
3499
- }
3500
- lines.push(" }");
3501
- lines.push("}");
3502
- return lines.join("\n");
3503
- }
3504
- function navigationToGodot(nav) {
3505
- const lines = [];
3506
- lines.push(`# Navigation: ${nav.name}`);
3507
- if (nav.keyword === "navmesh" || nav.keyword === "nav_mesh") {
3508
- lines.push("extends NavigationRegion3D");
3509
- lines.push("");
3510
- if (nav.agentRadius) lines.push(`@export var agent_radius: float = ${nav.agentRadius}`);
3511
- if (nav.maxSlope) lines.push(`@export var max_slope: float = ${nav.maxSlope}`);
3512
- } else {
3513
- lines.push("extends NavigationAgent3D");
3514
- lines.push("");
3515
- if (nav.speed) lines.push(`@export var speed: float = ${nav.speed}`);
3516
- if (nav.agentRadius) lines.push(`@export var agent_radius: float = ${nav.agentRadius}`);
3517
- if (nav.agentHeight) lines.push(`@export var agent_height: float = ${nav.agentHeight}`);
3518
- if (nav.avoidancePriority != null)
3519
- lines.push(`@export var avoidance_priority: int = ${nav.avoidancePriority}`);
3520
- }
3521
- lines.push("");
3522
- lines.push("signal navigation_finished");
3523
- lines.push("signal path_changed(new_path: PackedVector3Array)");
3524
- return lines.join("\n");
3525
- }
3526
- function navigationToVRChat(nav) {
3527
- const safeName = nav.name.replace(/[^a-zA-Z0-9_]/g, "_");
3528
- const lines = [];
3529
- lines.push(`// Navigation: ${nav.name}`);
3530
- lines.push("[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]");
3531
- lines.push(`public class ${safeName}Navigation : UdonSharpBehaviour {`);
3532
- lines.push(` public string navType = "${nav.keyword}";`);
3533
- if (nav.speed) lines.push(` public float speed = ${nav.speed}f;`);
3534
- if (nav.agentRadius) lines.push(` public float agentRadius = ${nav.agentRadius}f;`);
3535
- lines.push("}");
3536
- return lines.join("\n");
3537
- }
3538
- function navigationToUSDA(nav) {
3539
- const safeName = nav.name.replace(/[^a-zA-Z0-9_]/g, "_");
3540
- const lines = [];
3541
- lines.push(`def Scope "Navigation_${safeName}" {`);
3542
- lines.push(` custom string holoscript:navType = "${nav.keyword}"`);
3543
- if (nav.agentRadius) lines.push(` custom float holoscript:agentRadius = ${nav.agentRadius}`);
3544
- if (nav.agentHeight) lines.push(` custom float holoscript:agentHeight = ${nav.agentHeight}`);
3545
- if (nav.speed) lines.push(` custom float holoscript:speed = ${nav.speed}`);
3546
- if (nav.maxSlope) lines.push(` custom float holoscript:maxSlope = ${nav.maxSlope}`);
3547
- lines.push("}");
3548
- return lines.join("\n");
3549
- }
3550
- function compileInputBlock(block) {
3551
- const props = block.properties || {};
3552
- return {
3553
- name: block.name || "unnamed",
3554
- keyword: block.keyword,
3555
- inputType: props.input_type || props.type || block.keyword,
3556
- platform: props.platform,
3557
- binding: props.binding || props.key || props.button,
3558
- action: props.action,
3559
- threshold: props.threshold,
3560
- interactionDistance: props.interaction_distance || props.distance,
3561
- traits: block.traits || [],
3562
- properties: props
3563
- };
3564
- }
3565
- function inputToR3F(input) {
3566
- const safeName = input.name.replace(/[^a-zA-Z0-9_]/g, "_");
3567
- const lines = [];
3568
- lines.push(`// Input: ${input.name} (${input.keyword})`);
3569
- lines.push(`export const ${safeName}Config = {`);
3570
- lines.push(` name: "${input.name}",`);
3571
- lines.push(` type: "${input.keyword}",`);
3572
- if (input.inputType) lines.push(` inputType: "${input.inputType}",`);
3573
- if (input.platform) lines.push(` platform: "${input.platform}",`);
3574
- if (input.binding) lines.push(` binding: "${input.binding}",`);
3575
- if (input.action) lines.push(` action: "${input.action}",`);
3576
- if (input.threshold) lines.push(` threshold: ${input.threshold},`);
3577
- if (input.interactionDistance) lines.push(` interactionDistance: ${input.interactionDistance},`);
3578
- lines.push("};");
3579
- return lines.join("\n");
3580
- }
3581
- function inputToUnity(input) {
3582
- const safeName = input.name.replace(/[^a-zA-Z0-9_]/g, "_");
3583
- const lines = [];
3584
- lines.push(`// Input: ${input.name}`);
3585
- lines.push(`public class ${safeName}Input : MonoBehaviour {`);
3586
- lines.push(` public string inputType = "${input.keyword}";`);
3587
- if (input.binding) lines.push(` public string binding = "${input.binding}";`);
3588
- if (input.action) lines.push(` public string action = "${input.action}";`);
3589
- if (input.threshold) lines.push(` public float threshold = ${input.threshold}f;`);
3590
- if (input.interactionDistance)
3591
- lines.push(` public float interactionDistance = ${input.interactionDistance}f;`);
3592
- if (input.platform === "vr_controller") {
3593
- lines.push(" void Update() {");
3594
- lines.push(" // XR input polling");
3595
- lines.push(" var device = InputDevices.GetDeviceAtXRNode(XRNode.RightHand);");
3596
- lines.push(` device.TryGetFeatureValue(CommonUsages.trigger, out float triggerValue);`);
3597
- lines.push(" }");
3598
- }
3599
- lines.push("}");
3600
- return lines.join("\n");
3601
- }
3602
- function inputToGodot(input) {
3603
- const lines = [];
3604
- lines.push(`# Input: ${input.name}`);
3605
- lines.push("extends Node");
3606
- lines.push("");
3607
- lines.push(`@export var input_type: String = "${input.keyword}"`);
3608
- if (input.binding) lines.push(`@export var binding: String = "${input.binding}"`);
3609
- if (input.action) lines.push(`@export var action_name: String = "${input.action}"`);
3610
- if (input.threshold) lines.push(`@export var threshold: float = ${input.threshold}`);
3611
- if (input.interactionDistance)
3612
- lines.push(`@export var interaction_distance: float = ${input.interactionDistance}`);
3613
- lines.push("");
3614
- lines.push("signal action_triggered(action: String, value: float)");
3615
- lines.push("signal gesture_recognized(gesture: String)");
3616
- return lines.join("\n");
3617
- }
3618
- function inputToVRChat(input) {
3619
- const safeName = input.name.replace(/[^a-zA-Z0-9_]/g, "_");
3620
- const lines = [];
3621
- lines.push(`// Input: ${input.name}`);
3622
- lines.push(`public class ${safeName}Input : UdonSharpBehaviour {`);
3623
- lines.push(` public string inputType = "${input.keyword}";`);
3624
- if (input.action) lines.push(` public string action = "${input.action}";`);
3625
- if (input.interactionDistance)
3626
- lines.push(` public float interactionDistance = ${input.interactionDistance}f;`);
3627
- if (input.keyword === "interaction" || input.keyword === "gesture_profile") {
3628
- lines.push(" public override void Interact() {");
3629
- lines.push(" // Handle VRChat interaction");
3630
- lines.push(" }");
3631
- }
3632
- lines.push("}");
3633
- return lines.join("\n");
3634
- }
3635
- function inputToUSDA(input) {
3636
- const safeName = input.name.replace(/[^a-zA-Z0-9_]/g, "_");
3637
- const lines = [];
3638
- lines.push(`def Scope "Input_${safeName}" {`);
3639
- lines.push(` custom string holoscript:inputType = "${input.keyword}"`);
3640
- if (input.binding) lines.push(` custom string holoscript:binding = "${input.binding}"`);
3641
- if (input.action) lines.push(` custom string holoscript:action = "${input.action}"`);
3642
- if (input.interactionDistance)
3643
- lines.push(` custom float holoscript:interactionDistance = ${input.interactionDistance}`);
3644
- lines.push("}");
3645
- return lines.join("\n");
3646
- }
3647
- function compileSimulationBlock(block) {
3648
- const traits = block.traits || [];
3649
- let simulationType = "unknown";
3650
- if (traits.includes("thermal_simulation")) simulationType = "thermal";
3651
- else if (traits.includes("structural_fem")) simulationType = "structural";
3652
- else if (traits.includes("hydraulic_pipe")) simulationType = "hydraulic";
3653
- const overlays = [];
3654
- for (const child of block.children || []) {
3655
- const c = child;
3656
- if (c.traits?.includes("scalar_field_overlay") || c.keyword === "scalar_field_overlay") {
3657
- const p = c.properties || {};
3658
- overlays.push({
3659
- source: p.source ?? "",
3660
- colormap: p.colormap ?? "turbo",
3661
- range: p.range ?? [0, 1],
3662
- opacity: p.opacity ?? 0.7,
3663
- visible: p.visible ?? true,
3664
- label: p.label ?? ""
3665
- });
3666
- }
3667
- }
3668
- return {
3669
- keyword: block.keyword,
3670
- name: block.name,
3671
- simulationType,
3672
- traits,
3673
- config: block.properties || {},
3674
- overlays
3675
- };
3676
- }
3677
- function simulationToR3F(sim) {
3678
- const configJSON = JSON.stringify(sim.config).replace(/"/g, "'").replace(/'/g, '"');
3679
- const overlayJSX = sim.overlays.map(
3680
- (o) => `<ScalarFieldOverlay colormap="${o.colormap}" range={[${o.range.join(", ")}]} opacity={${o.opacity}} visible={${o.visible}} label="${o.label}" />`
3681
- ).join("\n ");
3682
- return `{/* Simulation: ${sim.name} (${sim.simulationType}) */}
3683
- <SimulationProvider type="${sim.simulationType}" config={${configJSON}}>
3684
- ${overlayJSX}
3685
- </SimulationProvider>`;
3686
- }
3687
- function compileDomainBlocks(blocks, handlers, fallback) {
3688
- return blocks.map((block) => {
3689
- const handler = handlers[block.domain];
3690
- if (handler) return handler(block);
3691
- if (fallback) return fallback(block);
3692
- return `/* Unhandled domain block: ${block.domain}/${block.keyword} "${block.name}" */`;
3693
- });
3694
- }
3695
- function hexToRGB(hex) {
3696
- const h = hex.replace("#", "");
3697
- const r = parseInt(h.substring(0, 2), 16) / 255;
3698
- const g = parseInt(h.substring(2, 4), 16) / 255;
3699
- const b = parseInt(h.substring(4, 6), 16) / 255;
3700
- return `${r.toFixed(3)}, ${g.toFixed(3)}, ${b.toFixed(3)}`;
3701
- }
3702
- function hexToRGBA(hex, alpha) {
3703
- const h = hex.replace("#", "");
3704
- return [
3705
- parseInt(h.substring(0, 2), 16) / 255,
3706
- parseInt(h.substring(2, 4), 16) / 255,
3707
- parseInt(h.substring(4, 6), 16) / 255,
3708
- alpha
3709
- ];
3710
- }
3711
- function getRequiredCapability() {
3712
- return ANSCapabilityPath.DOMAIN_BLOCK;
3713
- }
3714
- var DOMAIN_BLOCK_COMPILER_MIXIN_CAPABILITY;
3715
- var init_DomainBlockCompilerMixin = __esm({
3716
- "src/compiler/DomainBlockCompilerMixin.ts"() {
3717
- init_CompilerBase();
3718
- init_ANSNamespace();
3719
- DOMAIN_BLOCK_COMPILER_MIXIN_CAPABILITY = "/compile/mixin/domain-block";
3720
- }
3721
- });
3722
-
3723
- export { DOMAIN_BLOCK_COMPILER_MIXIN_CAPABILITY, architectureToGodot, architectureToR3F, architectureToUSDA, architectureToUnity, architectureToVRChat, audioSourceToAndroidXR, audioSourceToBabylon, audioSourceToGodot, audioSourceToPlayCanvas, audioSourceToR3F, audioSourceToUSD, audioSourceToUnity, audioSourceToUnreal, audioSourceToVisionOS, compileArchitectureBlock, compileAudioSourceBlock, compileDataVizBlock, compileDomainBlocks, compileEducationBlock, compileHealthcareBlock, compileInputBlock, compileIoTBlock, compileMaterialBlock, compileMusicBlock, compileNarrativeBlock, compileNavigationBlock, compileParticleBlock, compilePaymentBlock, compilePhysicsBlock, compilePostProcessingBlock, compileProceduralBlock, compileRenderingBlock, compileRoboticsBlock, compileSimulationBlock, compileWeatherBlock, compileWeb3Block, datavizToGodot, datavizToR3F, datavizToUSDA, datavizToUnity, datavizToVRChat, educationToGodot, educationToR3F, educationToUSDA, educationToUnity, educationToVRChat, getRequiredCapability, healthcareToGodot, healthcareToR3F, healthcareToUSDA, healthcareToUnity, healthcareToVRChat, init_DomainBlockCompilerMixin, inputToGodot, inputToR3F, inputToUSDA, inputToUnity, inputToVRChat, iotToGodot, iotToR3F, iotToUSDA, iotToUnity, iotToVRChat, materialToAndroidXR, materialToBabylon, materialToGLTF, materialToGodot, materialToPlayCanvas, materialToR3F, materialToSDF, materialToUSD, materialToUnity, materialToUnreal, materialToVRChat, materialToVisionOS, materialToWebGPU, musicToGodot, musicToR3F, musicToUSDA, musicToUnity, musicToVRChat, narrativeToGodot, narrativeToR3F, narrativeToUSDA, narrativeToUnity, narrativeToVRChat, navigationToGodot, navigationToR3F, navigationToUSDA, navigationToUnity, navigationToVRChat, particlesToAndroidXR, particlesToBabylon, particlesToGodot, particlesToPlayCanvas, particlesToR3F, particlesToUSD, particlesToUnity, particlesToUnreal, particlesToVisionOS, paymentToGodot, paymentToR3F, paymentToUSDA, paymentToUnity, paymentToVRChat, physicsToAndroidXR, physicsToBabylon, physicsToGodot, physicsToPlayCanvas, physicsToR3F, physicsToSDF, physicsToURDF, physicsToUnity, physicsToUnreal, physicsToVisionOS, postProcessingToBabylon, postProcessingToGodot, postProcessingToR3F, postProcessingToUSD, postProcessingToUnity, postProcessingToUnreal, proceduralToGodot, proceduralToR3F, proceduralToUSDA, proceduralToUnity, proceduralToVRChat, renderingToGodot, renderingToR3F, renderingToUSDA, renderingToUnity, renderingToVRChat, roboticsToGodot, roboticsToR3F, roboticsToUSDA, roboticsToUnity, roboticsToVRChat, simulationToR3F, weatherToAndroidXR, weatherToGodot, weatherToR3F, weatherToUSD, weatherToUnity, weatherToUnreal, web3ToGodot, web3ToR3F, web3ToUSDA, web3ToUnity, web3ToVRChat };
3724
- //# sourceMappingURL=chunk-YQK5JNFK.js.map
3725
- //# sourceMappingURL=chunk-YQK5JNFK.js.map