@holoscript/core 7.0.0 → 8.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 (345) hide show
  1. package/README.md +2 -2
  2. package/bin/holoscript.cjs +3 -0
  3. package/dist/GLTFPipeline-276GE64O.js +16 -0
  4. package/dist/GLTFPipeline-M7WSSJED.cjs +37 -0
  5. package/dist/HoloScriptPlusParser-7FBIFUFC.js +693 -0
  6. package/dist/HoloScriptPlusParser-A2W7OCN2.cjs +698 -0
  7. package/dist/HoloScriptPlusParser-F2Z56FJR.js +10 -0
  8. package/dist/HoloScriptPlusParser-WKHRIH6T.cjs +27 -0
  9. package/dist/HoloScriptRuntime-3URVTKPJ.js +10 -0
  10. package/dist/HoloScriptRuntime-SXEAEU2N.cjs +19 -0
  11. package/dist/USDZExporter-3FWJ25JI.cjs +1037 -0
  12. package/dist/USDZExporter-D2HQLQYK.js +1035 -0
  13. package/dist/agents/index.cjs +19 -0
  14. package/dist/agents/index.d.ts +100 -0
  15. package/dist/agents/index.js +17 -0
  16. package/dist/chunk-23J755AR.js +1046 -0
  17. package/dist/chunk-253GBQZY.cjs +627 -0
  18. package/dist/chunk-25IQCHTO.cjs +781 -0
  19. package/dist/chunk-2BSMSUCE.js +1941 -0
  20. package/dist/chunk-2M2DPHKB.js +762 -0
  21. package/dist/chunk-2YSNA2F2.cjs +1274 -0
  22. package/dist/chunk-3AO425MZ.cjs +886 -0
  23. package/dist/chunk-3FOKASKO.cjs +348 -0
  24. package/dist/chunk-3HYYMEXI.cjs +56578 -0
  25. package/dist/chunk-3NFFOWGG.js +4287 -0
  26. package/dist/chunk-3WZEJHUQ.cjs +116 -0
  27. package/dist/chunk-4C57PR42.js +468 -0
  28. package/dist/chunk-4N4SXXWF.js +769 -0
  29. package/dist/chunk-4PDEPEQW.cjs +41 -0
  30. package/dist/chunk-4R6SBXDB.js +45 -0
  31. package/dist/chunk-4V2E7U7Q.cjs +2015 -0
  32. package/dist/chunk-5FSKKMR7.cjs +2092 -0
  33. package/dist/chunk-5GLCTO44.js +161 -0
  34. package/dist/chunk-5JEU52DW.js +382 -0
  35. package/dist/chunk-5S7RKFGR.cjs +446 -0
  36. package/dist/chunk-5WUNN6ZN.cjs +428 -0
  37. package/dist/chunk-62FBK3B7.js +70 -0
  38. package/dist/chunk-6CTRH7HT.cjs +1985 -0
  39. package/dist/chunk-6DPSFNJB.cjs +847 -0
  40. package/dist/chunk-6EX3I5P4.cjs +130 -0
  41. package/dist/chunk-73FELZVJ.cjs +611 -0
  42. package/dist/chunk-7CUEMLDZ.cjs +6445 -0
  43. package/dist/chunk-7HIASF7S.cjs +814 -0
  44. package/dist/chunk-A6KINLZJ.js +236 -0
  45. package/dist/chunk-AIA52I7T.cjs +543 -0
  46. package/dist/chunk-ANXZFVY2.js +113 -0
  47. package/dist/chunk-AYBXB26F.js +2176 -0
  48. package/dist/chunk-B4TFTDG4.js +449 -0
  49. package/dist/chunk-BE4UJCQT.js +623 -0
  50. package/dist/chunk-BRQJKJGT.cjs +20 -0
  51. package/dist/chunk-C2A5DUMF.cjs +689 -0
  52. package/dist/chunk-C37BHB7N.cjs +636 -0
  53. package/dist/chunk-CBJY23VL.js +126 -0
  54. package/dist/chunk-CIWWXYHZ.cjs +50 -0
  55. package/dist/chunk-CXFDRBQU.cjs +672 -0
  56. package/dist/chunk-D54CNIAJ.cjs +413 -0
  57. package/dist/chunk-DAJXW4KX.js +725 -0
  58. package/dist/chunk-DTGBOSEM.cjs +319 -0
  59. package/dist/chunk-E7JP3BS3.cjs +61 -0
  60. package/dist/chunk-EKBKLK7P.js +1169 -0
  61. package/dist/chunk-EKYL4PE3.cjs +404 -0
  62. package/dist/chunk-EUDQTK7N.cjs +4310 -0
  63. package/dist/chunk-EXKSFGSX.cjs +274 -0
  64. package/dist/chunk-EXUP2BUM.cjs +1173 -0
  65. package/dist/chunk-F43YAA34.js +623 -0
  66. package/dist/chunk-FDSGHPAK.js +130 -0
  67. package/dist/chunk-FEWUHQNM.cjs +144 -0
  68. package/dist/chunk-FGGJQRLZ.js +270 -0
  69. package/dist/chunk-FHP6LXJS.js +415 -0
  70. package/dist/chunk-FJPADH77.cjs +666 -0
  71. package/dist/chunk-FYSPZT4V.cjs +169 -0
  72. package/dist/chunk-GIOYPNTH.js +5575 -0
  73. package/dist/chunk-GJNCFRJU.cjs +125 -0
  74. package/dist/chunk-GMP623FG.cjs +1508 -0
  75. package/dist/chunk-GQHQOPXZ.cjs +5580 -0
  76. package/dist/chunk-GQT4TYKY.cjs +4381 -0
  77. package/dist/chunk-GTU2Z2WW.cjs +262 -0
  78. package/dist/chunk-GYZE55MO.js +2007 -0
  79. package/dist/chunk-GZG4KA4E.js +529 -0
  80. package/dist/chunk-H652NHX5.js +600 -0
  81. package/dist/chunk-HCCQLAA4.cjs +74 -0
  82. package/dist/chunk-HINXWAOD.cjs +1049 -0
  83. package/dist/chunk-HYNTS5CP.js +422 -0
  84. package/dist/chunk-HZSPDCXV.cjs +457 -0
  85. package/dist/chunk-HZTDET3N.js +1399 -0
  86. package/dist/chunk-I6XZ5DZF.cjs +488 -0
  87. package/dist/chunk-ILRBGFVD.cjs +72 -0
  88. package/dist/chunk-IPWSXCCN.js +1183 -0
  89. package/dist/chunk-IUTY5WQ2.cjs +424 -0
  90. package/dist/chunk-IVSZDECV.js +882 -0
  91. package/dist/chunk-IVY74O6C.js +247 -0
  92. package/dist/chunk-IZM5VQZD.js +714 -0
  93. package/dist/chunk-J32ZJZJH.js +554 -0
  94. package/dist/chunk-J6M4FPK5.js +421 -0
  95. package/dist/chunk-JC5YBPSF.cjs +984 -0
  96. package/dist/chunk-JCLBKPMX.js +3813 -0
  97. package/dist/chunk-JD7CIZ33.js +1949 -0
  98. package/dist/chunk-JIYN45TV.cjs +2525 -0
  99. package/dist/chunk-JJBE3TIH.cjs +1189 -0
  100. package/dist/chunk-JX7YL6ZE.js +2252 -0
  101. package/dist/chunk-K4VVR7CN.cjs +2433 -0
  102. package/dist/chunk-KEFNV2WM.cjs +2257 -0
  103. package/dist/chunk-KH4CNH66.cjs +424 -0
  104. package/dist/chunk-KJLB4OPV.js +5731 -0
  105. package/dist/chunk-KKFZ3B6J.cjs +557 -0
  106. package/dist/chunk-KKP7JKN4.cjs +6002 -0
  107. package/dist/chunk-KPJL34Y7.cjs +186 -0
  108. package/dist/chunk-KQCN6AKJ.cjs +3042 -0
  109. package/dist/chunk-KVRSTFNH.cjs +72 -0
  110. package/dist/chunk-LICPB5HZ.cjs +1409 -0
  111. package/dist/chunk-LM2VU56C.cjs +37 -0
  112. package/dist/chunk-M56JSP4A.js +400 -0
  113. package/dist/chunk-MBOOR7X4.js +18 -0
  114. package/dist/chunk-MGE5Z4GS.js +608 -0
  115. package/dist/chunk-MXFUTKCO.js +56 -0
  116. package/dist/chunk-MYY4PMWX.cjs +264 -0
  117. package/dist/chunk-N75IH2HY.js +258 -0
  118. package/dist/chunk-NBMHU6SW.js +669 -0
  119. package/dist/chunk-NG77ATEW.cjs +778 -0
  120. package/dist/chunk-NGKREZ36.js +6384 -0
  121. package/dist/chunk-NHWSN2SD.cjs +718 -0
  122. package/dist/chunk-NV4VMVXU.js +421 -0
  123. package/dist/chunk-NW5G5FBQ.js +215 -0
  124. package/dist/chunk-NXZFOPVD.cjs +5737 -0
  125. package/dist/chunk-OBIYPYYS.cjs +1993 -0
  126. package/dist/chunk-OIQYIIO3.cjs +473 -0
  127. package/dist/chunk-OL46QLBJ.js +61 -0
  128. package/dist/chunk-OMXII44L.js +5386 -0
  129. package/dist/chunk-OR4Q2BGL.cjs +759 -0
  130. package/dist/chunk-OSYNRVOV.cjs +243 -0
  131. package/dist/chunk-PGANYCAG.cjs +220 -0
  132. package/dist/chunk-PHENW4MQ.js +65 -0
  133. package/dist/chunk-PHVRG4I2.js +844 -0
  134. package/dist/chunk-Q56TT7IL.js +483 -0
  135. package/dist/chunk-QPOQ7VPI.js +1491 -0
  136. package/dist/chunk-QPSKHBJP.js +5963 -0
  137. package/dist/chunk-QXH7QDSZ.js +1989 -0
  138. package/dist/chunk-R75BSDH7.cjs +50 -0
  139. package/dist/chunk-RARB3MBR.js +207 -0
  140. package/dist/chunk-RVBHAXFG.js +56160 -0
  141. package/dist/chunk-S3MDHNKB.cjs +490 -0
  142. package/dist/chunk-S4W6Z2MN.js +2426 -0
  143. package/dist/chunk-S6YWHCKV.cjs +410 -0
  144. package/dist/chunk-SIEXCILW.js +229 -0
  145. package/dist/chunk-SJBGLS25.cjs +2196 -0
  146. package/dist/chunk-SLU6UPJI.cjs +410 -0
  147. package/dist/chunk-SMIWS6DE.cjs +212 -0
  148. package/dist/chunk-T2QCTZMO.js +811 -0
  149. package/dist/chunk-T5J7ZKP3.cjs +4885 -0
  150. package/dist/chunk-TDCNJHWO.js +341 -0
  151. package/dist/chunk-TG7O4WBC.js +406 -0
  152. package/dist/chunk-THCK6ECW.js +2085 -0
  153. package/dist/chunk-TJHVSBP2.js +439 -0
  154. package/dist/chunk-TVHSPJ4N.cjs +606 -0
  155. package/dist/chunk-U44IKGG7.cjs +5390 -0
  156. package/dist/chunk-UJXISJBN.js +487 -0
  157. package/dist/chunk-UM6C3CGK.js +4375 -0
  158. package/dist/chunk-UMABK6SI.js +686 -0
  159. package/dist/chunk-UOIGFQXC.cjs +9750 -0
  160. package/dist/chunk-URG2SJLK.js +2521 -0
  161. package/dist/chunk-V6MKC2FZ.js +979 -0
  162. package/dist/chunk-VECQYRXL.js +474 -0
  163. package/dist/chunk-VJ3L7CHT.cjs +169 -0
  164. package/dist/chunk-VMLKSV26.js +1216 -0
  165. package/dist/chunk-VVKVQZI6.js +55 -0
  166. package/dist/chunk-W6RW64BB.cjs +1219 -0
  167. package/dist/chunk-W7VDOASB.cjs +639 -0
  168. package/dist/chunk-WDT3JTGM.cjs +483 -0
  169. package/dist/chunk-WJIHFLMJ.js +404 -0
  170. package/dist/chunk-WKX5AMOY.js +309 -0
  171. package/dist/chunk-WNNE3PO3.js +34 -0
  172. package/dist/chunk-WRKUDAZJ.js +3038 -0
  173. package/dist/chunk-WRLUBRKS.cjs +1943 -0
  174. package/dist/chunk-WRNEH5MO.js +3169 -0
  175. package/dist/chunk-WRWEX5ZF.js +658 -0
  176. package/dist/chunk-X3GJPRVK.cjs +3246 -0
  177. package/dist/chunk-XHIV6326.cjs +793 -0
  178. package/dist/chunk-XIVIE43A.cjs +729 -0
  179. package/dist/chunk-XJAN7CZG.cjs +432 -0
  180. package/dist/chunk-XKTPFXGA.js +164 -0
  181. package/dist/chunk-XL6INWKT.js +121 -0
  182. package/dist/chunk-XSFNHP2E.js +632 -0
  183. package/dist/chunk-XT6JY5W5.js +9684 -0
  184. package/dist/chunk-XUILI4KB.cjs +430 -0
  185. package/dist/chunk-XUUVDHIF.cjs +3962 -0
  186. package/dist/chunk-YF2I3MV3.js +46 -0
  187. package/dist/chunk-YIMN575O.js +4847 -0
  188. package/dist/chunk-YIVFJNYV.js +176 -0
  189. package/dist/chunk-YKGPCZEE.cjs +237 -0
  190. package/dist/chunk-YN6V7R3L.cjs +327 -0
  191. package/dist/chunk-YQELFNJV.js +39 -0
  192. package/dist/chunk-YYXH45E2.js +426 -0
  193. package/dist/chunk-ZBQXLH2L.js +756 -0
  194. package/dist/chunk-ZDSYWBIE.cjs +69 -0
  195. package/dist/chunk-ZU7NIRT6.js +325 -0
  196. package/dist/chunk-ZZ7RO2UQ.js +1243 -0
  197. package/dist/chunk-ZZEI7MV4.js +778 -0
  198. package/dist/cli/holoscript-runner.cjs +2255 -0
  199. package/dist/cli/holoscript-runner.js +2230 -0
  200. package/dist/codebase/index.cjs +336 -0
  201. package/dist/codebase/index.js +331 -0
  202. package/dist/compiler/agent-inference.cjs +31 -0
  203. package/dist/compiler/agent-inference.js +8 -0
  204. package/dist/compiler/android-xr.cjs +24 -0
  205. package/dist/compiler/android-xr.js +14 -0
  206. package/dist/compiler/android.cjs +24 -0
  207. package/dist/compiler/android.js +14 -0
  208. package/dist/compiler/ar.cjs +23 -0
  209. package/dist/compiler/ar.js +11 -0
  210. package/dist/compiler/babylon.cjs +21 -0
  211. package/dist/compiler/babylon.js +15 -0
  212. package/dist/compiler/business-quest.cjs +43 -0
  213. package/dist/compiler/business-quest.js +4 -0
  214. package/dist/compiler/coco.cjs +27 -0
  215. package/dist/compiler/coco.js +4 -0
  216. package/dist/compiler/context.cjs +25 -0
  217. package/dist/compiler/context.d.ts +28 -0
  218. package/dist/compiler/context.js +8 -0
  219. package/dist/compiler/domain-block-utils.cjs +605 -0
  220. package/dist/compiler/domain-block-utils.js +11 -0
  221. package/dist/compiler/dtdl.cjs +27 -0
  222. package/dist/compiler/dtdl.js +11 -0
  223. package/dist/compiler/gltf-pipeline.cjs +39 -0
  224. package/dist/compiler/gltf-pipeline.js +4 -0
  225. package/dist/compiler/godot.cjs +18 -0
  226. package/dist/compiler/godot.js +12 -0
  227. package/dist/compiler/incremental.cjs +34 -0
  228. package/dist/compiler/incremental.js +9 -0
  229. package/dist/compiler/index.cjs +5860 -0
  230. package/dist/compiler/index.d.ts +322 -21
  231. package/dist/compiler/index.js +5525 -0
  232. package/dist/compiler/ios.cjs +23 -0
  233. package/dist/compiler/ios.js +13 -0
  234. package/dist/compiler/llm-provider-capabilities.cjs +25 -0
  235. package/dist/compiler/llm-provider-capabilities.d.ts +43 -0
  236. package/dist/compiler/llm-provider-capabilities.js +8 -0
  237. package/dist/compiler/multi-layer.cjs +24 -0
  238. package/dist/compiler/multi-layer.js +15 -0
  239. package/dist/compiler/nodetoy.cjs +23 -0
  240. package/dist/compiler/nodetoy.js +4 -0
  241. package/dist/compiler/openxr.cjs +19 -0
  242. package/dist/compiler/openxr.js +13 -0
  243. package/dist/compiler/playcanvas.cjs +19 -0
  244. package/dist/compiler/playcanvas.js +13 -0
  245. package/dist/compiler/r3f.cjs +38 -0
  246. package/dist/compiler/r3f.d.ts +22 -0
  247. package/dist/compiler/r3f.js +16 -0
  248. package/dist/compiler/remotion.cjs +23 -0
  249. package/dist/compiler/remotion.js +4 -0
  250. package/dist/compiler/reproducibility.cjs +39 -0
  251. package/dist/compiler/reproducibility.js +4 -0
  252. package/dist/compiler/sdf.cjs +24 -0
  253. package/dist/compiler/sdf.js +12 -0
  254. package/dist/compiler/semantic-scene.cjs +31 -0
  255. package/dist/compiler/semantic-scene.js +4 -0
  256. package/dist/compiler/state.cjs +21 -0
  257. package/dist/compiler/state.js +11 -0
  258. package/dist/compiler/trait-composition.cjs +30 -0
  259. package/dist/compiler/trait-composition.js +9 -0
  260. package/dist/compiler/unity.cjs +19 -0
  261. package/dist/compiler/unity.js +13 -0
  262. package/dist/compiler/unreal.cjs +23 -0
  263. package/dist/compiler/unreal.js +13 -0
  264. package/dist/compiler/urdf.cjs +52 -0
  265. package/dist/compiler/urdf.js +12 -0
  266. package/dist/compiler/usd-physics.cjs +26 -0
  267. package/dist/compiler/usd-physics.js +9 -0
  268. package/dist/compiler/visionos.cjs +19 -0
  269. package/dist/compiler/visionos.js +13 -0
  270. package/dist/compiler/vrchat.cjs +22 -0
  271. package/dist/compiler/vrchat.js +12 -0
  272. package/dist/compiler/vrr.cjs +24 -0
  273. package/dist/compiler/vrr.js +12 -0
  274. package/dist/compiler/wasm.cjs +36 -0
  275. package/dist/compiler/wasm.js +12 -0
  276. package/dist/compiler/webgpu.cjs +18 -0
  277. package/dist/compiler/webgpu.js +12 -0
  278. package/dist/coordinators/index.cjs +1266 -0
  279. package/dist/coordinators/index.d.ts +72 -1
  280. package/dist/coordinators/index.js +1259 -0
  281. package/dist/debugger.cjs +24 -0
  282. package/dist/debugger.js +11 -0
  283. package/dist/entries/interop.cjs +64 -0
  284. package/dist/entries/interop.js +7 -0
  285. package/dist/entries/scripting.cjs +55 -0
  286. package/dist/entries/scripting.js +10 -0
  287. package/dist/hololand/index.cjs +146 -0
  288. package/dist/hololand/index.d.ts +70 -0
  289. package/dist/hololand/index.js +5 -0
  290. package/dist/index.cjs +43233 -0
  291. package/dist/index.d.ts +976 -21
  292. package/dist/index.js +39995 -0
  293. package/dist/math/tropical-spmv.cjs +45 -0
  294. package/dist/math/tropical-spmv.js +4 -0
  295. package/dist/math/vec3.cjs +57 -0
  296. package/dist/math/vec3.js +4 -0
  297. package/dist/ml-dsa-FSKBTE3W.cjs +1265 -0
  298. package/dist/ml-dsa-Z7JDKW4L.js +1265 -0
  299. package/dist/paper-0c-spike/index.cjs +150 -0
  300. package/dist/paper-0c-spike/index.js +141 -0
  301. package/dist/parser.cjs +61 -0
  302. package/dist/parser.d.ts +11 -0
  303. package/dist/parser.js +12 -0
  304. package/dist/playwright-3AT3AKTV.cjs +98673 -0
  305. package/dist/playwright-VZPDVUEQ.js +98660 -0
  306. package/dist/reconstruction/index.cjs +153 -0
  307. package/dist/reconstruction/index.d.ts +29 -2
  308. package/dist/reconstruction/index.js +8 -0
  309. package/dist/runtime.cjs +316 -0
  310. package/dist/runtime.d.ts +61 -0
  311. package/dist/runtime.js +31 -0
  312. package/dist/self-improvement/index.cjs +563 -0
  313. package/dist/self-improvement/index.js +545 -0
  314. package/dist/storage/index.cjs +38 -0
  315. package/dist/storage/index.js +5 -0
  316. package/dist/testing.cjs +25 -0
  317. package/dist/testing.d.ts +70 -0
  318. package/dist/testing.js +4 -0
  319. package/dist/traitDocs/traitDocs.cjs +33 -0
  320. package/dist/traitDocs/traitDocs.js +7 -0
  321. package/dist/traits/botanical-lotus.cjs +41 -0
  322. package/dist/traits/botanical-lotus.d.ts +172 -0
  323. package/dist/traits/botanical-lotus.js +4 -0
  324. package/dist/traits/engines/index.cjs +520 -0
  325. package/dist/traits/engines/index.js +380 -0
  326. package/dist/traits/index.cjs +24409 -0
  327. package/dist/traits/index.d.ts +171 -35
  328. package/dist/traits/index.js +21634 -0
  329. package/dist/traits/simulation-solver-factory.cjs +13 -0
  330. package/dist/traits/simulation-solver-factory.d.ts +23 -0
  331. package/dist/traits/simulation-solver-factory.js +4 -0
  332. package/dist/traits/webcam-gaze.cjs +35 -0
  333. package/dist/traits/webcam-gaze.d.ts +17 -0
  334. package/dist/traits/webcam-gaze.js +4 -0
  335. package/dist/type-checker.cjs +19 -0
  336. package/dist/type-checker.js +6 -0
  337. package/dist/world/index.cjs +947 -0
  338. package/dist/world/index.d.ts +147 -0
  339. package/dist/world/index.js +939 -0
  340. package/dist/world-model/index.cjs +1446 -0
  341. package/dist/world-model/index.d.ts +119 -0
  342. package/dist/world-model/index.js +1414 -0
  343. package/dist/wot/index.cjs +29 -0
  344. package/dist/wot/index.js +4 -0
  345. package/package.json +93 -49
@@ -0,0 +1,2252 @@
1
+ import { generateHullGeometry, generateMembraneGeometry, generateSplineGeometry } from './chunk-EKBKLK7P.js';
2
+ import { init_R3FCompiler, init_ObjectPool, ASTNodePool, MATERIAL_PRESETS } from './chunk-UM6C3CGK.js';
3
+ import { init_TraitCompositor, TraitCompositor } from './chunk-4C57PR42.js';
4
+ import { init_DomainBlockCompilerMixin, compileDomainBlocks, compileMaterialBlock, materialToGLTF } from './chunk-JCLBKPMX.js';
5
+ import { init_CompilerBase, CompilerBase } from './chunk-QPSKHBJP.js';
6
+ import { ANSCapabilityPath } from '@holoscript/core-types/ans';
7
+
8
+ // src/compiler/GLTFPipeline.ts
9
+ init_TraitCompositor();
10
+ init_R3FCompiler();
11
+ init_CompilerBase();
12
+ init_DomainBlockCompilerMixin();
13
+
14
+ // src/compiler/gltf/extensions.ts
15
+ function createEmissiveStrengthExtension(strength) {
16
+ return {
17
+ KHR_materials_emissive_strength: {
18
+ emissiveStrength: Math.max(0, strength)
19
+ }
20
+ };
21
+ }
22
+ function createClearcoatExtension(options) {
23
+ return {
24
+ KHR_materials_clearcoat: {
25
+ clearcoatFactor: options.factor ?? 1,
26
+ clearcoatRoughnessFactor: options.roughness ?? 0
27
+ }
28
+ };
29
+ }
30
+ function createTransmissionExtension(factor) {
31
+ return {
32
+ KHR_materials_transmission: {
33
+ transmissionFactor: Math.max(0, Math.min(1, factor))
34
+ }
35
+ };
36
+ }
37
+ function createIORExtension(ior) {
38
+ return {
39
+ KHR_materials_ior: {
40
+ ior: Math.max(1, ior)
41
+ }
42
+ };
43
+ }
44
+ function createSheenExtension(options) {
45
+ return {
46
+ KHR_materials_sheen: {
47
+ sheenColorFactor: options.color ?? [1, 1, 1],
48
+ sheenRoughnessFactor: options.roughness ?? 0.5
49
+ }
50
+ };
51
+ }
52
+ function createAnisotropyExtension(options) {
53
+ return {
54
+ KHR_materials_anisotropy: {
55
+ anisotropyStrength: Math.max(0, Math.min(1, options.strength ?? 0.5)),
56
+ anisotropyRotation: options.rotation ?? 0
57
+ }
58
+ };
59
+ }
60
+ function createVolumeExtension(options) {
61
+ return {
62
+ KHR_materials_volume: {
63
+ thicknessFactor: options.thickness ?? 1,
64
+ attenuationDistance: options.attenuationDistance ?? 1,
65
+ attenuationColor: options.attenuationColor ?? [1, 1, 1]
66
+ }
67
+ };
68
+ }
69
+ function createIridescenceExtension(options) {
70
+ return {
71
+ KHR_materials_iridescence: {
72
+ iridescenceFactor: options.factor ?? 1,
73
+ iridescenceIor: options.ior ?? 1.3,
74
+ iridescenceThicknessMinimum: options.thicknessRange?.[0] ?? 100,
75
+ iridescenceThicknessMaximum: options.thicknessRange?.[1] ?? 400
76
+ }
77
+ };
78
+ }
79
+ function collectUsedExtensions(gltf) {
80
+ const extensions = /* @__PURE__ */ new Set();
81
+ const materials = gltf.materials;
82
+ if (materials) {
83
+ for (const material of materials) {
84
+ if (material.extensions) {
85
+ Object.keys(material.extensions).forEach((ext) => extensions.add(ext));
86
+ }
87
+ }
88
+ }
89
+ const nodes = gltf.nodes;
90
+ if (nodes) {
91
+ for (const node of nodes) {
92
+ if (node.extensions) {
93
+ Object.keys(node.extensions).forEach((ext) => extensions.add(ext));
94
+ }
95
+ }
96
+ }
97
+ if (gltf.extensions) {
98
+ Object.keys(gltf.extensions).forEach((ext) => extensions.add(ext));
99
+ }
100
+ return Array.from(extensions);
101
+ }
102
+ function isExtensionRequired(extension) {
103
+ const requiredExtensions = [
104
+ "KHR_draco_mesh_compression",
105
+ "KHR_mesh_quantization",
106
+ "KHR_texture_basisu"
107
+ ];
108
+ return requiredExtensions.includes(extension);
109
+ }
110
+ function declareExtensions(gltf) {
111
+ const usedExtensions = collectUsedExtensions(gltf);
112
+ if (usedExtensions.length === 0) return;
113
+ gltf.extensionsUsed = usedExtensions;
114
+ const required = usedExtensions.filter(isExtensionRequired);
115
+ if (required.length > 0) {
116
+ gltf.extensionsRequired = required;
117
+ }
118
+ }
119
+
120
+ // src/compiler/GLTFPipeline.ts
121
+ init_ObjectPool();
122
+ var gltfNodePool = new ASTNodePool(
123
+ () => ({ name: "" }),
124
+ (node) => {
125
+ node.name = "";
126
+ node.translation = void 0;
127
+ node.rotation = void 0;
128
+ node.scale = void 0;
129
+ node.mesh = void 0;
130
+ node.skin = void 0;
131
+ node.children = void 0;
132
+ node.camera = void 0;
133
+ node.extras = void 0;
134
+ },
135
+ 0
136
+ // Was 10000 — demand-allocate instead of pre-allocating
137
+ );
138
+ var PRIMITIVE_GENERATORS = {
139
+ cube: generateCubeGeometry,
140
+ box: generateCubeGeometry,
141
+ sphere: generateSphereGeometry,
142
+ orb: generateSphereGeometry,
143
+ cylinder: generateCylinderGeometry,
144
+ cone: generateConeGeometry,
145
+ pyramid: generateConeGeometry,
146
+ plane: generatePlaneGeometry,
147
+ ground: generatePlaneGeometry
148
+ };
149
+ function generateScaleTexture(size = 512, baseColor = [30, 15, 61], borderColor = [20, 12, 40], highlightColor = [70, 50, 120]) {
150
+ const data = new Uint8Array(size * size * 4);
151
+ const scaleSize = size / 16;
152
+ const hexH = scaleSize;
153
+ const hexW = scaleSize * Math.sqrt(3);
154
+ function scaleHash(row, col) {
155
+ let h = row * 73856093 ^ col * 19349663;
156
+ h = (h >> 16 ^ h) * 73244475;
157
+ h = (h >> 16 ^ h) * 73244475;
158
+ return (h >> 16 ^ h) & 255;
159
+ }
160
+ for (let y = 0; y < size; y++) {
161
+ for (let x = 0; x < size; x++) {
162
+ const row = Math.floor(y / (hexH * 0.75));
163
+ const isOddRow = row % 2 === 1;
164
+ const xOff = isOddRow ? hexW * 0.5 : 0;
165
+ const col = Math.floor((x + xOff) / hexW);
166
+ const cx = col * hexW - xOff + hexW * 0.5;
167
+ const cy = row * hexH * 0.75 + hexH * 0.5;
168
+ const dx = (x - cx) / (hexW * 0.5);
169
+ const dy = (y - cy) / (hexH * 0.5);
170
+ const q = Math.abs(dx);
171
+ const r = Math.abs(dy);
172
+ const hexDist = Math.max(q, (q + r * Math.sqrt(3)) / 2);
173
+ const jitter = (scaleHash(row, col) / 255 - 0.5) * 40;
174
+ const jR = Math.round(jitter * 0.4);
175
+ const jG = Math.round(jitter * 0.3);
176
+ const jB = Math.round(jitter * 0.6);
177
+ const idx = (y * size + x) * 4;
178
+ if (hexDist > 0.94) {
179
+ data[idx] = Math.max(0, borderColor[0] + jR);
180
+ data[idx + 1] = Math.max(0, borderColor[1] + jG);
181
+ data[idx + 2] = Math.max(0, borderColor[2] + jB);
182
+ data[idx + 3] = 255;
183
+ } else if (hexDist < 0.12) {
184
+ const t = hexDist / 0.12;
185
+ const specR = 100, specG = 80, specB = 160;
186
+ data[idx] = Math.min(255, Math.round(specR * (1 - t) + highlightColor[0] * t) + jR);
187
+ data[idx + 1] = Math.min(255, Math.round(specG * (1 - t) + highlightColor[1] * t) + jG);
188
+ data[idx + 2] = Math.min(255, Math.round(specB * (1 - t) + highlightColor[2] * t) + jB);
189
+ data[idx + 3] = 255;
190
+ } else if (hexDist < 0.35) {
191
+ const t = (hexDist - 0.12) / 0.23;
192
+ data[idx] = Math.min(255, Math.round(highlightColor[0] * (1 - t) + baseColor[0] * t) + jR);
193
+ data[idx + 1] = Math.min(
194
+ 255,
195
+ Math.round(highlightColor[1] * (1 - t) + baseColor[1] * t) + jG
196
+ );
197
+ data[idx + 2] = Math.min(
198
+ 255,
199
+ Math.round(highlightColor[2] * (1 - t) + baseColor[2] * t) + jB
200
+ );
201
+ data[idx + 3] = 255;
202
+ } else {
203
+ const t = (hexDist - 0.35) / 0.59;
204
+ data[idx] = Math.max(
205
+ 0,
206
+ Math.min(255, Math.round(baseColor[0] * (1 - t * 0.3) + borderColor[0] * (t * 0.3)) + jR)
207
+ );
208
+ data[idx + 1] = Math.max(
209
+ 0,
210
+ Math.min(255, Math.round(baseColor[1] * (1 - t * 0.3) + borderColor[1] * (t * 0.3)) + jG)
211
+ );
212
+ data[idx + 2] = Math.max(
213
+ 0,
214
+ Math.min(255, Math.round(baseColor[2] * (1 - t * 0.3) + borderColor[2] * (t * 0.3)) + jB)
215
+ );
216
+ data[idx + 3] = 255;
217
+ }
218
+ }
219
+ }
220
+ return data;
221
+ }
222
+ function generateScaleNormalMap(size = 512) {
223
+ const data = new Uint8Array(size * size * 4);
224
+ const scaleSize = size / 16;
225
+ const hexH = scaleSize;
226
+ const hexW = scaleSize * Math.sqrt(3);
227
+ for (let y = 0; y < size; y++) {
228
+ for (let x = 0; x < size; x++) {
229
+ const row = Math.floor(y / (hexH * 0.75));
230
+ const isOddRow = row % 2 === 1;
231
+ const xOff = isOddRow ? hexW * 0.5 : 0;
232
+ const col = Math.floor((x + xOff) / hexW);
233
+ const cx = col * hexW - xOff + hexW * 0.5;
234
+ const cy = row * hexH * 0.75 + hexH * 0.5;
235
+ const dx = (x - cx) / (hexW * 0.5);
236
+ const dy = (y - cy) / (hexH * 0.5);
237
+ const q = Math.abs(dx);
238
+ const r = Math.abs(dy);
239
+ const hexDist = Math.max(q, (q + r * Math.sqrt(3)) / 2);
240
+ const idx = (y * size + x) * 4;
241
+ let nx = 0, ny = 0, nz = 1;
242
+ if (hexDist > 0.92 && hexDist < 1) {
243
+ const len = Math.sqrt(dx * dx + dy * dy) || 1;
244
+ const strength = 0.55;
245
+ nx = dx / len * strength;
246
+ ny = dy / len * strength;
247
+ nz = Math.sqrt(Math.max(0, 1 - nx * nx - ny * ny));
248
+ } else if (hexDist < 0.5) {
249
+ const strength = 0.25;
250
+ nx = -dx * strength;
251
+ ny = -dy * strength;
252
+ nz = Math.sqrt(Math.max(0, 1 - nx * nx - ny * ny));
253
+ }
254
+ data[idx] = Math.round((nx * 0.5 + 0.5) * 255);
255
+ data[idx + 1] = Math.round((ny * 0.5 + 0.5) * 255);
256
+ data[idx + 2] = Math.round((nz * 0.5 + 0.5) * 255);
257
+ data[idx + 3] = 255;
258
+ }
259
+ }
260
+ return data;
261
+ }
262
+ function encodePNG(pixels, width, height) {
263
+ const rowSize = width * 4 + 1;
264
+ const rawData = new Uint8Array(rowSize * height);
265
+ for (let y = 0; y < height; y++) {
266
+ rawData[y * rowSize] = 0;
267
+ rawData.set(pixels.slice(y * width * 4, (y + 1) * width * 4), y * rowSize + 1);
268
+ }
269
+ const deflated = deflateStored(rawData);
270
+ const crcTable = [];
271
+ for (let n = 0; n < 256; n++) {
272
+ let c = n;
273
+ for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
274
+ crcTable[n] = c;
275
+ }
276
+ function crc32(buf) {
277
+ let crc = 4294967295;
278
+ for (let i = 0; i < buf.length; i++) crc = crcTable[(crc ^ buf[i]) & 255] ^ crc >>> 8;
279
+ return (crc ^ 4294967295) >>> 0;
280
+ }
281
+ function writeChunk(type, data) {
282
+ const chunk = new Uint8Array(4 + 4 + data.length + 4);
283
+ const dv = new DataView(chunk.buffer);
284
+ dv.setUint32(0, data.length);
285
+ for (let i = 0; i < 4; i++) chunk[4 + i] = type.charCodeAt(i);
286
+ chunk.set(data, 8);
287
+ const crcInput = new Uint8Array(4 + data.length);
288
+ crcInput.set(chunk.slice(4, 8));
289
+ crcInput.set(data, 4);
290
+ dv.setUint32(8 + data.length, crc32(crcInput));
291
+ return chunk;
292
+ }
293
+ const signature = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]);
294
+ const ihdr = new Uint8Array(13);
295
+ const ihdrDV = new DataView(ihdr.buffer);
296
+ ihdrDV.setUint32(0, width);
297
+ ihdrDV.setUint32(4, height);
298
+ ihdr[8] = 8;
299
+ ihdr[9] = 6;
300
+ ihdr[10] = 0;
301
+ ihdr[11] = 0;
302
+ ihdr[12] = 0;
303
+ const ihdrChunk = writeChunk("IHDR", ihdr);
304
+ const idatChunk = writeChunk("IDAT", deflated);
305
+ const iendChunk = writeChunk("IEND", new Uint8Array(0));
306
+ const png = new Uint8Array(
307
+ signature.length + ihdrChunk.length + idatChunk.length + iendChunk.length
308
+ );
309
+ let offset = 0;
310
+ png.set(signature, offset);
311
+ offset += signature.length;
312
+ png.set(ihdrChunk, offset);
313
+ offset += ihdrChunk.length;
314
+ png.set(idatChunk, offset);
315
+ offset += idatChunk.length;
316
+ png.set(iendChunk, offset);
317
+ return png;
318
+ }
319
+ function decimateGeometry(geometry, ratio) {
320
+ const cellSize = Math.max(0.01, (1 - ratio) * 0.3);
321
+ const positions = geometry.positions;
322
+ const normals = geometry.normals;
323
+ const uvs = geometry.uvs;
324
+ const indices = geometry.indices;
325
+ const vertCount = positions.length / 3;
326
+ const cellMap = /* @__PURE__ */ new Map();
327
+ const remap = new Int32Array(vertCount);
328
+ const newPositions = [];
329
+ const newNormals = [];
330
+ const newUVs = [];
331
+ let newIdx = 0;
332
+ for (let i = 0; i < vertCount; i++) {
333
+ const px = positions[i * 3], py = positions[i * 3 + 1], pz = positions[i * 3 + 2];
334
+ const cx = Math.round(px / cellSize), cy = Math.round(py / cellSize), cz = Math.round(pz / cellSize);
335
+ const key = `${cx},${cy},${cz}`;
336
+ if (cellMap.has(key)) {
337
+ remap[i] = cellMap.get(key);
338
+ } else {
339
+ cellMap.set(key, newIdx);
340
+ remap[i] = newIdx;
341
+ newPositions.push(px, py, pz);
342
+ newNormals.push(normals[i * 3], normals[i * 3 + 1], normals[i * 3 + 2]);
343
+ newUVs.push(uvs[i * 2], uvs[i * 2 + 1]);
344
+ newIdx++;
345
+ }
346
+ }
347
+ const newIndices = [];
348
+ for (let i = 0; i < indices.length; i += 3) {
349
+ const a = remap[indices[i]], b = remap[indices[i + 1]], c = remap[indices[i + 2]];
350
+ if (a !== b && b !== c && a !== c) {
351
+ newIndices.push(a, b, c);
352
+ }
353
+ }
354
+ const newVertexCount = newPositions.length / 3;
355
+ const IndexArrayType = newVertexCount > 65535 ? Uint32Array : Uint16Array;
356
+ return {
357
+ positions: new Float32Array(newPositions),
358
+ normals: new Float32Array(newNormals),
359
+ uvs: new Float32Array(newUVs),
360
+ indices: new IndexArrayType(newIndices)
361
+ };
362
+ }
363
+ var DRAGON_SKELETON = [
364
+ { name: "Root", position: [0, 2.5, 0] },
365
+ { name: "Spine", position: [0, 2.5, 0], parent: "Root" },
366
+ { name: "Neck", position: [0, 3.5, 2], parent: "Spine" },
367
+ { name: "Head", position: [0, 4.5, 4.2], parent: "Neck" },
368
+ { name: "Jaw", position: [0, 4.2, 4.6], parent: "Head" },
369
+ { name: "Tail1", position: [0, 2.2, -2], parent: "Spine" },
370
+ { name: "Tail2", position: [0, 1, -3.5], parent: "Tail1" },
371
+ { name: "TailTip", position: [0, -0.05, -4.6], parent: "Tail2" },
372
+ { name: "LeftWing", position: [-1.2, 3, 0.2], parent: "Spine" },
373
+ { name: "LeftWingTip", position: [-2.6, 3.8, 0.2], parent: "LeftWing" },
374
+ { name: "RightWing", position: [1.2, 3, 0.2], parent: "Spine" },
375
+ { name: "RightWingTip", position: [2.6, 3.8, 0.2], parent: "RightWing" },
376
+ { name: "LeftFrontLeg", position: [-0.9, 1.6, 1.2], parent: "Spine" },
377
+ { name: "LeftFrontFoot", position: [-0.95, 0.15, 1.4], parent: "LeftFrontLeg" },
378
+ { name: "RightFrontLeg", position: [0.9, 1.6, 1.2], parent: "Spine" },
379
+ { name: "RightFrontFoot", position: [0.95, 0.15, 1.4], parent: "RightFrontLeg" },
380
+ { name: "LeftBackLeg", position: [-0.9, 1.5, -1], parent: "Spine" },
381
+ { name: "LeftBackFoot", position: [-0.95, 0.1, -1.15], parent: "LeftBackLeg" },
382
+ { name: "RightBackLeg", position: [0.9, 1.5, -1], parent: "Spine" },
383
+ { name: "RightBackFoot", position: [0.95, 0.1, -1.15], parent: "RightBackLeg" }
384
+ ];
385
+ function deflateStored(data) {
386
+ const BLOCK_MAX = 65535;
387
+ const numBlocks = Math.ceil(data.length / BLOCK_MAX) || 1;
388
+ let size = 2 + 4;
389
+ for (let i = 0; i < numBlocks; i++) {
390
+ size += 5;
391
+ const blockLen = Math.min(BLOCK_MAX, data.length - i * BLOCK_MAX);
392
+ size += blockLen;
393
+ }
394
+ const out = new Uint8Array(size);
395
+ let pos = 0;
396
+ out[pos++] = 120;
397
+ out[pos++] = 1;
398
+ for (let i = 0; i < numBlocks; i++) {
399
+ const blockStart = i * BLOCK_MAX;
400
+ const blockLen = Math.min(BLOCK_MAX, data.length - blockStart);
401
+ const isLast = i === numBlocks - 1;
402
+ out[pos++] = isLast ? 1 : 0;
403
+ out[pos++] = blockLen & 255;
404
+ out[pos++] = blockLen >> 8 & 255;
405
+ out[pos++] = ~blockLen & 255;
406
+ out[pos++] = ~blockLen >> 8 & 255;
407
+ out.set(data.slice(blockStart, blockStart + blockLen), pos);
408
+ pos += blockLen;
409
+ }
410
+ let a = 1, b = 0;
411
+ for (let i = 0; i < data.length; i++) {
412
+ a = (a + data[i]) % 65521;
413
+ b = (b + a) % 65521;
414
+ }
415
+ const adler = (b << 16 | a) >>> 0;
416
+ out[pos++] = adler >> 24 & 255;
417
+ out[pos++] = adler >> 16 & 255;
418
+ out[pos++] = adler >> 8 & 255;
419
+ out[pos++] = adler & 255;
420
+ return out;
421
+ }
422
+ var ADVANCED_GEOMETRY_TYPES = /* @__PURE__ */ new Set(["spline", "membrane", "hull", "blob", "metaball"]);
423
+ function generateCubeGeometry(scale) {
424
+ const [sx, sy, sz] = scale.map((s) => s * 0.5);
425
+ const positions = new Float32Array([
426
+ // Front face
427
+ -sx,
428
+ -sy,
429
+ sz,
430
+ sx,
431
+ -sy,
432
+ sz,
433
+ sx,
434
+ sy,
435
+ sz,
436
+ -sx,
437
+ sy,
438
+ sz,
439
+ // Back face
440
+ -sx,
441
+ -sy,
442
+ -sz,
443
+ -sx,
444
+ sy,
445
+ -sz,
446
+ sx,
447
+ sy,
448
+ -sz,
449
+ sx,
450
+ -sy,
451
+ -sz,
452
+ // Top face
453
+ -sx,
454
+ sy,
455
+ -sz,
456
+ -sx,
457
+ sy,
458
+ sz,
459
+ sx,
460
+ sy,
461
+ sz,
462
+ sx,
463
+ sy,
464
+ -sz,
465
+ // Bottom face
466
+ -sx,
467
+ -sy,
468
+ -sz,
469
+ sx,
470
+ -sy,
471
+ -sz,
472
+ sx,
473
+ -sy,
474
+ sz,
475
+ -sx,
476
+ -sy,
477
+ sz,
478
+ // Right face
479
+ sx,
480
+ -sy,
481
+ -sz,
482
+ sx,
483
+ sy,
484
+ -sz,
485
+ sx,
486
+ sy,
487
+ sz,
488
+ sx,
489
+ -sy,
490
+ sz,
491
+ // Left face
492
+ -sx,
493
+ -sy,
494
+ -sz,
495
+ -sx,
496
+ -sy,
497
+ sz,
498
+ -sx,
499
+ sy,
500
+ sz,
501
+ -sx,
502
+ sy,
503
+ -sz
504
+ ]);
505
+ const normals = new Float32Array([
506
+ // Front
507
+ 0,
508
+ 0,
509
+ 1,
510
+ 0,
511
+ 0,
512
+ 1,
513
+ 0,
514
+ 0,
515
+ 1,
516
+ 0,
517
+ 0,
518
+ 1,
519
+ // Back
520
+ 0,
521
+ 0,
522
+ -1,
523
+ 0,
524
+ 0,
525
+ -1,
526
+ 0,
527
+ 0,
528
+ -1,
529
+ 0,
530
+ 0,
531
+ -1,
532
+ // Top
533
+ 0,
534
+ 1,
535
+ 0,
536
+ 0,
537
+ 1,
538
+ 0,
539
+ 0,
540
+ 1,
541
+ 0,
542
+ 0,
543
+ 1,
544
+ 0,
545
+ // Bottom
546
+ 0,
547
+ -1,
548
+ 0,
549
+ 0,
550
+ -1,
551
+ 0,
552
+ 0,
553
+ -1,
554
+ 0,
555
+ 0,
556
+ -1,
557
+ 0,
558
+ // Right
559
+ 1,
560
+ 0,
561
+ 0,
562
+ 1,
563
+ 0,
564
+ 0,
565
+ 1,
566
+ 0,
567
+ 0,
568
+ 1,
569
+ 0,
570
+ 0,
571
+ // Left
572
+ -1,
573
+ 0,
574
+ 0,
575
+ -1,
576
+ 0,
577
+ 0,
578
+ -1,
579
+ 0,
580
+ 0,
581
+ -1,
582
+ 0,
583
+ 0
584
+ ]);
585
+ const uvs = new Float32Array([
586
+ // Front
587
+ 0,
588
+ 0,
589
+ 1,
590
+ 0,
591
+ 1,
592
+ 1,
593
+ 0,
594
+ 1,
595
+ // Back
596
+ 1,
597
+ 0,
598
+ 1,
599
+ 1,
600
+ 0,
601
+ 1,
602
+ 0,
603
+ 0,
604
+ // Top
605
+ 0,
606
+ 1,
607
+ 0,
608
+ 0,
609
+ 1,
610
+ 0,
611
+ 1,
612
+ 1,
613
+ // Bottom
614
+ 1,
615
+ 1,
616
+ 0,
617
+ 1,
618
+ 0,
619
+ 0,
620
+ 1,
621
+ 0,
622
+ // Right
623
+ 1,
624
+ 0,
625
+ 1,
626
+ 1,
627
+ 0,
628
+ 1,
629
+ 0,
630
+ 0,
631
+ // Left
632
+ 0,
633
+ 0,
634
+ 1,
635
+ 0,
636
+ 1,
637
+ 1,
638
+ 0,
639
+ 1
640
+ ]);
641
+ const indices = new Uint16Array([
642
+ 0,
643
+ 1,
644
+ 2,
645
+ 0,
646
+ 2,
647
+ 3,
648
+ // Front
649
+ 4,
650
+ 5,
651
+ 6,
652
+ 4,
653
+ 6,
654
+ 7,
655
+ // Back
656
+ 8,
657
+ 9,
658
+ 10,
659
+ 8,
660
+ 10,
661
+ 11,
662
+ // Top
663
+ 12,
664
+ 13,
665
+ 14,
666
+ 12,
667
+ 14,
668
+ 15,
669
+ // Bottom
670
+ 16,
671
+ 17,
672
+ 18,
673
+ 16,
674
+ 18,
675
+ 19,
676
+ // Right
677
+ 20,
678
+ 21,
679
+ 22,
680
+ 20,
681
+ 22,
682
+ 23
683
+ // Left
684
+ ]);
685
+ return { positions, normals, uvs, indices };
686
+ }
687
+ function generateSphereGeometry(scale) {
688
+ const sx = scale[0] * 0.5;
689
+ const sy = scale[1] * 0.5;
690
+ const sz = scale[2] * 0.5;
691
+ const segments = 32;
692
+ const rings = 24;
693
+ const positions = [];
694
+ const normals = [];
695
+ const uvs = [];
696
+ const indices = [];
697
+ for (let y = 0; y <= rings; y++) {
698
+ const v = y / rings;
699
+ const theta = v * Math.PI;
700
+ for (let x = 0; x <= segments; x++) {
701
+ const u = x / segments;
702
+ const phi = u * Math.PI * 2;
703
+ const nx = Math.sin(theta) * Math.cos(phi);
704
+ const ny = Math.cos(theta);
705
+ const nz = Math.sin(theta) * Math.sin(phi);
706
+ positions.push(nx * sx);
707
+ positions.push(ny * sy);
708
+ positions.push(nz * sz);
709
+ normals.push(nx, ny, nz);
710
+ uvs.push(u, 1 - v);
711
+ }
712
+ }
713
+ for (let y = 0; y < rings; y++) {
714
+ for (let x = 0; x < segments; x++) {
715
+ const a = y * (segments + 1) + x;
716
+ const b = a + segments + 1;
717
+ indices.push(a, b, a + 1);
718
+ indices.push(b, b + 1, a + 1);
719
+ }
720
+ }
721
+ return {
722
+ positions: new Float32Array(positions),
723
+ normals: new Float32Array(normals),
724
+ uvs: new Float32Array(uvs),
725
+ indices: new Uint16Array(indices)
726
+ };
727
+ }
728
+ function generateCylinderGeometry(scale) {
729
+ const radiusTop = scale[0] * 0.5;
730
+ const radiusBottom = scale[2] * 0.5;
731
+ const height = scale[1];
732
+ const segments = 32;
733
+ const positions = [];
734
+ const normals = [];
735
+ const uvs = [];
736
+ const indices = [];
737
+ const halfHeight = height / 2;
738
+ for (let y = 0; y <= 1; y++) {
739
+ const radius = y === 0 ? radiusBottom : radiusTop;
740
+ const posY = y === 0 ? -halfHeight : halfHeight;
741
+ for (let x = 0; x <= segments; x++) {
742
+ const u = x / segments;
743
+ const theta = u * Math.PI * 2;
744
+ const cosTheta = Math.cos(theta);
745
+ const sinTheta = Math.sin(theta);
746
+ positions.push(radius * cosTheta, posY, radius * sinTheta);
747
+ normals.push(cosTheta, 0, sinTheta);
748
+ uvs.push(u, y);
749
+ }
750
+ }
751
+ for (let x = 0; x < segments; x++) {
752
+ const a = x;
753
+ const b = x + segments + 1;
754
+ indices.push(a, b, a + 1);
755
+ indices.push(b, b + 1, a + 1);
756
+ }
757
+ const topCenterIndex = positions.length / 3;
758
+ positions.push(0, halfHeight, 0);
759
+ normals.push(0, 1, 0);
760
+ uvs.push(0.5, 0.5);
761
+ for (let x = 0; x <= segments; x++) {
762
+ const u = x / segments;
763
+ const theta = u * Math.PI * 2;
764
+ positions.push(radiusTop * Math.cos(theta), halfHeight, radiusTop * Math.sin(theta));
765
+ normals.push(0, 1, 0);
766
+ uvs.push(Math.cos(theta) * 0.5 + 0.5, Math.sin(theta) * 0.5 + 0.5);
767
+ }
768
+ for (let x = 0; x < segments; x++) {
769
+ indices.push(topCenterIndex, topCenterIndex + x + 1, topCenterIndex + x + 2);
770
+ }
771
+ const bottomCenterIndex = positions.length / 3;
772
+ positions.push(0, -halfHeight, 0);
773
+ normals.push(0, -1, 0);
774
+ uvs.push(0.5, 0.5);
775
+ for (let x = 0; x <= segments; x++) {
776
+ const u = x / segments;
777
+ const theta = u * Math.PI * 2;
778
+ positions.push(radiusBottom * Math.cos(theta), -halfHeight, radiusBottom * Math.sin(theta));
779
+ normals.push(0, -1, 0);
780
+ uvs.push(Math.cos(theta) * 0.5 + 0.5, Math.sin(theta) * 0.5 + 0.5);
781
+ }
782
+ for (let x = 0; x < segments; x++) {
783
+ indices.push(bottomCenterIndex, bottomCenterIndex + x + 2, bottomCenterIndex + x + 1);
784
+ }
785
+ return {
786
+ positions: new Float32Array(positions),
787
+ normals: new Float32Array(normals),
788
+ uvs: new Float32Array(uvs),
789
+ indices: new Uint16Array(indices)
790
+ };
791
+ }
792
+ function generateConeGeometry(scale) {
793
+ return generateCylinderGeometry([1e-3, scale[1], scale[2]]);
794
+ }
795
+ function generatePlaneGeometry(scale) {
796
+ const [sx, _, sz] = scale.map((s) => s * 0.5);
797
+ const positions = new Float32Array([
798
+ -sx,
799
+ 0,
800
+ -sz,
801
+ sx,
802
+ 0,
803
+ -sz,
804
+ sx,
805
+ 0,
806
+ sz,
807
+ -sx,
808
+ 0,
809
+ sz
810
+ ]);
811
+ const normals = new Float32Array([
812
+ 0,
813
+ 1,
814
+ 0,
815
+ 0,
816
+ 1,
817
+ 0,
818
+ 0,
819
+ 1,
820
+ 0,
821
+ 0,
822
+ 1,
823
+ 0
824
+ ]);
825
+ const uvs = new Float32Array([
826
+ 0,
827
+ 0,
828
+ 1,
829
+ 0,
830
+ 1,
831
+ 1,
832
+ 0,
833
+ 1
834
+ ]);
835
+ const indices = new Uint16Array([0, 1, 2, 0, 2, 3]);
836
+ return { positions, normals, uvs, indices };
837
+ }
838
+ var INITIAL_COMPILE_BUFFER_SIZE = 1024 * 1024;
839
+ var MAX_RETAINED_BUFFER_SIZE = 1024 * 1024 * 20;
840
+ var SHARED_COMPILE_BUFFER = new Uint8Array(INITIAL_COMPILE_BUFFER_SIZE);
841
+ var GLTFPipeline = class extends CompilerBase {
842
+ constructor(options = {}) {
843
+ super();
844
+ this.compilerName = "GLTFPipeline";
845
+ this.bufferByteLength = 0;
846
+ this.accessors = [];
847
+ this.bufferViews = [];
848
+ this.meshes = [];
849
+ this.materials = [];
850
+ this.nodes = [];
851
+ this.scenes = [];
852
+ this.animations = [];
853
+ this.materialMap = /* @__PURE__ */ new Map();
854
+ this.images = [];
855
+ this.textures = [];
856
+ this.samplers = [];
857
+ this.scaleTextureIndex = -1;
858
+ this.scaleNormalTextureIndex = -1;
859
+ this.textureIndexMap = /* @__PURE__ */ new Map();
860
+ this.stats = {
861
+ nodeCount: 0,
862
+ meshCount: 0,
863
+ materialCount: 0,
864
+ textureCount: 0,
865
+ animationCount: 0,
866
+ totalVertices: 0,
867
+ totalTriangles: 0,
868
+ fileSizeBytes: 0
869
+ };
870
+ this._lodCoverages = null;
871
+ this._skins = null;
872
+ this._jointStartIndex = 0;
873
+ this.options = {
874
+ provenanceHash: options.provenanceHash ?? "",
875
+ format: options.format ?? "glb",
876
+ dracoCompression: options.dracoCompression ?? false,
877
+ quantize: options.quantize ?? true,
878
+ prune: options.prune ?? true,
879
+ dedupe: options.dedupe ?? true,
880
+ embedTextures: options.embedTextures ?? true,
881
+ textureData: options.textureData ?? {},
882
+ generator: options.generator ?? "HoloScript GLTFPipeline v1.0.0",
883
+ copyright: options.copyright ?? ""
884
+ };
885
+ this.compositor = new TraitCompositor();
886
+ }
887
+ getRequiredCapability() {
888
+ return ANSCapabilityPath.GLTF;
889
+ }
890
+ get bufferData() {
891
+ return SHARED_COMPILE_BUFFER;
892
+ }
893
+ set bufferData(v) {
894
+ SHARED_COMPILE_BUFFER = v;
895
+ }
896
+ ensureBufferCapacity(needed) {
897
+ if (this.bufferByteLength + needed > this.bufferData.length) {
898
+ const newLen = Math.max(this.bufferData.length * 2, this.bufferByteLength + needed);
899
+ const newArr = new Uint8Array(newLen);
900
+ newArr.set(this.bufferData.subarray(0, this.bufferByteLength));
901
+ this.bufferData = newArr;
902
+ }
903
+ }
904
+ appendToBuffer(data) {
905
+ this.ensureBufferCapacity(data.length);
906
+ this.bufferData.set(data, this.bufferByteLength);
907
+ this.bufferByteLength += data.length;
908
+ }
909
+ padBuffer(alignment) {
910
+ const remainder = this.bufferByteLength % alignment;
911
+ if (remainder !== 0) {
912
+ const padding = alignment - remainder;
913
+ this.ensureBufferCapacity(padding);
914
+ this.bufferByteLength += padding;
915
+ }
916
+ }
917
+ /**
918
+ * Global smooth normals pass.
919
+ * Finds vertices at the same 3D position across all meshes and averages
920
+ * their normals. This eliminates hard seams where separate meshes meet
921
+ * (e.g., neck spline meets the head sphere).
922
+ */
923
+ smoothNormalsGlobal() {
924
+ const QUANT = 100;
925
+ const posMap = /* @__PURE__ */ new Map();
926
+ for (const mesh of this.meshes) {
927
+ for (const prim of mesh.primitives) {
928
+ const posIdx = prim.attributes.POSITION;
929
+ const nrmIdx = prim.attributes.NORMAL;
930
+ if (posIdx === void 0 || nrmIdx === void 0) continue;
931
+ const posAcc = this.accessors[posIdx];
932
+ const nrmAcc = this.accessors[nrmIdx];
933
+ if (!posAcc || !nrmAcc) continue;
934
+ const posBV = this.bufferViews[posAcc.bufferView];
935
+ const nrmBV = this.bufferViews[nrmAcc.bufferView];
936
+ if (!posBV || !nrmBV) continue;
937
+ const count = posAcc.count;
938
+ for (let i = 0; i < count; i++) {
939
+ const pOff = posBV.byteOffset + i * 12;
940
+ const px = this.readFloat32(pOff);
941
+ const py = this.readFloat32(pOff + 4);
942
+ const pz = this.readFloat32(pOff + 8);
943
+ const nOff = nrmBV.byteOffset + i * 12;
944
+ const nx = this.readFloat32(nOff);
945
+ const ny = this.readFloat32(nOff + 4);
946
+ const nz = this.readFloat32(nOff + 8);
947
+ const key = `${Math.round(px * QUANT)},${Math.round(py * QUANT)},${Math.round(pz * QUANT)}`;
948
+ let entries = posMap.get(key);
949
+ if (!entries) {
950
+ entries = [];
951
+ posMap.set(key, entries);
952
+ }
953
+ entries.push({ nx, ny, nz, byteOffset: nOff });
954
+ }
955
+ }
956
+ }
957
+ for (const entries of posMap.values()) {
958
+ if (entries.length < 2) continue;
959
+ let ax = 0, ay = 0, az = 0;
960
+ for (const e of entries) {
961
+ ax += e.nx;
962
+ ay += e.ny;
963
+ az += e.nz;
964
+ }
965
+ const len = Math.sqrt(ax * ax + ay * ay + az * az);
966
+ if (len < 1e-8) continue;
967
+ ax /= len;
968
+ ay /= len;
969
+ az /= len;
970
+ for (const e of entries) {
971
+ this.writeFloat32(e.byteOffset, ax);
972
+ this.writeFloat32(e.byteOffset + 4, ay);
973
+ this.writeFloat32(e.byteOffset + 8, az);
974
+ }
975
+ }
976
+ }
977
+ /** Read a Float32 from the buffer at byteOffset */
978
+ readFloat32(byteOffset) {
979
+ const bytes = new Uint8Array(4);
980
+ bytes.set(this.bufferData.subarray(byteOffset, byteOffset + 4));
981
+ return new Float32Array(bytes.buffer)[0];
982
+ }
983
+ /** Write a Float32 to the buffer at byteOffset */
984
+ writeFloat32(byteOffset, value) {
985
+ const f32 = new Float32Array([value]);
986
+ const view = new Uint8Array(f32.buffer);
987
+ this.bufferData.set(view, byteOffset);
988
+ }
989
+ /**
990
+ * Generate LOD meshes for the MSFT_lod extension.
991
+ * Creates 2 lower detail levels (50% and 25%) per mesh.
992
+ */
993
+ generateLODs() {
994
+ const ratios = [0.5, 0.25];
995
+ const originalCount = this.meshes.length;
996
+ const coverages = [];
997
+ for (let mi = 0; mi < originalCount; mi++) {
998
+ const mesh = this.meshes[mi];
999
+ const lodIds = [];
1000
+ for (const ratio of ratios) {
1001
+ for (const prim of mesh.primitives) {
1002
+ const posIdx = prim.attributes.POSITION;
1003
+ const nrmIdx = prim.attributes.NORMAL;
1004
+ const uvIdx = prim.attributes.TEXCOORD_0;
1005
+ const idxIdx = prim.indices;
1006
+ if (posIdx === void 0 || nrmIdx === void 0 || idxIdx === void 0) continue;
1007
+ const posAcc = this.accessors[posIdx];
1008
+ const nrmAcc = this.accessors[nrmIdx];
1009
+ const idxAcc = this.accessors[idxIdx];
1010
+ if (!posAcc || !nrmAcc || !idxAcc) continue;
1011
+ const posBV = this.bufferViews[posAcc.bufferView];
1012
+ const nrmBV = this.bufferViews[nrmAcc.bufferView];
1013
+ const idxBV = this.bufferViews[idxAcc.bufferView];
1014
+ if (!posBV || !nrmBV || !idxBV) continue;
1015
+ const vCount = posAcc.count;
1016
+ const iCount = idxAcc.count;
1017
+ const positions = new Float32Array(vCount * 3);
1018
+ const normals = new Float32Array(vCount * 3);
1019
+ const uvs = new Float32Array(vCount * 2);
1020
+ const indices = new Uint16Array(iCount);
1021
+ for (let i = 0; i < vCount * 3; i++) {
1022
+ positions[i] = this.readFloat32(posBV.byteOffset + i * 4);
1023
+ normals[i] = this.readFloat32(nrmBV.byteOffset + i * 4);
1024
+ }
1025
+ if (uvIdx !== void 0) {
1026
+ const uvAcc = this.accessors[uvIdx];
1027
+ const uvBV = uvAcc ? this.bufferViews[uvAcc.bufferView] : null;
1028
+ if (uvBV) {
1029
+ for (let i = 0; i < vCount * 2; i++) {
1030
+ uvs[i] = this.readFloat32(uvBV.byteOffset + i * 4);
1031
+ }
1032
+ }
1033
+ }
1034
+ const compSize = idxAcc.componentType === 5123 ? 2 : 4;
1035
+ for (let i = 0; i < iCount; i++) {
1036
+ const off = idxBV.byteOffset + i * compSize;
1037
+ if (compSize === 2) {
1038
+ indices[i] = this.bufferData[off] | this.bufferData[off + 1] << 8;
1039
+ } else {
1040
+ indices[i] = this.readFloat32(off);
1041
+ }
1042
+ }
1043
+ const geom = { positions, normals, uvs, indices };
1044
+ const decimated = decimateGeometry(geom, ratio);
1045
+ const lodMeshIndex = this.meshes.length;
1046
+ const lodPrim = { attributes: {}, material: prim.material };
1047
+ lodPrim.attributes.POSITION = this.createAccessor(decimated.positions, "VEC3", true);
1048
+ lodPrim.attributes.NORMAL = this.createAccessor(decimated.normals, "VEC3");
1049
+ lodPrim.attributes.TEXCOORD_0 = this.createAccessor(decimated.uvs, "VEC2");
1050
+ lodPrim.indices = this.createAccessor(decimated.indices, "SCALAR");
1051
+ this.meshes.push({ name: `LOD${ratio}_mesh${mi}`, primitives: [lodPrim] });
1052
+ lodIds.push(lodMeshIndex);
1053
+ }
1054
+ }
1055
+ if (lodIds.length > 0) {
1056
+ mesh["extensions"] = {
1057
+ MSFT_lod: { ids: lodIds }
1058
+ };
1059
+ coverages.push(0.5, 0.2);
1060
+ }
1061
+ }
1062
+ if (coverages.length > 0) {
1063
+ this._lodCoverages = coverages;
1064
+ }
1065
+ }
1066
+ /**
1067
+ * Build skeleton hierarchy and embed as glTF skin.
1068
+ * Creates 20 joint nodes with inverse bind matrices.
1069
+ */
1070
+ buildSkeleton() {
1071
+ const bones = DRAGON_SKELETON;
1072
+ const boneNameToIdx = /* @__PURE__ */ new Map();
1073
+ const jointStartIndex = this.nodes.length;
1074
+ for (let i = 0; i < bones.length; i++) {
1075
+ const bone = bones[i];
1076
+ const nodeIdx = this.nodes.length;
1077
+ boneNameToIdx.set(bone.name, nodeIdx);
1078
+ const node = {
1079
+ name: `Joint_${bone.name}`,
1080
+ translation: bone.position
1081
+ };
1082
+ this.nodes.push(node);
1083
+ }
1084
+ for (const bone of bones) {
1085
+ if (bone.parent) {
1086
+ const parentIdx = boneNameToIdx.get(bone.parent);
1087
+ const childIdx = boneNameToIdx.get(bone.name);
1088
+ if (parentIdx !== void 0 && childIdx !== void 0) {
1089
+ const parentNode = this.nodes[parentIdx];
1090
+ if (!parentNode.children) parentNode.children = [];
1091
+ parentNode.children.push(childIdx);
1092
+ }
1093
+ }
1094
+ }
1095
+ const ibmData = new Float32Array(bones.length * 16);
1096
+ for (let i = 0; i < bones.length; i++) {
1097
+ const p = bones[i].position;
1098
+ const off = i * 16;
1099
+ ibmData[off + 0] = 1;
1100
+ ibmData[off + 5] = 1;
1101
+ ibmData[off + 10] = 1;
1102
+ ibmData[off + 15] = 1;
1103
+ ibmData[off + 12] = -p[0];
1104
+ ibmData[off + 13] = -p[1];
1105
+ ibmData[off + 14] = -p[2];
1106
+ }
1107
+ const ibmAccessor = this.createAccessorRaw(ibmData, "MAT4", 5126);
1108
+ const joints = [];
1109
+ for (let i = 0; i < bones.length; i++) {
1110
+ joints.push(jointStartIndex + i);
1111
+ }
1112
+ this._skins = [
1113
+ {
1114
+ skeleton: jointStartIndex,
1115
+ joints,
1116
+ inverseBindMatrices: ibmAccessor
1117
+ }
1118
+ ];
1119
+ this._jointStartIndex = jointStartIndex;
1120
+ }
1121
+ /**
1122
+ * Skin all mesh nodes to the skeleton.
1123
+ * For each vertex, finds the 4 nearest bones by distance and assigns
1124
+ * normalized inverse-distance weights. Writes JOINTS_0 (Uint8) and
1125
+ * WEIGHTS_0 (Float32) attributes into each mesh primitive.
1126
+ */
1127
+ skinMeshes() {
1128
+ if (!this._skins || this._skins.length === 0) return;
1129
+ const bones = DRAGON_SKELETON;
1130
+ const bonePositions = bones.map((b) => b.position);
1131
+ const originalNodeCount = this._jointStartIndex;
1132
+ for (let ni = 0; ni < originalNodeCount; ni++) {
1133
+ const node = this.nodes[ni];
1134
+ if (node.mesh === void 0) continue;
1135
+ const mesh = this.meshes[node.mesh];
1136
+ if (!mesh) continue;
1137
+ for (const prim of mesh.primitives) {
1138
+ const posIdx = prim.attributes.POSITION;
1139
+ if (posIdx === void 0) continue;
1140
+ const posAcc = this.accessors[posIdx];
1141
+ if (!posAcc) continue;
1142
+ const posBV = this.bufferViews[posAcc.bufferView];
1143
+ if (!posBV) continue;
1144
+ const vCount = posAcc.count;
1145
+ if (vCount === 0) continue;
1146
+ const tx = node.translation ? node.translation[0] : 0;
1147
+ const ty = node.translation ? node.translation[1] : 0;
1148
+ const tz = node.translation ? node.translation[2] : 0;
1149
+ const jointsData = new Uint8Array(vCount * 4);
1150
+ const weightsData = new Float32Array(vCount * 4);
1151
+ for (let vi = 0; vi < vCount; vi++) {
1152
+ const pOff = posBV.byteOffset + vi * 12;
1153
+ const vx = this.readFloat32(pOff) + tx;
1154
+ const vy = this.readFloat32(pOff + 4) + ty;
1155
+ const vz = this.readFloat32(pOff + 8) + tz;
1156
+ const distances = [];
1157
+ for (let bi = 0; bi < bonePositions.length; bi++) {
1158
+ const bp = bonePositions[bi];
1159
+ const dx = vx - bp[0], dy = vy - bp[1], dz = vz - bp[2];
1160
+ distances.push({ boneIdx: bi, distSq: dx * dx + dy * dy + dz * dz });
1161
+ }
1162
+ distances.sort((a, b) => a.distSq - b.distSq);
1163
+ const top4 = distances.slice(0, 4);
1164
+ let totalWeight = 0;
1165
+ const rawWeights = [];
1166
+ for (const d of top4) {
1167
+ const w = 1 / (d.distSq + 1e-4);
1168
+ rawWeights.push(w);
1169
+ totalWeight += w;
1170
+ }
1171
+ const off = vi * 4;
1172
+ for (let j = 0; j < 4; j++) {
1173
+ if (j < top4.length) {
1174
+ jointsData[off + j] = top4[j].boneIdx;
1175
+ weightsData[off + j] = rawWeights[j] / totalWeight;
1176
+ } else {
1177
+ jointsData[off + j] = 0;
1178
+ weightsData[off + j] = 0;
1179
+ }
1180
+ }
1181
+ }
1182
+ prim.attributes.JOINTS_0 = this.createAccessorRaw(jointsData, "VEC4", 5121);
1183
+ prim.attributes.WEIGHTS_0 = this.createAccessor(weightsData, "VEC4");
1184
+ }
1185
+ }
1186
+ }
1187
+ /**
1188
+ * Compile a HoloScript composition to glTF format
1189
+ */
1190
+ compile(composition, agentToken, outputPath) {
1191
+ this.validateCompilerAccess(agentToken, outputPath);
1192
+ this.reset();
1193
+ this.processComposition(composition);
1194
+ this.smoothNormalsGlobal();
1195
+ this.generateLODs();
1196
+ this.buildSkeleton();
1197
+ this.skinMeshes();
1198
+ const buffer = this.bufferData.slice(0, this.bufferByteLength);
1199
+ if (SHARED_COMPILE_BUFFER.length > MAX_RETAINED_BUFFER_SIZE) {
1200
+ SHARED_COMPILE_BUFFER = new Uint8Array(INITIAL_COMPILE_BUFFER_SIZE);
1201
+ }
1202
+ const gltf = this.buildDocument(composition, buffer.byteLength);
1203
+ if (this.options.format === "glb") {
1204
+ const binary = this.createGLB(gltf, buffer);
1205
+ this.stats.fileSizeBytes = binary.byteLength;
1206
+ return {
1207
+ binary,
1208
+ stats: { ...this.stats }
1209
+ };
1210
+ } else {
1211
+ this.stats.fileSizeBytes = JSON.stringify(gltf).length + buffer.byteLength;
1212
+ return {
1213
+ json: gltf,
1214
+ buffer,
1215
+ stats: { ...this.stats }
1216
+ };
1217
+ }
1218
+ }
1219
+ /**
1220
+ * Reset pipeline state for new compilation
1221
+ */
1222
+ reset() {
1223
+ this.bufferByteLength = 0;
1224
+ this.accessors = [];
1225
+ this.bufferViews = [];
1226
+ this.meshes = [];
1227
+ this.materials = [];
1228
+ this.nodes = [];
1229
+ this.scenes = [];
1230
+ this.animations = [];
1231
+ this.materialMap.clear();
1232
+ this.images = [];
1233
+ this.textures = [];
1234
+ this.samplers = [];
1235
+ this.scaleTextureIndex = -1;
1236
+ this.scaleNormalTextureIndex = -1;
1237
+ this.textureIndexMap.clear();
1238
+ this.stats = {
1239
+ nodeCount: 0,
1240
+ meshCount: 0,
1241
+ materialCount: 0,
1242
+ textureCount: 0,
1243
+ animationCount: 0,
1244
+ totalVertices: 0,
1245
+ totalTriangles: 0,
1246
+ fileSizeBytes: 0
1247
+ };
1248
+ }
1249
+ /**
1250
+ * Process the entire composition
1251
+ */
1252
+ processComposition(composition) {
1253
+ const rootNodes = [];
1254
+ for (const object of composition.objects || []) {
1255
+ const nodeIndex = this.processObject(object);
1256
+ if (nodeIndex !== -1) {
1257
+ rootNodes.push(nodeIndex);
1258
+ }
1259
+ }
1260
+ for (const group of composition.spatialGroups || []) {
1261
+ const nodeIndex = this.processSpatialGroup(group);
1262
+ if (nodeIndex !== -1) {
1263
+ rootNodes.push(nodeIndex);
1264
+ }
1265
+ }
1266
+ for (const light of composition.lights || []) {
1267
+ const nodeIndex = this.processLight(light);
1268
+ if (nodeIndex !== -1) {
1269
+ rootNodes.push(nodeIndex);
1270
+ }
1271
+ }
1272
+ if (composition.camera) {
1273
+ const nodeIndex = this.processCamera(composition.camera);
1274
+ if (nodeIndex !== -1) {
1275
+ rootNodes.push(nodeIndex);
1276
+ }
1277
+ }
1278
+ for (const timeline of composition.timelines || []) {
1279
+ this.processTimeline(timeline);
1280
+ }
1281
+ const domainBlocks = composition.domainBlocks ?? [];
1282
+ if (domainBlocks.length > 0) {
1283
+ compileDomainBlocks(
1284
+ domainBlocks,
1285
+ {
1286
+ material: (block) => {
1287
+ const mat = compileMaterialBlock(block);
1288
+ const gltfMat = materialToGLTF(mat);
1289
+ this.materials.push(gltfMat);
1290
+ this.stats.materialCount++;
1291
+ return "";
1292
+ }
1293
+ },
1294
+ () => ""
1295
+ );
1296
+ }
1297
+ this.scenes.push({
1298
+ name: composition.name,
1299
+ nodes: rootNodes
1300
+ });
1301
+ }
1302
+ /**
1303
+ * Process a single object
1304
+ */
1305
+ processObject(object) {
1306
+ const position = this.extractVec3Prop(object, "position", [0, 0, 0]);
1307
+ const rotation = this.extractVec3Prop(object, "rotation", [0, 0, 0]);
1308
+ const scale = this.extractVec3Prop(object, "scale", [1, 1, 1]);
1309
+ const geometryProp = this.findProp(object, "geometry") || this.findProp(object, "mesh") || this.findProp(object, "type");
1310
+ const shapeType = (typeof geometryProp === "string" ? geometryProp : "box").toLowerCase();
1311
+ let meshIndex;
1312
+ if (PRIMITIVE_GENERATORS[shapeType]) {
1313
+ meshIndex = this.createPrimitiveMesh(object.name, shapeType, scale, object);
1314
+ } else if (ADVANCED_GEOMETRY_TYPES.has(shapeType)) {
1315
+ meshIndex = this.createAdvancedMesh(object.name, shapeType, scale, object);
1316
+ }
1317
+ const node = gltfNodePool.acquire();
1318
+ node.name = object.name || `node_${this.nodes.length}`;
1319
+ node.translation = position;
1320
+ node.rotation = this.eulerToQuaternion(rotation);
1321
+ node.scale = [1, 1, 1];
1322
+ if (meshIndex !== void 0) {
1323
+ node.mesh = meshIndex;
1324
+ }
1325
+ if (object.children && object.children.length > 0) {
1326
+ const childIndices = [];
1327
+ for (const child of object.children) {
1328
+ const childIdx = this.processObject(child);
1329
+ if (childIdx !== -1) childIndices.push(childIdx);
1330
+ }
1331
+ if (childIndices.length > 0) node.children = childIndices;
1332
+ }
1333
+ const nodeIndex = this.nodes.length;
1334
+ this.nodes.push(node);
1335
+ this.stats.nodeCount++;
1336
+ return nodeIndex;
1337
+ }
1338
+ /**
1339
+ * Process a spatial group
1340
+ */
1341
+ processSpatialGroup(group) {
1342
+ const childIndices = [];
1343
+ for (const child of group.objects || []) {
1344
+ const childIndex = this.processObject(child);
1345
+ if (childIndex !== -1) {
1346
+ childIndices.push(childIndex);
1347
+ }
1348
+ }
1349
+ if (group.groups) {
1350
+ for (const sub of group.groups) {
1351
+ const subIdx = this.processSpatialGroup(sub);
1352
+ if (subIdx !== -1) childIndices.push(subIdx);
1353
+ }
1354
+ }
1355
+ const posProp = (group.properties || []).find((p) => p.key === "position");
1356
+ const position = posProp && Array.isArray(posProp.value) ? [
1357
+ Number(posProp.value[0]) || 0,
1358
+ Number(posProp.value[1]) || 0,
1359
+ Number(posProp.value[2]) || 0
1360
+ ] : [0, 0, 0];
1361
+ const node = gltfNodePool.acquire();
1362
+ node.name = group.name || `group_${this.nodes.length}`;
1363
+ node.translation = position;
1364
+ if (childIndices.length > 0) {
1365
+ node.children = childIndices;
1366
+ }
1367
+ const nodeIndex = this.nodes.length;
1368
+ this.nodes.push(node);
1369
+ this.stats.nodeCount++;
1370
+ return nodeIndex;
1371
+ }
1372
+ /**
1373
+ * Process a timeline as animation.
1374
+ *
1375
+ * HoloTimeline has entries: HoloTimelineEntry[] where each entry has
1376
+ * { time: number, action: HoloTimelineAction }.
1377
+ * We extract 'animate' actions and group them by target + property.
1378
+ */
1379
+ processTimeline(timeline) {
1380
+ if (!timeline.entries || timeline.entries.length === 0) return;
1381
+ const animateEntries = timeline.entries.filter((e) => e.action.kind === "animate").map((e) => ({
1382
+ time: e.time,
1383
+ target: e.action.target,
1384
+ properties: e.action.properties
1385
+ }));
1386
+ if (animateEntries.length === 0) return;
1387
+ const channels = [];
1388
+ const samplers = [];
1389
+ const grouped = /* @__PURE__ */ new Map();
1390
+ for (const entry of animateEntries) {
1391
+ const targetNodeIndex = this.nodes.findIndex((n) => n.name === entry.target);
1392
+ if (targetNodeIndex === -1) continue;
1393
+ for (const [prop, value] of Object.entries(entry.properties)) {
1394
+ const gltfPath = this.mapPropertyToGLTFPath(prop);
1395
+ if (!gltfPath) continue;
1396
+ const key = `${targetNodeIndex}:${gltfPath}`;
1397
+ if (!grouped.has(key)) grouped.set(key, []);
1398
+ grouped.get(key).push({ time: entry.time, value });
1399
+ }
1400
+ }
1401
+ for (const [key, keyframes] of grouped) {
1402
+ const [nodeIdxStr, gltfPath] = key.split(":");
1403
+ const nodeIdx = parseInt(nodeIdxStr, 10);
1404
+ const times = keyframes.map((kf) => kf.time / 1e3);
1405
+ const inputAccessor = this.createAccessor(new Float32Array(times), "SCALAR");
1406
+ const values = [];
1407
+ for (const kf of keyframes) {
1408
+ if (Array.isArray(kf.value)) {
1409
+ if (gltfPath === "rotation") {
1410
+ const quat = this.eulerToQuaternion(kf.value);
1411
+ values.push(...quat);
1412
+ } else {
1413
+ values.push(...kf.value);
1414
+ }
1415
+ }
1416
+ }
1417
+ const outputType = gltfPath === "rotation" ? "VEC4" : "VEC3";
1418
+ const outputAccessor = this.createAccessor(new Float32Array(values), outputType);
1419
+ const samplerIndex = samplers.length;
1420
+ samplers.push({ input: inputAccessor, interpolation: "LINEAR", output: outputAccessor });
1421
+ channels.push({ sampler: samplerIndex, target: { node: nodeIdx, path: gltfPath } });
1422
+ }
1423
+ if (channels.length > 0) {
1424
+ this.animations.push({
1425
+ name: timeline.name || `animation_${this.animations.length}`,
1426
+ channels,
1427
+ samplers
1428
+ });
1429
+ this.stats.animationCount++;
1430
+ }
1431
+ }
1432
+ /**
1433
+ * Create a primitive mesh
1434
+ */
1435
+ createPrimitiveMesh(name, shapeType, scale, object) {
1436
+ const generator = PRIMITIVE_GENERATORS[shapeType];
1437
+ if (!generator) return -1;
1438
+ const geometry = generator(scale);
1439
+ const positionAccessor = this.createAccessor(geometry.positions, "VEC3", true);
1440
+ const normalAccessor = this.createAccessor(geometry.normals, "VEC3");
1441
+ const uvAccessor = this.createAccessor(geometry.uvs, "VEC2");
1442
+ const indexAccessor = this.createAccessor(geometry.indices, "SCALAR");
1443
+ const materialIndex = this.getOrCreateMaterial(object, shapeType);
1444
+ const mesh = {
1445
+ name: name || `mesh_${this.meshes.length}`,
1446
+ primitives: [
1447
+ {
1448
+ attributes: {
1449
+ POSITION: positionAccessor,
1450
+ NORMAL: normalAccessor,
1451
+ TEXCOORD_0: uvAccessor
1452
+ },
1453
+ indices: indexAccessor,
1454
+ material: materialIndex,
1455
+ mode: 4
1456
+ // TRIANGLES
1457
+ }
1458
+ ]
1459
+ };
1460
+ const meshIndex = this.meshes.length;
1461
+ this.meshes.push(mesh);
1462
+ this.stats.meshCount++;
1463
+ this.stats.totalVertices += geometry.positions.length / 3;
1464
+ this.stats.totalTriangles += geometry.indices.length / 3;
1465
+ return meshIndex;
1466
+ }
1467
+ /**
1468
+ * Create an advanced mesh (spline, membrane, hull/metaball).
1469
+ * These geometry types need additional properties beyond scale.
1470
+ */
1471
+ createAdvancedMesh(name, shapeType, scale, object) {
1472
+ let geometry;
1473
+ switch (shapeType) {
1474
+ case "spline": {
1475
+ const pointsProp = this.findProp(object, "points");
1476
+ const radiiProp = this.findProp(object, "radii");
1477
+ const segmentsProp = this.findProp(object, "segments");
1478
+ const stepsProp = this.findProp(object, "steps");
1479
+ const points = this.extractNestedArray(pointsProp, 3);
1480
+ const radii = Array.isArray(radiiProp) ? radiiProp.map(Number) : [0.1];
1481
+ while (radii.length < points.length) {
1482
+ radii.push(radii[radii.length - 1] ?? 0.1);
1483
+ }
1484
+ const radialSegments = typeof segmentsProp === "number" ? segmentsProp : 24;
1485
+ const lengthSteps = typeof stepsProp === "number" ? stepsProp : 8;
1486
+ geometry = generateSplineGeometry(points, radii, radialSegments, lengthSteps);
1487
+ break;
1488
+ }
1489
+ case "membrane": {
1490
+ const anchorsProp = this.findProp(object, "anchors");
1491
+ const subdivisionsProp = this.findProp(object, "subdivisions");
1492
+ const bulgeProp = this.findProp(object, "bulge");
1493
+ const anchors = this.extractNestedArray(anchorsProp, 3);
1494
+ const subdivisions = typeof subdivisionsProp === "number" ? subdivisionsProp : 8;
1495
+ const bulge = typeof bulgeProp === "number" ? bulgeProp : 0.15;
1496
+ geometry = generateMembraneGeometry(anchors, subdivisions, bulge);
1497
+ break;
1498
+ }
1499
+ case "hull":
1500
+ case "blob":
1501
+ case "metaball": {
1502
+ const blobsProp = this.findProp(object, "blobs");
1503
+ const resolutionProp = this.findProp(object, "resolution");
1504
+ const thresholdProp = this.findProp(object, "threshold");
1505
+ const blobs = [];
1506
+ if (Array.isArray(blobsProp)) {
1507
+ for (const blobItem of blobsProp) {
1508
+ if (blobItem && typeof blobItem === "object") {
1509
+ const b = blobItem;
1510
+ const center = Array.isArray(b.center) ? b.center.map(Number) : [0, 0, 0];
1511
+ const radius = Array.isArray(b.radius) ? b.radius.map(Number) : [0.5, 0.5, 0.5];
1512
+ blobs.push({ center, radius });
1513
+ }
1514
+ }
1515
+ }
1516
+ if (blobs.length === 0) {
1517
+ blobs.push({
1518
+ center: [0, 0, 0],
1519
+ radius: [scale[0] * 0.5, scale[1] * 0.5, scale[2] * 0.5]
1520
+ });
1521
+ }
1522
+ const resolution = typeof resolutionProp === "number" ? resolutionProp : 24;
1523
+ const threshold = typeof thresholdProp === "number" ? thresholdProp : 1;
1524
+ geometry = generateHullGeometry(blobs, resolution, threshold);
1525
+ break;
1526
+ }
1527
+ default:
1528
+ return -1;
1529
+ }
1530
+ const positionAccessor = this.createAccessor(geometry.positions, "VEC3", true);
1531
+ const normalAccessor = this.createAccessor(geometry.normals, "VEC3");
1532
+ const uvAccessor = this.createAccessor(geometry.uvs, "VEC2");
1533
+ const indexAccessor = this.createAccessor(geometry.indices, "SCALAR");
1534
+ const materialIndex = this.getOrCreateMaterial(object, shapeType);
1535
+ const mesh = {
1536
+ name: name || `mesh_${this.meshes.length}`,
1537
+ primitives: [
1538
+ {
1539
+ attributes: {
1540
+ POSITION: positionAccessor,
1541
+ NORMAL: normalAccessor,
1542
+ TEXCOORD_0: uvAccessor
1543
+ },
1544
+ indices: indexAccessor,
1545
+ material: materialIndex,
1546
+ mode: 4
1547
+ // TRIANGLES
1548
+ }
1549
+ ]
1550
+ };
1551
+ const meshIndex = this.meshes.length;
1552
+ this.meshes.push(mesh);
1553
+ this.stats.meshCount++;
1554
+ this.stats.totalVertices += geometry.positions.length / 3;
1555
+ this.stats.totalTriangles += geometry.indices.length / 3;
1556
+ return meshIndex;
1557
+ }
1558
+ /**
1559
+ * Extract a nested array of vec3s from a HoloValue.
1560
+ * e.g. [[0, 1, 2], [3, 4, 5]] => [[0,1,2], [3,4,5]]
1561
+ */
1562
+ extractNestedArray(val, expectedLength) {
1563
+ const result = [];
1564
+ if (!Array.isArray(val)) return result;
1565
+ for (const item of val) {
1566
+ if (Array.isArray(item) && item.length >= expectedLength) {
1567
+ result.push(item.slice(0, expectedLength).map(Number));
1568
+ }
1569
+ }
1570
+ return result;
1571
+ }
1572
+ /**
1573
+ * Get or create a material from object properties + traits.
1574
+ *
1575
+ * Material composition order (later overrides earlier):
1576
+ * 1. Defaults (white, metallic 0, roughness 0.5)
1577
+ * 2. Named material preset (e.g., material: "glass")
1578
+ * 3. TraitCompositor output (PBR from visual presets)
1579
+ * 4. Direct property overrides (color, opacity)
1580
+ */
1581
+ getOrCreateMaterial(object, shapeType) {
1582
+ let color = [1, 1, 1];
1583
+ let metallic = 0;
1584
+ let roughness = 0.5;
1585
+ let opacity = 1;
1586
+ let emissive = [0, 0, 0];
1587
+ let transmission = 0;
1588
+ let ior = 1.5;
1589
+ let thickness = 0;
1590
+ let clearcoat = 0;
1591
+ let clearcoatRoughness = 0;
1592
+ let sheen = 0;
1593
+ let sheenRoughness = 0.5;
1594
+ let sheenColor = [1, 1, 1];
1595
+ let iridescence = 0;
1596
+ let iridescenceIOR = 1.3;
1597
+ let anisotropy = 0;
1598
+ let anisotropyRotation = 0;
1599
+ let attenuationColor;
1600
+ let attenuationDistance;
1601
+ const namedMat = this.findProp(object, "material");
1602
+ if (typeof namedMat === "string" && MATERIAL_PRESETS[namedMat]) {
1603
+ const preset = MATERIAL_PRESETS[namedMat];
1604
+ if (preset.color) color = this.parseColorString(preset.color);
1605
+ if (preset.metalness !== void 0) metallic = preset.metalness;
1606
+ if (preset.roughness !== void 0) roughness = preset.roughness;
1607
+ if (preset.opacity !== void 0) opacity = preset.opacity;
1608
+ if (preset.transparent && opacity >= 1) opacity = 0.99;
1609
+ if (preset.emissive) emissive = this.parseColorString(preset.emissive);
1610
+ if (preset.transmission !== void 0) transmission = preset.transmission;
1611
+ if (preset.ior !== void 0) ior = preset.ior;
1612
+ if (preset.thickness !== void 0) thickness = preset.thickness;
1613
+ if (preset.clearcoat !== void 0) clearcoat = preset.clearcoat;
1614
+ if (preset.clearcoatRoughness !== void 0) clearcoatRoughness = preset.clearcoatRoughness;
1615
+ if (preset.sheen !== void 0) sheen = preset.sheen;
1616
+ if (preset.sheenRoughness !== void 0) sheenRoughness = preset.sheenRoughness;
1617
+ if (preset.sheenColor) sheenColor = this.parseColorString(preset.sheenColor);
1618
+ if (preset.iridescence !== void 0) iridescence = preset.iridescence;
1619
+ if (preset.iridescenceIOR !== void 0) iridescenceIOR = preset.iridescenceIOR;
1620
+ if (preset.anisotropy !== void 0) anisotropy = preset.anisotropy;
1621
+ if (preset.anisotropyRotation !== void 0) anisotropyRotation = preset.anisotropyRotation;
1622
+ if (preset.attenuationColor)
1623
+ attenuationColor = this.parseColorString(preset.attenuationColor);
1624
+ if (preset.attenuationDistance !== void 0)
1625
+ attenuationDistance = preset.attenuationDistance;
1626
+ }
1627
+ const traitNames = (object.traits || []).map((t) => t.name);
1628
+ if (traitNames.length > 0) {
1629
+ const composed = this.compositor.compose(traitNames);
1630
+ if (composed.color) color = this.parseColorString(composed.color);
1631
+ if (composed.metalness !== void 0) metallic = composed.metalness;
1632
+ if (composed.roughness !== void 0) roughness = composed.roughness;
1633
+ if (composed.opacity !== void 0) opacity = composed.opacity;
1634
+ if (composed.emissive) emissive = this.parseColorString(composed.emissive);
1635
+ if (composed.transparent) opacity = Math.min(opacity, 0.9);
1636
+ if (composed.transmission !== void 0) transmission = composed.transmission;
1637
+ if (composed.ior !== void 0) ior = composed.ior;
1638
+ if (composed.thickness !== void 0) thickness = composed.thickness;
1639
+ if (composed.clearcoat !== void 0) clearcoat = composed.clearcoat;
1640
+ if (composed.clearcoatRoughness !== void 0)
1641
+ clearcoatRoughness = composed.clearcoatRoughness;
1642
+ if (composed.sheen !== void 0) sheen = composed.sheen;
1643
+ if (composed.sheenRoughness !== void 0) sheenRoughness = composed.sheenRoughness;
1644
+ if (composed.sheenColor) sheenColor = this.parseColorString(composed.sheenColor);
1645
+ if (composed.iridescence !== void 0) iridescence = composed.iridescence;
1646
+ if (composed.iridescenceIOR !== void 0) iridescenceIOR = composed.iridescenceIOR;
1647
+ if (composed.anisotropy !== void 0) anisotropy = composed.anisotropy;
1648
+ if (composed.anisotropyRotation !== void 0)
1649
+ anisotropyRotation = composed.anisotropyRotation;
1650
+ if (composed.attenuationColor)
1651
+ attenuationColor = this.parseColorString(composed.attenuationColor);
1652
+ if (composed.attenuationDistance !== void 0)
1653
+ attenuationDistance = composed.attenuationDistance;
1654
+ }
1655
+ const colorProp = this.findProp(object, "color");
1656
+ if (typeof colorProp === "string") {
1657
+ color = this.parseColorString(colorProp);
1658
+ } else if (Array.isArray(colorProp) && colorProp.length >= 3) {
1659
+ color = [Number(colorProp[0]), Number(colorProp[1]), Number(colorProp[2])];
1660
+ }
1661
+ const opacityProp = this.findProp(object, "opacity");
1662
+ if (typeof opacityProp === "number") opacity = opacityProp;
1663
+ const metallicProp = this.findProp(object, "metallic") ?? this.findProp(object, "metalness");
1664
+ if (typeof metallicProp === "number") metallic = metallicProp;
1665
+ const roughnessProp = this.findProp(object, "roughness");
1666
+ if (typeof roughnessProp === "number") roughness = roughnessProp;
1667
+ const emissiveIntensityProp = this.findProp(object, "emissiveIntensity");
1668
+ const emissiveIntensity = typeof emissiveIntensityProp === "number" ? emissiveIntensityProp : 1;
1669
+ const emissiveProp = this.findProp(object, "emissive");
1670
+ if (typeof emissiveProp === "string") emissive = this.parseColorString(emissiveProp);
1671
+ const transmissionProp = this.findProp(object, "transmission");
1672
+ if (typeof transmissionProp === "number") transmission = transmissionProp;
1673
+ const iorProp = this.findProp(object, "ior");
1674
+ if (typeof iorProp === "number") ior = iorProp;
1675
+ const clearcoatProp = this.findProp(object, "clearcoat");
1676
+ if (typeof clearcoatProp === "number") clearcoat = clearcoatProp;
1677
+ const texturePaths = {};
1678
+ const TEX_PROP_MAP = {
1679
+ // HoloScript property name → glTF slot key
1680
+ baseColorMap: "baseColor",
1681
+ albedo_map: "baseColor",
1682
+ colorMap: "baseColor",
1683
+ normalMap: "normal",
1684
+ normal_map: "normal",
1685
+ roughnessMap: "metallicRoughness",
1686
+ roughness_map: "metallicRoughness",
1687
+ metallicMap: "metallicRoughness",
1688
+ metallic_map: "metallicRoughness",
1689
+ metalnessMap: "metallicRoughness",
1690
+ occlusionMap: "occlusion",
1691
+ ao_map: "occlusion",
1692
+ ambientOcclusionMap: "occlusion",
1693
+ emissiveMap: "emissive",
1694
+ emissive_map: "emissive",
1695
+ emissionMap: "emissive"
1696
+ };
1697
+ for (const [propName, slotKey] of Object.entries(TEX_PROP_MAP)) {
1698
+ const val = this.findProp(object, propName);
1699
+ if (typeof val === "string" && val.length > 0 && !texturePaths[slotKey]) {
1700
+ texturePaths[slotKey] = val;
1701
+ }
1702
+ }
1703
+ const key = JSON.stringify({
1704
+ color,
1705
+ metallic,
1706
+ roughness,
1707
+ opacity,
1708
+ emissive,
1709
+ transmission,
1710
+ ior,
1711
+ thickness,
1712
+ clearcoat,
1713
+ clearcoatRoughness,
1714
+ sheen,
1715
+ sheenRoughness,
1716
+ sheenColor,
1717
+ iridescence,
1718
+ iridescenceIOR,
1719
+ anisotropy,
1720
+ anisotropyRotation,
1721
+ attenuationColor,
1722
+ attenuationDistance,
1723
+ texturePaths
1724
+ });
1725
+ if (this.materialMap.has(key)) {
1726
+ return this.materialMap.get(key);
1727
+ }
1728
+ const material = {
1729
+ name: `material_${this.materials.length}`,
1730
+ pbrMetallicRoughness: {
1731
+ baseColorFactor: [...color, opacity],
1732
+ metallicFactor: metallic,
1733
+ roughnessFactor: roughness
1734
+ },
1735
+ doubleSided: opacity < 1 || transmission > 0
1736
+ };
1737
+ if (opacity < 1 || transmission > 0) {
1738
+ material.alphaMode = "BLEND";
1739
+ }
1740
+ const emissiveSum = emissive[0] + emissive[1] + emissive[2];
1741
+ if (emissiveSum > 0) {
1742
+ material.emissiveFactor = emissive.map((c) => c * emissiveIntensity);
1743
+ }
1744
+ const extensions = {};
1745
+ if (transmission > 0) {
1746
+ Object.assign(extensions, createTransmissionExtension(transmission));
1747
+ }
1748
+ if (ior !== 1.5) {
1749
+ Object.assign(extensions, createIORExtension(ior));
1750
+ }
1751
+ if (clearcoat > 0) {
1752
+ Object.assign(
1753
+ extensions,
1754
+ createClearcoatExtension({ factor: clearcoat, roughness: clearcoatRoughness })
1755
+ );
1756
+ }
1757
+ if (sheen > 0) {
1758
+ Object.assign(
1759
+ extensions,
1760
+ createSheenExtension({ color: sheenColor, roughness: sheenRoughness })
1761
+ );
1762
+ }
1763
+ if (iridescence > 0) {
1764
+ Object.assign(
1765
+ extensions,
1766
+ createIridescenceExtension({ factor: iridescence, ior: iridescenceIOR })
1767
+ );
1768
+ }
1769
+ if (anisotropy > 0) {
1770
+ Object.assign(
1771
+ extensions,
1772
+ createAnisotropyExtension({ strength: anisotropy, rotation: anisotropyRotation })
1773
+ );
1774
+ }
1775
+ if (thickness > 0 || attenuationDistance !== void 0) {
1776
+ Object.assign(
1777
+ extensions,
1778
+ createVolumeExtension({
1779
+ thickness: thickness || 1,
1780
+ attenuationDistance,
1781
+ attenuationColor
1782
+ })
1783
+ );
1784
+ }
1785
+ if (emissiveIntensity > 1) {
1786
+ Object.assign(extensions, createEmissiveStrengthExtension(emissiveIntensity));
1787
+ }
1788
+ if (Object.keys(extensions).length > 0) {
1789
+ material.extensions = extensions;
1790
+ }
1791
+ const isScaledGeometry = shapeType === "hull" || shapeType === "metaball";
1792
+ const isScaledMaterial = typeof namedMat === "string" && (namedMat === "skin_dark" || namedMat === "leather");
1793
+ if (isScaledGeometry || isScaledMaterial) {
1794
+ const texIdx = this.ensureScaleTexture();
1795
+ if (texIdx >= 0) {
1796
+ material.pbrMetallicRoughness.baseColorTexture = {
1797
+ index: texIdx,
1798
+ texCoord: 0
1799
+ };
1800
+ if (this.scaleNormalTextureIndex >= 0) {
1801
+ material.normalTexture = {
1802
+ index: this.scaleNormalTextureIndex,
1803
+ texCoord: 0,
1804
+ scale: 1
1805
+ };
1806
+ }
1807
+ this.stats.textureCount = 2;
1808
+ }
1809
+ }
1810
+ if (Object.keys(texturePaths).length > 0) {
1811
+ const pbr = material.pbrMetallicRoughness;
1812
+ if (texturePaths.baseColor && !pbr.baseColorTexture) {
1813
+ const idx = this.getOrCreateExternalTexture(texturePaths.baseColor);
1814
+ if (idx >= 0) pbr.baseColorTexture = { index: idx, texCoord: 0 };
1815
+ }
1816
+ if (texturePaths.metallicRoughness && !pbr.metallicRoughnessTexture) {
1817
+ const idx = this.getOrCreateExternalTexture(texturePaths.metallicRoughness);
1818
+ if (idx >= 0) pbr.metallicRoughnessTexture = { index: idx, texCoord: 0 };
1819
+ }
1820
+ const matRecord = material;
1821
+ if (texturePaths.normal && !matRecord.normalTexture) {
1822
+ const idx = this.getOrCreateExternalTexture(texturePaths.normal);
1823
+ if (idx >= 0) matRecord.normalTexture = { index: idx, texCoord: 0, scale: 1 };
1824
+ }
1825
+ if (texturePaths.occlusion && !matRecord.occlusionTexture) {
1826
+ const idx = this.getOrCreateExternalTexture(texturePaths.occlusion);
1827
+ if (idx >= 0) matRecord.occlusionTexture = { index: idx, texCoord: 0, strength: 1 };
1828
+ }
1829
+ if (texturePaths.emissive && !matRecord.emissiveTexture) {
1830
+ const idx = this.getOrCreateExternalTexture(texturePaths.emissive);
1831
+ if (idx >= 0) matRecord.emissiveTexture = { index: idx, texCoord: 0 };
1832
+ }
1833
+ }
1834
+ const materialIndex = this.materials.length;
1835
+ this.materials.push(material);
1836
+ this.materialMap.set(key, materialIndex);
1837
+ this.stats.materialCount++;
1838
+ return materialIndex;
1839
+ }
1840
+ /**
1841
+ * Embed an external texture image in the glTF buffer. Returns the texture
1842
+ * index, or -1 if the image data is not available in options.textureData.
1843
+ * Caches by path so the same image is only embedded once.
1844
+ */
1845
+ getOrCreateExternalTexture(path) {
1846
+ if (this.textureIndexMap.has(path)) {
1847
+ return this.textureIndexMap.get(path);
1848
+ }
1849
+ const imageData = this.options.textureData[path];
1850
+ if (!imageData || imageData.length === 0) {
1851
+ return -1;
1852
+ }
1853
+ const isPNG = imageData[0] === 137 && imageData[1] === 80;
1854
+ const isJPEG = imageData[0] === 255 && imageData[1] === 216;
1855
+ const mimeType = isPNG ? "image/png" : isJPEG ? "image/jpeg" : "image/png";
1856
+ const byteOffset = this.bufferByteLength;
1857
+ this.appendToBuffer(imageData);
1858
+ this.padBuffer(4);
1859
+ const bufferViewIndex = this.bufferViews.length;
1860
+ this.bufferViews.push({
1861
+ buffer: 0,
1862
+ byteOffset,
1863
+ byteLength: imageData.length
1864
+ });
1865
+ const imageIndex = this.images.length;
1866
+ this.images.push({
1867
+ bufferView: bufferViewIndex,
1868
+ mimeType
1869
+ });
1870
+ let samplerIndex;
1871
+ if (this.samplers.length > 0) {
1872
+ samplerIndex = 0;
1873
+ } else {
1874
+ samplerIndex = this.samplers.length;
1875
+ this.samplers.push({
1876
+ magFilter: 9729,
1877
+ // LINEAR
1878
+ minFilter: 9987,
1879
+ // LINEAR_MIPMAP_LINEAR
1880
+ wrapS: 10497,
1881
+ // REPEAT
1882
+ wrapT: 10497
1883
+ // REPEAT
1884
+ });
1885
+ }
1886
+ const textureIndex = this.textures.length;
1887
+ this.textures.push({
1888
+ source: imageIndex,
1889
+ sampler: samplerIndex
1890
+ });
1891
+ this.textureIndexMap.set(path, textureIndex);
1892
+ this.stats.textureCount++;
1893
+ return textureIndex;
1894
+ }
1895
+ /**
1896
+ * Ensure the procedural scale texture is generated and embedded in the glTF.
1897
+ * Returns the texture index, or -1 if generation failed.
1898
+ */
1899
+ ensureScaleTexture() {
1900
+ if (this.scaleTextureIndex >= 0) return this.scaleTextureIndex;
1901
+ const TEX_SIZE = 256;
1902
+ const pixels = generateScaleTexture(TEX_SIZE);
1903
+ const pngData = encodePNG(pixels, TEX_SIZE, TEX_SIZE);
1904
+ const byteOffset = this.bufferByteLength;
1905
+ this.appendToBuffer(pngData);
1906
+ this.padBuffer(4);
1907
+ const bufferViewIndex = this.bufferViews.length;
1908
+ this.bufferViews.push({
1909
+ buffer: 0,
1910
+ byteOffset,
1911
+ byteLength: pngData.length
1912
+ });
1913
+ const imageIndex = this.images.length;
1914
+ this.images.push({
1915
+ bufferView: bufferViewIndex,
1916
+ mimeType: "image/png"
1917
+ });
1918
+ const samplerIndex = this.samplers.length;
1919
+ this.samplers.push({
1920
+ magFilter: 9729,
1921
+ // LINEAR
1922
+ minFilter: 9987,
1923
+ // LINEAR_MIPMAP_LINEAR
1924
+ wrapS: 10497,
1925
+ // REPEAT
1926
+ wrapT: 10497
1927
+ // REPEAT
1928
+ });
1929
+ this.scaleTextureIndex = this.textures.length;
1930
+ this.textures.push({
1931
+ source: imageIndex,
1932
+ sampler: samplerIndex
1933
+ });
1934
+ const normalPixels = generateScaleNormalMap(TEX_SIZE);
1935
+ const normalPng = encodePNG(normalPixels, TEX_SIZE, TEX_SIZE);
1936
+ const normalByteOffset = this.bufferByteLength;
1937
+ this.appendToBuffer(normalPng);
1938
+ this.padBuffer(4);
1939
+ const normalBVIndex = this.bufferViews.length;
1940
+ this.bufferViews.push({
1941
+ buffer: 0,
1942
+ byteOffset: normalByteOffset,
1943
+ byteLength: normalPng.length
1944
+ });
1945
+ const normalImageIndex = this.images.length;
1946
+ this.images.push({
1947
+ bufferView: normalBVIndex,
1948
+ mimeType: "image/png"
1949
+ });
1950
+ this.scaleNormalTextureIndex = this.textures.length;
1951
+ this.textures.push({
1952
+ source: normalImageIndex,
1953
+ sampler: samplerIndex
1954
+ // reuse same sampler
1955
+ });
1956
+ return this.scaleTextureIndex;
1957
+ }
1958
+ /**
1959
+ * Create an accessor with arbitrary type string (e.g., MAT4 for skeleton data, VEC4 for skinning).
1960
+ * Supports Uint8Array for UNSIGNED_BYTE (5121), Uint16Array for UNSIGNED_SHORT (5123),
1961
+ * Uint32Array for UNSIGNED_INT (5125), and Float32Array for FLOAT (5126).
1962
+ */
1963
+ createAccessorRaw(data, type, componentType) {
1964
+ const byteOffset = this.bufferByteLength;
1965
+ const view = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
1966
+ this.appendToBuffer(view);
1967
+ this.padBuffer(4);
1968
+ const bufferViewIndex = this.bufferViews.length;
1969
+ this.bufferViews.push({
1970
+ buffer: 0,
1971
+ byteOffset,
1972
+ byteLength: data.byteLength
1973
+ });
1974
+ const comps = type === "MAT4" ? 16 : type === "VEC4" ? 4 : type === "VEC3" ? 3 : type === "VEC2" ? 2 : 1;
1975
+ const count = data.length / comps;
1976
+ const accessorIndex = this.accessors.length;
1977
+ this.accessors.push({
1978
+ bufferView: bufferViewIndex,
1979
+ componentType,
1980
+ count,
1981
+ type
1982
+ });
1983
+ return accessorIndex;
1984
+ }
1985
+ /**
1986
+ * Create an accessor and buffer view for data
1987
+ */
1988
+ createAccessor(data, type, computeBounds = false) {
1989
+ const byteOffset = this.bufferByteLength;
1990
+ const componentType = data instanceof Uint32Array ? 5125 : data instanceof Uint16Array ? 5123 : 5126;
1991
+ const view = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
1992
+ this.appendToBuffer(view);
1993
+ this.padBuffer(4);
1994
+ const bufferViewIndex = this.bufferViews.length;
1995
+ const bufferView = {
1996
+ buffer: 0,
1997
+ byteOffset,
1998
+ byteLength: data.byteLength
1999
+ };
2000
+ if (componentType === 5126) {
2001
+ bufferView.target = 34962;
2002
+ } else {
2003
+ bufferView.target = 34963;
2004
+ }
2005
+ this.bufferViews.push(bufferView);
2006
+ const componentsPerElement = type === "SCALAR" ? 1 : type === "VEC2" ? 2 : type === "VEC3" ? 3 : 4;
2007
+ const count = data.length / componentsPerElement;
2008
+ const accessor = {
2009
+ bufferView: bufferViewIndex,
2010
+ componentType,
2011
+ count,
2012
+ type
2013
+ };
2014
+ if (computeBounds && type === "VEC3" && data instanceof Float32Array) {
2015
+ const min = [Infinity, Infinity, Infinity];
2016
+ const max = [-Infinity, -Infinity, -Infinity];
2017
+ for (let i = 0; i < data.length; i += 3) {
2018
+ min[0] = Math.min(min[0], data[i]);
2019
+ min[1] = Math.min(min[1], data[i + 1]);
2020
+ min[2] = Math.min(min[2], data[i + 2]);
2021
+ max[0] = Math.max(max[0], data[i]);
2022
+ max[1] = Math.max(max[1], data[i + 1]);
2023
+ max[2] = Math.max(max[2], data[i + 2]);
2024
+ }
2025
+ accessor.min = min;
2026
+ accessor.max = max;
2027
+ }
2028
+ const accessorIndex = this.accessors.length;
2029
+ this.accessors.push(accessor);
2030
+ return accessorIndex;
2031
+ }
2032
+ /**
2033
+ * Build the glTF JSON document
2034
+ */
2035
+ buildDocument(composition, bufferLength) {
2036
+ const name = composition.name;
2037
+ const gltf = {
2038
+ asset: {
2039
+ version: "2.0",
2040
+ generator: this.options.generator
2041
+ },
2042
+ scene: 0,
2043
+ scenes: this.scenes,
2044
+ nodes: this.nodes,
2045
+ meshes: this.meshes,
2046
+ materials: this.materials,
2047
+ accessors: this.accessors,
2048
+ bufferViews: this.bufferViews,
2049
+ buffers: [
2050
+ {
2051
+ byteLength: bufferLength
2052
+ }
2053
+ ]
2054
+ };
2055
+ if (this.options.copyright) {
2056
+ gltf.asset.copyright = this.options.copyright;
2057
+ }
2058
+ if (this.animations.length > 0) {
2059
+ gltf.animations = this.animations;
2060
+ }
2061
+ if (this.images.length > 0) {
2062
+ gltf.images = this.images;
2063
+ gltf.textures = this.textures;
2064
+ gltf.samplers = this.samplers;
2065
+ }
2066
+ if (this._skins && this._skins.length > 0) {
2067
+ gltf.skins = this._skins;
2068
+ }
2069
+ const objectNames = (composition.objects || []).map((o) => o.name);
2070
+ const allTraits = /* @__PURE__ */ new Set();
2071
+ for (const obj of composition.objects || []) {
2072
+ for (const trait of obj.traits || []) {
2073
+ allTraits.add(typeof trait === "string" ? trait : trait.name);
2074
+ }
2075
+ }
2076
+ const groupNames = (composition.spatialGroups || []).map((g) => g.name);
2077
+ gltf.asset.extras = {
2078
+ holoscript: {
2079
+ version: "6.0",
2080
+ compositionName: name,
2081
+ objects: objectNames,
2082
+ traits: [...allTraits],
2083
+ spatialGroups: groupNames,
2084
+ ...this.options.provenanceHash ? { provenanceHash: this.options.provenanceHash } : {}
2085
+ }
2086
+ };
2087
+ declareExtensions(gltf);
2088
+ if (this.options.format === "gltf") {
2089
+ gltf.buffers[0].uri = `${name}.bin`;
2090
+ }
2091
+ return gltf;
2092
+ }
2093
+ /**
2094
+ * Create a GLB binary file
2095
+ */
2096
+ createGLB(gltf, buffer) {
2097
+ const jsonString = JSON.stringify(gltf);
2098
+ const jsonBuffer = new TextEncoder().encode(jsonString);
2099
+ const jsonPadding = (4 - jsonBuffer.byteLength % 4) % 4;
2100
+ const paddedJsonLength = jsonBuffer.byteLength + jsonPadding;
2101
+ const binPadding = (4 - buffer.byteLength % 4) % 4;
2102
+ const paddedBinLength = buffer.byteLength + binPadding;
2103
+ const totalSize = 12 + 8 + paddedJsonLength + 8 + paddedBinLength;
2104
+ const output = new ArrayBuffer(totalSize);
2105
+ const view = new DataView(output);
2106
+ const bytes = new Uint8Array(output);
2107
+ let offset = 0;
2108
+ view.setUint32(offset, 1179937895, true);
2109
+ offset += 4;
2110
+ view.setUint32(offset, 2, true);
2111
+ offset += 4;
2112
+ view.setUint32(offset, totalSize, true);
2113
+ offset += 4;
2114
+ view.setUint32(offset, paddedJsonLength, true);
2115
+ offset += 4;
2116
+ view.setUint32(offset, 1313821514, true);
2117
+ offset += 4;
2118
+ bytes.set(jsonBuffer, offset);
2119
+ offset += jsonBuffer.byteLength;
2120
+ for (let i = 0; i < jsonPadding; i++) {
2121
+ bytes[offset++] = 32;
2122
+ }
2123
+ view.setUint32(offset, paddedBinLength, true);
2124
+ offset += 4;
2125
+ view.setUint32(offset, 5130562, true);
2126
+ offset += 4;
2127
+ bytes.set(buffer, offset);
2128
+ offset += buffer.byteLength;
2129
+ for (let i = 0; i < binPadding; i++) {
2130
+ bytes[offset++] = 0;
2131
+ }
2132
+ return new Uint8Array(output);
2133
+ }
2134
+ /**
2135
+ * Process a light node (stored as extras for universal glTF compatibility)
2136
+ */
2137
+ processLight(light) {
2138
+ const props = light.properties || [];
2139
+ const findLightProp = (key) => props.find((p) => p.key === key)?.value;
2140
+ const position = findLightProp("position");
2141
+ const node = {
2142
+ name: light.name || `light_${this.nodes.length}`,
2143
+ translation: position ? [position[0], position[1], position[2]] : [0, 0, 0],
2144
+ extras: {
2145
+ type: "light",
2146
+ lightType: light.lightType,
2147
+ color: findLightProp("color") || "#ffffff",
2148
+ intensity: findLightProp("intensity") ?? 1
2149
+ }
2150
+ };
2151
+ const nodeIndex = this.nodes.length;
2152
+ this.nodes.push(node);
2153
+ this.stats.nodeCount++;
2154
+ return nodeIndex;
2155
+ }
2156
+ /**
2157
+ * Process a camera node
2158
+ */
2159
+ processCamera(camera) {
2160
+ const props = camera.properties || [];
2161
+ const findCamProp = (key) => props.find((p) => p.key === key)?.value;
2162
+ const position = findCamProp("position");
2163
+ const node = {
2164
+ name: "Camera",
2165
+ translation: position ? [position[0], position[1], position[2]] : [0, 0, 0],
2166
+ extras: {
2167
+ type: "camera",
2168
+ cameraType: camera.cameraType,
2169
+ fov: findCamProp("fov") ?? 75,
2170
+ near: findCamProp("near") ?? 0.1,
2171
+ far: findCamProp("far") ?? 1e3
2172
+ }
2173
+ };
2174
+ const nodeIndex = this.nodes.length;
2175
+ this.nodes.push(node);
2176
+ this.stats.nodeCount++;
2177
+ return nodeIndex;
2178
+ }
2179
+ // =============================================================================
2180
+ // UTILITY METHODS
2181
+ // =============================================================================
2182
+ /** Find a property by key in a HoloObjectDecl's property array. */
2183
+ findProp(object, key) {
2184
+ return object.properties?.find((p) => p.key === key)?.value;
2185
+ }
2186
+ /** Extract a vec3 from an object's properties array. */
2187
+ extractVec3Prop(object, key, defaultValue) {
2188
+ const val = this.findProp(object, key);
2189
+ if (Array.isArray(val) && val.length >= 3) {
2190
+ return [Number(val[0]) || 0, Number(val[1]) || 0, Number(val[2]) || 0];
2191
+ }
2192
+ return defaultValue;
2193
+ }
2194
+ parseColorString(color) {
2195
+ if (color.startsWith("#")) {
2196
+ const hex = color.slice(1);
2197
+ if (hex.length >= 6) {
2198
+ const r = parseInt(hex.slice(0, 2), 16) / 255;
2199
+ const g = parseInt(hex.slice(2, 4), 16) / 255;
2200
+ const b = parseInt(hex.slice(4, 6), 16) / 255;
2201
+ return [r, g, b];
2202
+ }
2203
+ }
2204
+ const colors = {
2205
+ red: [1, 0, 0],
2206
+ green: [0, 1, 0],
2207
+ blue: [0, 0, 1],
2208
+ white: [1, 1, 1],
2209
+ black: [0, 0, 0],
2210
+ yellow: [1, 1, 0],
2211
+ cyan: [0, 1, 1],
2212
+ magenta: [1, 0, 1],
2213
+ orange: [1, 0.5, 0],
2214
+ purple: [0.5, 0, 0.5]
2215
+ };
2216
+ return colors[color.toLowerCase()] || [1, 1, 1];
2217
+ }
2218
+ eulerToQuaternion(euler) {
2219
+ const toRad = Math.PI / 180;
2220
+ const x = euler[0] * toRad / 2;
2221
+ const y = euler[1] * toRad / 2;
2222
+ const z = euler[2] * toRad / 2;
2223
+ const cx = Math.cos(x);
2224
+ const sx = Math.sin(x);
2225
+ const cy = Math.cos(y);
2226
+ const sy = Math.sin(y);
2227
+ const cz = Math.cos(z);
2228
+ const sz = Math.sin(z);
2229
+ return [
2230
+ sx * cy * cz - cx * sy * sz,
2231
+ cx * sy * cz + sx * cy * sz,
2232
+ cx * cy * sz - sx * sy * cz,
2233
+ cx * cy * cz + sx * sy * sz
2234
+ ];
2235
+ }
2236
+ mapPropertyToGLTFPath(property) {
2237
+ const mapping = {
2238
+ position: "translation",
2239
+ translation: "translation",
2240
+ rotation: "rotation",
2241
+ scale: "scale"
2242
+ };
2243
+ return mapping[property.toLowerCase()] || null;
2244
+ }
2245
+ };
2246
+ function createGLTFPipeline(options) {
2247
+ return new GLTFPipeline(options);
2248
+ }
2249
+
2250
+ export { GLTFPipeline, createGLTFPipeline, generateScaleNormalMap, generateScaleTexture };
2251
+ //# sourceMappingURL=chunk-JX7YL6ZE.js.map
2252
+ //# sourceMappingURL=chunk-JX7YL6ZE.js.map