@holoscript/core 8.0.8 → 8.0.9

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 (462) hide show
  1. package/bin/holoscript.cjs +5 -1
  2. package/dist/GLTFPipeline-L76YTXKA.js +15 -0
  3. package/dist/GLTFPipeline-ZWJN7GI6.cjs +36 -0
  4. package/dist/HoloCompositionParser-K76KTEEE.js +12 -0
  5. package/dist/HoloCompositionParser-UZH6Y4HO.cjs +45 -0
  6. package/dist/HoloScriptCodeParser-2D4ERFUZ.js +6 -0
  7. package/dist/HoloScriptCodeParser-UDRLDA7I.cjs +23 -0
  8. package/dist/HoloScriptPlusParser-FTMCGWXD.js +13 -0
  9. package/dist/HoloScriptPlusParser-LQR5GIKF.cjs +30 -0
  10. package/dist/HoloScriptRuntime-UTRLJI5L.js +12 -0
  11. package/dist/HoloScriptRuntime-YBYXJHJN.cjs +21 -0
  12. package/dist/SceneIRCompiler-63KA3M2F.js +17 -0
  13. package/dist/SceneIRCompiler-KWUFHZ4O.cjs +42 -0
  14. package/dist/{USDZExporter-AUHZODOF.cjs → USDZExporter-ML4UMIGC.cjs} +3 -3
  15. package/dist/{USDZExporter-GXB4AUSG.js → USDZExporter-ZFKLQ76G.js} +3 -3
  16. package/dist/agents/index.cjs +1 -1
  17. package/dist/agents/index.js +1 -1
  18. package/dist/audit/AuditLogger.d.ts +106 -0
  19. package/dist/audit/AuditQueryBuilder.d.ts +79 -0
  20. package/dist/audit/ComplianceReporter.d.ts +90 -0
  21. package/dist/audit/index.d.ts +13 -0
  22. package/dist/{chunk-FGMDMJM7.js → chunk-2BYAUHBO.js} +3 -3
  23. package/dist/{chunk-EDPYCLRC.cjs → chunk-2E6PP5UE.cjs} +83 -59
  24. package/dist/{chunk-GASCWJK5.js → chunk-2EGGAZT3.js} +65 -287
  25. package/dist/{chunk-SIEXCILW.js → chunk-2I3XAGMF.js} +3 -3
  26. package/dist/{chunk-OS533P33.cjs → chunk-2KKOYZYI.cjs} +1074 -1655
  27. package/dist/chunk-2MQKNDNH.js +51 -0
  28. package/dist/{chunk-7DMMMBCY.cjs → chunk-2X3IPCBK.cjs} +10 -10
  29. package/dist/chunk-2ZOTBO25.cjs +202 -0
  30. package/dist/chunk-356N4NPM.cjs +152 -0
  31. package/dist/{chunk-X3GJPRVK.cjs → chunk-36NPLOI4.cjs} +92 -81
  32. package/dist/{chunk-SLU6UPJI.cjs → chunk-37HHY7RH.cjs} +5 -5
  33. package/dist/{chunk-YDPEHCCI.cjs → chunk-3CDDRUER.cjs} +3 -118
  34. package/dist/chunk-3F7ZZWIN.js +1651 -0
  35. package/dist/chunk-3ILD7TKP.cjs +187 -0
  36. package/dist/{chunk-X27QRG4C.cjs → chunk-3IUHTGDD.cjs} +153 -41
  37. package/dist/{chunk-PXNZ6TME.js → chunk-4376VHNJ.js} +60 -36
  38. package/dist/{chunk-YKGPCZEE.cjs → chunk-4FIBOJW6.cjs} +10 -10
  39. package/dist/chunk-4Q7RKQQI.cjs +14195 -0
  40. package/dist/{chunk-YCM6QQRT.cjs → chunk-566ZB4LZ.cjs} +180 -8
  41. package/dist/{chunk-2Y3V22SG.js → chunk-5CURIYGT.js} +3 -3
  42. package/dist/{chunk-QBWNJXNR.js → chunk-5FYMCVBY.js} +5 -5
  43. package/dist/{chunk-ZA34AN3R.js → chunk-5LVFTGKH.js} +841 -12
  44. package/dist/chunk-63AUAIL6.js +48 -0
  45. package/dist/chunk-655FATJU.js +110 -0
  46. package/dist/{chunk-TQ377OLB.cjs → chunk-65S62L4D.cjs} +28 -22
  47. package/dist/chunk-6NTAZN5Z.cjs +502 -0
  48. package/dist/chunk-6TRX6AR2.js +9376 -0
  49. package/dist/chunk-6ZCCLKS2.cjs +51 -0
  50. package/dist/{chunk-MDR235RZ.js → chunk-734OB5SK.js} +721 -8
  51. package/dist/{chunk-Q2Q34NF3.js → chunk-77QI552M.js} +6 -6
  52. package/dist/{chunk-WKX5AMOY.js → chunk-7I74JWPW.js} +3 -3
  53. package/dist/{chunk-5FSKKMR7.cjs → chunk-7IDJDMPU.cjs} +232 -4
  54. package/dist/chunk-7VBKRGIZ.cjs +847 -0
  55. package/dist/{chunk-KCPHASCO.js → chunk-AATYYLYK.js} +5 -5
  56. package/dist/{chunk-WFKVS2K4.cjs → chunk-AUZRKIHQ.cjs} +1101 -55
  57. package/dist/{chunk-DTGBOSEM.cjs → chunk-AWXFEAQL.cjs} +12 -12
  58. package/dist/{chunk-THCK6ECW.js → chunk-B3CWTCK2.js} +231 -3
  59. package/dist/chunk-BCP4E7MD.cjs +997 -0
  60. package/dist/chunk-BG7RPYJP.js +91 -0
  61. package/dist/{chunk-VF257YKO.js → chunk-BP4KTMLY.js} +117 -5
  62. package/dist/{chunk-YN6IETRZ.js → chunk-BQJ3YBF3.js} +6424 -987
  63. package/dist/{chunk-KOUAQL2B.cjs → chunk-CANAL6CT.cjs} +1569 -168
  64. package/dist/{chunk-FDSGHPAK.js → chunk-CBSDJF3B.js} +3 -3
  65. package/dist/{chunk-FEWUHQNM.cjs → chunk-CFVK26P4.cjs} +4 -4
  66. package/dist/{chunk-M7K4LE66.cjs → chunk-CI33NINL.cjs} +4 -4
  67. package/dist/{chunk-2OWDB4FB.js → chunk-CKV5NYAE.js} +6 -6
  68. package/dist/{chunk-LPS5AMQD.cjs → chunk-CM4NHXVO.cjs} +24 -24
  69. package/dist/chunk-D3HSRXYB.js +115 -0
  70. package/dist/{chunk-FNHJRI32.js → chunk-DBH3D2MU.js} +1561 -160
  71. package/dist/{chunk-GW3LKD5C.js → chunk-DJNH4HFW.js} +3 -3
  72. package/dist/{chunk-2GCNOI2U.cjs → chunk-DN6F4DHH.cjs} +9 -3
  73. package/dist/chunk-DQRJ5RJG.js +432 -0
  74. package/dist/{chunk-C7ZBSV2Q.js → chunk-DUG3OQAS.js} +106 -43
  75. package/dist/chunk-ECUYJOJ2.cjs +199 -0
  76. package/dist/chunk-EEMTCAK7.js +182 -0
  77. package/dist/{chunk-3SKLAUDD.cjs → chunk-EI3J6LTW.cjs} +359 -581
  78. package/dist/{chunk-SSSN7VAM.js → chunk-EM2OGPYE.js} +4 -4
  79. package/dist/{chunk-56VOWURB.cjs → chunk-ENZCIQZC.cjs} +522 -453
  80. package/dist/chunk-ESBXUYOC.cjs +836 -0
  81. package/dist/{chunk-L5U4W6JC.js → chunk-ESSEF6U2.js} +4 -4
  82. package/dist/chunk-ET3AN4W3.js +824 -0
  83. package/dist/chunk-EXKSFGSX.cjs +14 -14
  84. package/dist/{chunk-I76GIKN7.cjs → chunk-F3YT6GUF.cjs} +17 -17
  85. package/dist/{chunk-WRWEX5ZF.js → chunk-F75DZBBI.js} +3 -3
  86. package/dist/{chunk-4JGRWHZJ.js → chunk-FG6PYGIZ.js} +12 -6
  87. package/dist/chunk-FGGJQRLZ.js +14 -14
  88. package/dist/{chunk-SXOSDZD6.js → chunk-FWCHPCD4.js} +128 -10
  89. package/dist/{chunk-XW6IXEQH.cjs → chunk-G35CAQ7I.cjs} +5 -5
  90. package/dist/{chunk-7VMGP2FW.js → chunk-G6KACNMO.js} +132 -188
  91. package/dist/{chunk-FJPADH77.cjs → chunk-GAWJJAGT.cjs} +6 -6
  92. package/dist/chunk-GGR7QUKK.cjs +4724 -0
  93. package/dist/chunk-GIBF4BHH.js +14098 -0
  94. package/dist/{chunk-AWB7QYY6.cjs → chunk-GILYQ5VH.cjs} +6 -6
  95. package/dist/{chunk-FWVYAMNW.cjs → chunk-GKFCHGCM.cjs} +4 -4
  96. package/dist/{chunk-Y3ZFVUUU.js → chunk-GLEJ2TLS.js} +3 -3
  97. package/dist/{chunk-3GWWJT7L.js → chunk-GP3OKSKT.js} +13 -13
  98. package/dist/chunk-GTIPOEHN.js +196 -0
  99. package/dist/{chunk-LMJ5EBV7.cjs → chunk-GZPUA2TL.cjs} +16 -15
  100. package/dist/{chunk-IELX2OKI.js → chunk-H4LJ4HEA.js} +3 -115
  101. package/dist/{chunk-ACVWFGBI.cjs → chunk-HCX4SMFK.cjs} +3 -3
  102. package/dist/{chunk-HYNTS5CP.js → chunk-HHRZ6STP.js} +24 -2
  103. package/dist/chunk-HIDEIEFG.js +48 -0
  104. package/dist/{chunk-W6RW64BB.cjs → chunk-HSWBIDZM.cjs} +228 -5
  105. package/dist/{chunk-GSOUNWEL.js → chunk-HVX7QQYK.js} +1035 -1616
  106. package/dist/{chunk-TRCGG42I.cjs → chunk-IFW5IW4L.cjs} +6502 -1019
  107. package/dist/{chunk-F5LKJ6F5.cjs → chunk-IJU6AS67.cjs} +32 -28
  108. package/dist/{chunk-TVANHNJ7.js → chunk-IK6Z2HNC.js} +173 -3
  109. package/dist/{chunk-QGMUTVVH.cjs → chunk-IS7NTKY5.cjs} +20 -20
  110. package/dist/{chunk-YFVQWSNJ.js → chunk-IXWGYWH6.js} +3 -3
  111. package/dist/chunk-J2DAS2PL.js +148 -0
  112. package/dist/chunk-JBQXZIWB.js +148 -0
  113. package/dist/chunk-JBYBMBMW.js +261 -0
  114. package/dist/{chunk-LWUOUCYL.js → chunk-JEJ7TT54.js} +5 -5
  115. package/dist/{chunk-DUCB6LGL.js → chunk-JOTCTHN5.js} +211 -5
  116. package/dist/{chunk-47RUFYKR.js → chunk-K56UVEXV.js} +3 -3
  117. package/dist/{chunk-XSFNHP2E.js → chunk-KB26H447.js} +3 -3
  118. package/dist/{chunk-3NGDZZR4.js → chunk-KEYG7HGY.js} +430 -37
  119. package/dist/{chunk-DY72BMU5.js → chunk-KFVNCW4Q.js} +4 -4
  120. package/dist/chunk-KPGC7SK2.js +192 -0
  121. package/dist/chunk-KROXXBK5.cjs +53 -0
  122. package/dist/{chunk-ZPZAVHXL.cjs → chunk-LB3ZZMKT.cjs} +137 -19
  123. package/dist/chunk-LDYZWNJW.cjs +1654 -0
  124. package/dist/{chunk-ULMSSHCJ.cjs → chunk-LMB555QB.cjs} +405 -38
  125. package/dist/{chunk-CBJY23VL.js → chunk-MD4IVS42.js} +3 -3
  126. package/dist/{chunk-VMLKSV26.js → chunk-MDDWEBCX.js} +226 -3
  127. package/dist/chunk-MUWH4QK5.cjs +94 -0
  128. package/dist/{chunk-T6W3Z3SH.cjs → chunk-N2ILK7BF.cjs} +4 -4
  129. package/dist/{chunk-6EX3I5P4.cjs → chunk-N74QRJGP.cjs} +6 -6
  130. package/dist/chunk-NFFHLX37.cjs +132 -0
  131. package/dist/chunk-NJSYWX7H.js +190 -0
  132. package/dist/{chunk-SH5PPVK7.cjs → chunk-NQN5LFN4.cjs} +165 -221
  133. package/dist/chunk-NTQRFOPP.cjs +56 -0
  134. package/dist/{chunk-YFWRJW4B.js → chunk-NWMJPTVL.js} +51 -55
  135. package/dist/{chunk-63ZGNR2T.cjs → chunk-OC6GV5QH.cjs} +42 -42
  136. package/dist/{chunk-7E7GCQCK.js → chunk-OG3MBHM3.js} +9 -3
  137. package/dist/chunk-OMNHTCS4.cjs +264 -0
  138. package/dist/chunk-OQXB6NNC.cjs +117 -0
  139. package/dist/{chunk-Y57W2CT5.cjs → chunk-OV46CCA2.cjs} +51 -55
  140. package/dist/{chunk-6PRZIHGL.cjs → chunk-OV6HHKLE.cjs} +21 -266
  141. package/dist/{chunk-C37BHB7N.cjs → chunk-P26YYPOO.cjs} +5 -5
  142. package/dist/{chunk-2BZHWUSR.cjs → chunk-P7JEKJTZ.cjs} +16 -16
  143. package/dist/{chunk-NGBXXZLL.cjs → chunk-PDXX5UI4.cjs} +45 -45
  144. package/dist/{chunk-FHQFPYV4.js → chunk-PJFTTSKE.js} +8 -7
  145. package/dist/{chunk-GVFJ6T4S.cjs → chunk-PVODJEJ7.cjs} +721 -8
  146. package/dist/{chunk-ZZ7RO2UQ.js → chunk-Q265VZJ4.js} +3 -3
  147. package/dist/{chunk-E7JP3BS3.cjs → chunk-Q47JEE2C.cjs} +4 -4
  148. package/dist/chunk-QBY7LRN2.js +281 -0
  149. package/dist/{chunk-Z6PMDS4G.js → chunk-QDQWKSU3.js} +1090 -53
  150. package/dist/{chunk-GH6C2QGW.cjs → chunk-QEDMOGF3.cjs} +857 -16
  151. package/dist/{chunk-5WUNN6ZN.cjs → chunk-QHSAVOOL.cjs} +24 -2
  152. package/dist/chunk-QJNCDVYM.cjs +137 -0
  153. package/dist/chunk-QM7FJB5W.js +4717 -0
  154. package/dist/chunk-QQFB4RT2.cjs +448 -0
  155. package/dist/chunk-QSYBHQAD.cjs +196 -0
  156. package/dist/{chunk-UGXHYIWT.cjs → chunk-QUJ3ZB55.cjs} +28 -28
  157. package/dist/{chunk-2YSNA2F2.cjs → chunk-QVJMDVYZ.cjs} +5 -5
  158. package/dist/chunk-RAJMAX6D.js +131 -0
  159. package/dist/{chunk-VVKVQZI6.js → chunk-RAN3ECAS.js} +3 -3
  160. package/dist/chunk-RKGUZBOC.js +79 -0
  161. package/dist/{chunk-HLFDZ35S.cjs → chunk-RRQIAJLQ.cjs} +8 -8
  162. package/dist/{chunk-PABONWKI.js → chunk-RXQNRZ5F.js} +3 -3
  163. package/dist/{chunk-7ZHYEITD.cjs → chunk-S4O7CFHQ.cjs} +10 -11
  164. package/dist/chunk-SE7ANBGN.js +128 -0
  165. package/dist/{chunk-X2AVEAZM.cjs → chunk-SJIRCTIS.cjs} +176 -2
  166. package/dist/{chunk-WXQ57LAO.js → chunk-SQXAZHDG.js} +4 -4
  167. package/dist/chunk-SR73L5ZP.cjs +84 -0
  168. package/dist/{chunk-OABEO6HH.js → chunk-SZOLTWWD.js} +2349 -214
  169. package/dist/{chunk-5JEU52DW.js → chunk-TPZ3BN2D.js} +3 -3
  170. package/dist/{chunk-QFU53KRH.js → chunk-TSTFYGGX.js} +4 -5
  171. package/dist/{chunk-EBS32AJI.cjs → chunk-TZCFKZ6Z.cjs} +5 -5
  172. package/dist/chunk-UCVZXQ63.js +724 -0
  173. package/dist/chunk-UGQ3QNV6.js +992 -0
  174. package/dist/chunk-UNMVGZVW.js +142 -0
  175. package/dist/{chunk-TEVX443G.js → chunk-UTUD6GJI.js} +178 -6
  176. package/dist/chunk-UXBYA7DV.cjs +155 -0
  177. package/dist/chunk-V6GXFSK7.cjs +443 -0
  178. package/dist/chunk-VHORVGCG.cjs +761 -0
  179. package/dist/{chunk-B4EKV6HQ.js → chunk-VKCTYLDN.js} +500 -442
  180. package/dist/{chunk-O3MGZDCT.cjs → chunk-VTEXJOSD.cjs} +63 -63
  181. package/dist/chunk-VVAAZITA.cjs +287 -0
  182. package/dist/{chunk-V7AKE5VT.cjs → chunk-W2GA3EQB.cjs} +435 -42
  183. package/dist/chunk-W4GABFCR.js +37 -0
  184. package/dist/chunk-WKEK4NCA.js +490 -0
  185. package/dist/{chunk-5A4TCHOC.cjs → chunk-WNYXT4TE.cjs} +4 -4
  186. package/dist/{chunk-S762UEV5.js → chunk-WTH23ISI.js} +6 -6
  187. package/dist/{chunk-BTKZGHAV.js → chunk-WWNCM473.js} +10 -6
  188. package/dist/{chunk-7X5PNIQJ.js → chunk-X3YFRH6K.js} +27 -25
  189. package/dist/{chunk-4YNYPHH3.cjs → chunk-X75H75UY.cjs} +2351 -213
  190. package/dist/{chunk-LYJJI7ZK.cjs → chunk-XCUDDFKC.cjs} +216 -9
  191. package/dist/chunk-YAO4HPJL.cjs +120 -0
  192. package/dist/chunk-YKY2JBER.cjs +9443 -0
  193. package/dist/chunk-YP5CHEYU.cjs +154 -0
  194. package/dist/{chunk-WRNEH5MO.js → chunk-YW3I2FQL.js} +18 -7
  195. package/dist/{chunk-BRNUPDHJ.js → chunk-Z557DVYN.js} +386 -19
  196. package/dist/{chunk-VSACG2AR.js → chunk-Z6LZUYZF.js} +21 -264
  197. package/dist/chunk-ZHPMP447.cjs +43 -0
  198. package/dist/{chunk-LODTHGST.cjs → chunk-ZK7KX5CD.cjs} +133 -70
  199. package/dist/{chunk-CCPSNT6B.cjs → chunk-ZRPALBQB.cjs} +5 -5
  200. package/dist/chunk-ZVFHPMC5.js +824 -0
  201. package/dist/chunk-ZVQMKUGJ.js +443 -0
  202. package/dist/cli/holoscript-runner.cjs +86 -48
  203. package/dist/cli/holoscript-runner.js +54 -16
  204. package/dist/codebase/index.cjs +1 -1
  205. package/dist/codebase/index.js +1 -1
  206. package/dist/compiler/agent-inference.cjs +11 -11
  207. package/dist/compiler/agent-inference.js +9 -6
  208. package/dist/compiler/android-xr.cjs +13 -12
  209. package/dist/compiler/android-xr.js +11 -10
  210. package/dist/compiler/android.cjs +12 -12
  211. package/dist/compiler/android.js +10 -10
  212. package/dist/compiler/business-quest.cjs +10 -10
  213. package/dist/compiler/business-quest.js +2 -2
  214. package/dist/compiler/coco.cjs +1 -1
  215. package/dist/compiler/coco.js +1 -1
  216. package/dist/compiler/context.cjs +9 -9
  217. package/dist/compiler/context.js +6 -6
  218. package/dist/compiler/daimon-seed.cjs +36 -0
  219. package/dist/compiler/daimon-seed.js +12 -0
  220. package/dist/compiler/domain-block-utils.cjs +205 -156
  221. package/dist/compiler/domain-block-utils.js +8 -7
  222. package/dist/compiler/dtdl.cjs +10 -10
  223. package/dist/compiler/dtdl.js +7 -7
  224. package/dist/compiler/gltf-pipeline.cjs +9 -9
  225. package/dist/compiler/gltf-pipeline.js +2 -2
  226. package/dist/compiler/godot.cjs +10 -9
  227. package/dist/compiler/godot.js +9 -8
  228. package/dist/compiler/incremental.cjs +11 -11
  229. package/dist/compiler/incremental.js +6 -6
  230. package/dist/compiler/index.cjs +2585 -3273
  231. package/dist/compiler/index.d.ts +149 -35
  232. package/dist/compiler/index.js +2197 -3102
  233. package/dist/compiler/ios.cjs +11 -11
  234. package/dist/compiler/ios.js +9 -9
  235. package/dist/compiler/llm-provider-capabilities.cjs +9 -9
  236. package/dist/compiler/llm-provider-capabilities.js +6 -6
  237. package/dist/compiler/nodetoy.cjs +1 -1
  238. package/dist/compiler/nodetoy.js +1 -1
  239. package/dist/compiler/openxr.cjs +11 -10
  240. package/dist/compiler/openxr.js +10 -9
  241. package/dist/compiler/remotion.cjs +1 -1
  242. package/dist/compiler/remotion.js +1 -1
  243. package/dist/compiler/reproducibility.cjs +1 -1
  244. package/dist/compiler/reproducibility.js +1 -1
  245. package/dist/compiler/sdf.cjs +11 -10
  246. package/dist/compiler/sdf.js +9 -8
  247. package/dist/compiler/semantic-scene.cjs +7 -7
  248. package/dist/compiler/semantic-scene.js +2 -2
  249. package/dist/compiler/state.cjs +9 -9
  250. package/dist/compiler/state.js +7 -7
  251. package/dist/compiler/trait-composition.cjs +11 -11
  252. package/dist/compiler/trait-composition.js +7 -7
  253. package/dist/compiler/traits/ProvenanceSemiring.d.ts +167 -0
  254. package/dist/compiler/traits/Semiring.d.ts +26 -0
  255. package/dist/compiler/unity.cjs +11 -10
  256. package/dist/compiler/unity.js +10 -9
  257. package/dist/compiler/unreal.cjs +12 -11
  258. package/dist/compiler/unreal.js +10 -9
  259. package/dist/compiler/urdf.cjs +18 -17
  260. package/dist/compiler/urdf.js +9 -8
  261. package/dist/compiler/usd-physics.cjs +11 -10
  262. package/dist/compiler/usd-physics.js +8 -7
  263. package/dist/compiler/visionos.cjs +11 -10
  264. package/dist/compiler/visionos.js +10 -9
  265. package/dist/compiler/vrchat.cjs +11 -10
  266. package/dist/compiler/vrchat.js +9 -8
  267. package/dist/compiler/wasm.cjs +14 -13
  268. package/dist/compiler/wasm.js +9 -8
  269. package/dist/compiler/webgpu.cjs +10 -9
  270. package/dist/compiler/webgpu.js +9 -8
  271. package/dist/constants.cjs +398 -0
  272. package/dist/constants.js +9 -0
  273. package/dist/coordinators/index.cjs +4 -1
  274. package/dist/coordinators/index.js +4 -1
  275. package/dist/debugger.cjs +11 -9
  276. package/dist/debugger.js +9 -7
  277. package/dist/{dist-ACXG6IH5.cjs → dist-GRMOP2UL.cjs} +341 -65
  278. package/dist/{dist-VD4L6V7Q.js → dist-ZBUKU2JG.js} +333 -63
  279. package/dist/entries/interop.cjs +23 -23
  280. package/dist/entries/interop.js +3 -3
  281. package/dist/entries/scripting.cjs +12 -11
  282. package/dist/entries/scripting.js +8 -7
  283. package/dist/evolution/index.cjs +66 -0
  284. package/dist/evolution/index.d.ts +162 -0
  285. package/dist/evolution/index.js +17 -0
  286. package/dist/hololand/index.cjs +41 -37
  287. package/dist/hololand/index.js +3 -3
  288. package/dist/index.cjs +12394 -3224
  289. package/dist/index.d.ts +260 -18
  290. package/dist/index.js +10755 -2182
  291. package/dist/keyword-registry/PluginKeywordRegistry.d.ts +138 -0
  292. package/dist/keyword-registry/index.cjs +29 -0
  293. package/dist/keyword-registry/index.d.ts +1 -0
  294. package/dist/keyword-registry/index.js +4 -0
  295. package/dist/math/tropical-spmv.cjs +11 -11
  296. package/dist/math/tropical-spmv.d.ts +1 -0
  297. package/dist/math/tropical-spmv.js +2 -2
  298. package/dist/math/tropicalSpmv.d.ts +43 -0
  299. package/dist/math/vec3.cjs +1 -1
  300. package/dist/math/vec3.js +1 -1
  301. package/dist/matter/StagedMatter.d.ts +82 -0
  302. package/dist/matter/index.cjs +17 -0
  303. package/dist/matter/index.d.ts +1 -0
  304. package/dist/matter/index.js +4 -0
  305. package/dist/{ml-dsa-Z7JDKW4L.js → ml-dsa-J6VKVT4K.js} +3 -3
  306. package/dist/{ml-dsa-FSKBTE3W.cjs → ml-dsa-MTIK4ZUQ.cjs} +23 -23
  307. package/dist/paper-0c-spike/index.cjs +1 -1
  308. package/dist/paper-0c-spike/index.js +1 -1
  309. package/dist/parameter-envelope/ParameterEnvelope.d.ts +128 -0
  310. package/dist/parameter-envelope/index.cjs +17 -0
  311. package/dist/parameter-envelope/index.d.ts +2 -0
  312. package/dist/parameter-envelope/index.js +4 -0
  313. package/dist/parser/HoloCompositionTypes.d.ts +2013 -0
  314. package/dist/parser/PipelineParser.d.ts +162 -0
  315. package/dist/parser.cjs +36 -20
  316. package/dist/parser.js +13 -9
  317. package/dist/plugin-manifest/ManifestAutoLoader.d.ts +35 -0
  318. package/dist/plugin-manifest/PluginManifest.d.ts +156 -0
  319. package/dist/plugin-manifest/index.cjs +25 -0
  320. package/dist/plugin-manifest/index.d.ts +2 -0
  321. package/dist/plugin-manifest/index.js +4 -0
  322. package/dist/plugin-solver-contract/PluginSolverContract.d.ts +288 -0
  323. package/dist/plugin-solver-contract/index.cjs +41 -0
  324. package/dist/plugin-solver-contract/index.d.ts +1 -0
  325. package/dist/plugin-solver-contract/index.js +4 -0
  326. package/dist/policy/ContentPolicyGate.d.ts +51 -0
  327. package/dist/policy/PolicyPack.d.ts +120 -0
  328. package/dist/policy/blocklist.d.ts +32 -0
  329. package/dist/policy/defaults.d.ts +44 -0
  330. package/dist/policy/index.cjs +106 -0
  331. package/dist/policy/index.d.ts +17 -0
  332. package/dist/policy/index.js +5 -0
  333. package/dist/policy/jsonLogic.d.ts +31 -0
  334. package/dist/policy/types.d.ts +174 -0
  335. package/dist/proof-composition/ProofCompositionLaw.d.ts +93 -0
  336. package/dist/proof-composition/index.cjs +25 -0
  337. package/dist/proof-composition/index.d.ts +1 -0
  338. package/dist/proof-composition/index.js +4 -0
  339. package/dist/receipts/hash-policy.d.ts +85 -0
  340. package/dist/reconstruction/index.cjs +75 -47
  341. package/dist/reconstruction/index.js +5 -5
  342. package/dist/runtime/plugin-trait-registrar.d.ts +36 -0
  343. package/dist/runtime.cjs +81 -79
  344. package/dist/runtime.js +9 -7
  345. package/dist/scene-presets-EDKYZ5GW.js +4 -0
  346. package/dist/scene-presets-NCW2CFRS.cjs +17 -0
  347. package/dist/self-improvement/index.cjs +1 -1
  348. package/dist/self-improvement/index.js +1 -1
  349. package/dist/{src-PT2FERDV.cjs → src-G3D7ZATQ.cjs} +545 -21
  350. package/dist/{src-J6CM4AUR.js → src-UXYA7HM6.js} +539 -16
  351. package/dist/storage/index.cjs +10 -10
  352. package/dist/storage/index.js +3 -3
  353. package/dist/testing.cjs +1 -1
  354. package/dist/testing.js +1 -1
  355. package/dist/tools/index.cjs +3631 -0
  356. package/dist/tools/index.js +3581 -0
  357. package/dist/traitDocs/traitDocs.cjs +9 -9
  358. package/dist/traitDocs/traitDocs.d.ts +1 -0
  359. package/dist/traitDocs/traitDocs.js +3 -3
  360. package/dist/traits/ControlLoopTrait.d.ts +154 -0
  361. package/dist/traits/KinematicChainTrait.d.ts +116 -0
  362. package/dist/traits/SensorSamplingTrait.d.ts +154 -0
  363. package/dist/traits/TraitTypes.d.ts +270 -0
  364. package/dist/traits/TransactionTrait.d.ts +121 -0
  365. package/dist/traits/botanical-lotus.cjs +54 -50
  366. package/dist/traits/botanical-lotus.js +2 -5
  367. package/dist/traits/control-loop.cjs +21 -0
  368. package/dist/traits/control-loop.d.ts +1 -0
  369. package/dist/traits/control-loop.js +4 -0
  370. package/dist/traits/engines/cloth-verlet.d.ts +65 -0
  371. package/dist/traits/engines/index.cjs +19 -19
  372. package/dist/traits/engines/index.d.ts +15 -275
  373. package/dist/traits/engines/index.js +3 -3
  374. package/dist/traits/engines/motion-data-schema.d.ts +119 -0
  375. package/dist/traits/engines/motion-matching.d.ts +102 -0
  376. package/dist/traits/engines/noise.d.ts +25 -0
  377. package/dist/traits/engines/onnx-adapter.d.ts +173 -0
  378. package/dist/traits/engines/onnx-motion-matching.d.ts +163 -0
  379. package/dist/traits/engines/pfnn-network.d.ts +92 -0
  380. package/dist/traits/engines/synthetic-walk-cycle.d.ts +38 -0
  381. package/dist/traits/engines/tensor-ops.d.ts +15 -0
  382. package/dist/traits/index.cjs +2789 -1259
  383. package/dist/traits/index.d.ts +35 -0
  384. package/dist/traits/index.js +1692 -411
  385. package/dist/traits/kinematic-chain.cjs +25 -0
  386. package/dist/traits/kinematic-chain.d.ts +1 -0
  387. package/dist/traits/kinematic-chain.js +4 -0
  388. package/dist/traits/sensor-sampling.cjs +33 -0
  389. package/dist/traits/sensor-sampling.d.ts +1 -0
  390. package/dist/traits/sensor-sampling.js +4 -0
  391. package/dist/traits/simulation-solver-factory.cjs +1 -1
  392. package/dist/traits/simulation-solver-factory.js +1 -1
  393. package/dist/traits/transaction.cjs +29 -0
  394. package/dist/traits/transaction.d.ts +1 -0
  395. package/dist/traits/transaction.js +4 -0
  396. package/dist/traits/webcam-gaze.cjs +1 -1
  397. package/dist/traits/webcam-gaze.js +1 -1
  398. package/dist/type-checker.cjs +7 -6
  399. package/dist/type-checker.js +5 -4
  400. package/dist/types/AdvancedTypeSystem.d.ts +489 -0
  401. package/dist/types/HoloScriptPlus.d.ts +810 -0
  402. package/dist/types/base.d.ts +248 -0
  403. package/dist/types.d.ts +799 -0
  404. package/dist/world/index.cjs +3 -4
  405. package/dist/world/index.js +3 -4
  406. package/dist/world-model/index.cjs +1 -1
  407. package/dist/world-model/index.js +1 -1
  408. package/dist/wot/index.cjs +1 -1
  409. package/dist/wot/index.js +1 -1
  410. package/package.json +113 -46
  411. package/dist/GLTFPipeline-3EJLL3TS.cjs +0 -38
  412. package/dist/GLTFPipeline-3OWJV2VK.js +0 -17
  413. package/dist/HoloScriptPlusParser-ADWRY5OS.cjs +0 -698
  414. package/dist/HoloScriptPlusParser-JLJDXHSC.js +0 -693
  415. package/dist/HoloScriptPlusParser-QCGFPWIL.cjs +0 -27
  416. package/dist/HoloScriptPlusParser-WENAFEFV.js +0 -10
  417. package/dist/HoloScriptRuntime-GGRVEU4T.cjs +0 -19
  418. package/dist/HoloScriptRuntime-GJK6VJPH.js +0 -10
  419. package/dist/chunk-22Q5A6RV.js +0 -979
  420. package/dist/chunk-4C57PR42.js +0 -468
  421. package/dist/chunk-4W5G5QVL.cjs +0 -847
  422. package/dist/chunk-5ET6L4NS.js +0 -487
  423. package/dist/chunk-C4GSLCHE.cjs +0 -7153
  424. package/dist/chunk-F2G6CWFT.js +0 -7089
  425. package/dist/chunk-G6PNEASF.cjs +0 -814
  426. package/dist/chunk-GTA4Q3A3.js +0 -1491
  427. package/dist/chunk-HCCQLAA4.cjs +0 -74
  428. package/dist/chunk-HFSVMKM3.cjs +0 -72
  429. package/dist/chunk-KAIVDEIG.cjs +0 -4539
  430. package/dist/chunk-KQU64CIX.cjs +0 -1508
  431. package/dist/chunk-MSYSQ2AJ.js +0 -4533
  432. package/dist/chunk-NHJLP37F.js +0 -70
  433. package/dist/chunk-NHYRRAGI.cjs +0 -490
  434. package/dist/chunk-OIQYIIO3.cjs +0 -473
  435. package/dist/chunk-OL46QLBJ.js +0 -61
  436. package/dist/chunk-SKZPC5AG.cjs +0 -984
  437. package/dist/chunk-SLHLXUMO.js +0 -445
  438. package/dist/chunk-UOIGFQXC.cjs +0 -9750
  439. package/dist/chunk-UOL6Y5TD.cjs +0 -759
  440. package/dist/chunk-UVFI7XIR.cjs +0 -452
  441. package/dist/chunk-VEPGBETF.js +0 -844
  442. package/dist/chunk-XQ5MWMP2.js +0 -756
  443. package/dist/chunk-XT6JY5W5.js +0 -9684
  444. package/dist/chunk-YRRAUB35.js +0 -811
  445. package/dist/compiler/GasOptimizationAnalyzer.d.ts +0 -73
  446. package/dist/compiler/NFTMarketplaceCompiler.d.ts +0 -23
  447. package/dist/compiler/ar.cjs +0 -23
  448. package/dist/compiler/ar.js +0 -11
  449. package/dist/compiler/babylon.cjs +0 -21
  450. package/dist/compiler/babylon.js +0 -15
  451. package/dist/compiler/multi-layer.cjs +0 -24
  452. package/dist/compiler/multi-layer.js +0 -15
  453. package/dist/compiler/playcanvas.cjs +0 -19
  454. package/dist/compiler/playcanvas.js +0 -13
  455. package/dist/compiler/r3f.cjs +0 -39
  456. package/dist/compiler/r3f.d.ts +0 -22
  457. package/dist/compiler/r3f.js +0 -17
  458. package/dist/compiler/vrr.cjs +0 -24
  459. package/dist/compiler/vrr.js +0 -12
  460. package/dist/parser/NFTMarketplaceTypes.d.ts +0 -191
  461. package/dist/playwright-3AT3AKTV.cjs +0 -98673
  462. package/dist/playwright-VZPDVUEQ.js +0 -98660
@@ -1,1011 +1,1010 @@
1
- import { init_AndroidKotlinHelpers, sanitizeNameCapitalized, getSceneformGeometry, findObjProp, toKotlinType, toKotlinValue, toAndroidColor, compositionHasTrait } from './chunk-FDSGHPAK.js';
2
- import { init_CompilerBase, CompilerBase } from './chunk-C7ZBSV2Q.js';
3
- import { init_geospatial, init_depth_scanner, init_spatial_authoring, init_haptic_feedback, init_nearby_connections, init_foldable_display, init_samsung_dex, init_google_lens, init_webxr, SPATIAL_AUTHORING_TRAITS, SPATIAL_AUTHORING_DEFAULTS, HAPTIC_FEEDBACK_TRAITS, NEARBY_CONNECTIONS_TRAITS, FOLDABLE_DISPLAY_TRAITS, SAMSUNG_DEX_TRAITS, GOOGLE_LENS_TRAITS, WEBXR_TRAITS, DEPTH_SCANNER_TRAITS, GEOSPATIAL_DEFAULTS, DEPTH_SCANNER_DEFAULTS } from './chunk-WKX5AMOY.js';
4
- import { init_portal_ar, init_camera_hand_tracking, init_npu_scene, NPU_SCENE_TRAITS, NPU_SCENE_DEFAULTS, CAMERA_HAND_TRACKING_TRAITS, PORTAL_AR_TRAITS } from './chunk-CBJY23VL.js';
5
- import { __esm, __export } from './chunk-OL46QLBJ.js';
1
+ import { init_AndroidKotlinHelpers, sanitizeNameCapitalized, getSceneformGeometry, findObjProp, toKotlinType, toKotlinValue, toAndroidColor, compositionHasTrait, toKotlinColor } from './chunk-CBSDJF3B.js';
2
+ import { init_CompilerBase, CompilerBase } from './chunk-DUG3OQAS.js';
3
+ import { init_geospatial, init_depth_scanner, init_spatial_authoring, init_haptic_feedback, init_nearby_connections, init_foldable_display, init_samsung_dex, init_google_lens, init_webxr, GEOSPATIAL_DEFAULTS, DEPTH_SCANNER_DEFAULTS, SPATIAL_AUTHORING_TRAITS, SPATIAL_AUTHORING_DEFAULTS, HAPTIC_FEEDBACK_TRAITS, NEARBY_CONNECTIONS_TRAITS, FOLDABLE_DISPLAY_TRAITS, SAMSUNG_DEX_TRAITS, GOOGLE_LENS_TRAITS, WEBXR_TRAITS, DEPTH_SCANNER_TRAITS } from './chunk-7I74JWPW.js';
4
+ import { init_portal_ar, init_camera_hand_tracking, init_npu_scene, NPU_SCENE_TRAITS, NPU_SCENE_DEFAULTS, PORTAL_AR_TRAITS, CAMERA_HAND_TRACKING_TRAITS } from './chunk-MD4IVS42.js';
5
+ import { __esm, __export } from './chunk-W4GABFCR.js';
6
6
  import { ANSCapabilityPath } from '@holoscript/core-types/ans';
7
7
 
8
- // src/compiler/AndroidFeatureGenerators.ts
9
- function hasGeoTraits(composition) {
10
- const geoTraitNames = [
11
- "geo_anchor",
12
- "geo_persist",
13
- "geo_radius",
14
- "geo_compass_heading",
15
- "geo_altitude",
16
- "geo_cloud_anchor",
17
- "geo_terrain_snap",
18
- "geo_session_continuity",
19
- "geo_proximity_trigger",
20
- "geo_discoverable",
21
- "geo_arcore_geospatial",
22
- "geo_arkit_geo_anchor",
23
- // ARCore Geospatial API traits (M.010.15)
24
- "geospatial_vps",
25
- "geospatial_anchor",
26
- "geospatial_terrain_anchor",
27
- "geospatial_rooftop_anchor",
28
- "geospatial_streetscape",
29
- "geospatial_heading"
30
- ];
31
- for (const obj of composition.objects || []) {
32
- for (const trait of obj.traits || []) {
33
- const name = typeof trait === "string" ? trait : trait.name;
34
- if (geoTraitNames.includes(name)) return true;
8
+ // src/compiler/AndroidSceneViewFeatureGenerators.ts
9
+ function objectsOf(composition) {
10
+ return composition.objects ?? [];
11
+ }
12
+ function traitsOf(obj) {
13
+ return obj.traits ?? [];
14
+ }
15
+ function traitName(trait) {
16
+ return typeof trait === "string" ? trait : trait.name ?? "";
17
+ }
18
+ function traitConfig(trait) {
19
+ if (!trait || typeof trait === "string") return {};
20
+ return trait.config ?? trait.params ?? {};
21
+ }
22
+ function findTrait(obj, name) {
23
+ return traitsOf(obj).find((trait) => traitName(trait) === name);
24
+ }
25
+ function hasAnyTrait(composition, names) {
26
+ return objectsOf(composition).some(
27
+ (obj) => traitsOf(obj).some((trait) => names.includes(traitName(trait)))
28
+ );
29
+ }
30
+ function collectUsedTraits(composition, names) {
31
+ const used = /* @__PURE__ */ new Set();
32
+ for (const obj of objectsOf(composition)) {
33
+ for (const trait of traitsOf(obj)) {
34
+ const name = traitName(trait);
35
+ if (names.includes(name)) used.add(name);
35
36
  }
36
37
  }
37
- return false;
38
+ return [...used].sort();
38
39
  }
39
- function hasGeospatialVPSTraits(composition) {
40
- const geospatialTraitNames = [
41
- "geospatial_vps",
42
- "geospatial_anchor",
43
- "geospatial_terrain_anchor",
44
- "geospatial_rooftop_anchor",
45
- "geospatial_streetscape",
46
- "geospatial_heading"
47
- ];
48
- for (const obj of composition.objects || []) {
49
- for (const trait of obj.traits || []) {
50
- const name = typeof trait === "string" ? trait : trait.name;
51
- if (geospatialTraitNames.includes(name)) return true;
52
- }
40
+ function numberConfig(config, keys, fallback) {
41
+ for (const key of keys) {
42
+ const raw = config[key];
43
+ const numeric = typeof raw === "number" ? raw : Number(raw);
44
+ if (Number.isFinite(numeric)) return numeric;
53
45
  }
54
- return false;
46
+ return fallback;
47
+ }
48
+ function floatLiteral(value) {
49
+ return `${Number.isInteger(value) ? value.toFixed(0) : value}f`;
50
+ }
51
+ function quotedKotlin(compiler, value) {
52
+ return `"${compiler.escapeStringValue(String(value), "Kotlin")}"`;
53
+ }
54
+ function emitHeader(compiler, composition, title, requirements) {
55
+ compiler.lines = [];
56
+ compiler.indentLevel = 0;
57
+ compiler.emit(`// Auto-generated by HoloScript AndroidCompiler - ${title}`);
58
+ compiler.emit(
59
+ `// Source: composition "${compiler.escapeStringValue(String(composition.name), "Kotlin")}"`
60
+ );
61
+ for (const requirement of requirements) {
62
+ compiler.emit(`// Requires ${requirement}`);
63
+ }
64
+ compiler.emit("// SceneView-native sidecar generated without legacy fragment or node factories.");
65
+ compiler.emit("");
66
+ compiler.emit(`package ${compiler.options.packageName}`);
67
+ compiler.emit("");
68
+ }
69
+ function finish(compiler) {
70
+ return `${compiler.lines.join("\n")}
71
+ `;
72
+ }
73
+ function emitUsedTraits(compiler, used) {
74
+ if (used.length === 0) {
75
+ compiler.emit("private val usedTraits = emptySet<String>()");
76
+ return;
77
+ }
78
+ compiler.emit(`private val usedTraits = setOf(${used.map((trait) => `"${trait}"`).join(", ")})`);
79
+ }
80
+ function hasGeoAnchorTraits(composition) {
81
+ return hasAnyTrait(composition, GEO_ANCHOR_TRAITS);
82
+ }
83
+ function hasGeoTraits(composition) {
84
+ return hasGeoAnchorTraits(composition) || hasGeospatialVPSTraits(composition);
85
+ }
86
+ function hasGeospatialVPSTraits(composition) {
87
+ return hasAnyTrait(composition, GEOSPATIAL_TRAITS);
88
+ }
89
+ function hasDepthScanTraits(composition) {
90
+ return hasAnyTrait(composition, DEPTH_SCANNER_TRAITS);
91
+ }
92
+ function hasPortalARTraits(composition) {
93
+ return hasAnyTrait(composition, PORTAL_AR_TRAITS);
94
+ }
95
+ function hasHandTrackingTraits(composition) {
96
+ return hasAnyTrait(composition, CAMERA_HAND_TRACKING_TRAITS);
55
97
  }
56
98
  function emitGeoAnchorSetup(compiler, composition) {
99
+ emitHeader(compiler, composition, "SceneView Geo-Anchor Setup", [
100
+ "ARCore Earth anchors",
101
+ "Google Play Services location"
102
+ ]);
103
+ compiler.emit("import android.content.Context");
104
+ compiler.emit("import android.util.Log");
105
+ compiler.emit("import com.google.ar.core.Anchor");
106
+ compiler.emit("import com.google.ar.core.Config");
107
+ compiler.emit("import com.google.ar.core.Earth");
108
+ compiler.emit("import com.google.ar.core.Session");
109
+ compiler.emit("import com.google.ar.core.TrackingState");
57
110
  compiler.emit("");
58
- compiler.emit("// === Geo-Anchor: GPS-pinned persistent holograms ===");
59
111
  compiler.emit(
60
- "private var fusedLocationClient: com.google.android.gms.location.FusedLocationProviderClient? = null"
112
+ `class ${compiler.options.className}GeoAnchorManager(private val context: Context) {`
61
113
  );
114
+ compiler.indentLevel++;
115
+ emitUsedTraits(compiler, collectUsedTraits(composition, GEO_ANCHOR_TRAITS));
62
116
  compiler.emit("private val geoAnchors = mutableMapOf<String, Anchor>()");
117
+ compiler.emit("private val requestedAnchors = listOf(");
118
+ compiler.indentLevel++;
119
+ const anchors = objectsOf(composition).filter((obj) => findTrait(obj, "geo_anchor"));
120
+ if (anchors.length === 0) {
121
+ compiler.emit("// No explicit geo_anchor objects; call createGeoAnchor at runtime.");
122
+ }
123
+ anchors.forEach((obj, index) => {
124
+ const geoConfig = traitConfig(findTrait(obj, "geo_anchor"));
125
+ const altitudeConfig = traitConfig(findTrait(obj, "geo_altitude"));
126
+ const headingConfig = traitConfig(findTrait(obj, "geo_compass_heading"));
127
+ const lat = numberConfig(geoConfig, ["latitude", "lat"], 0);
128
+ const lng = numberConfig(geoConfig, ["longitude", "lng"], 0);
129
+ const altitude = numberConfig(altitudeConfig, ["meters", "altitude"], 0);
130
+ const heading = numberConfig(headingConfig, ["degrees", "heading"], 0);
131
+ compiler.emit(
132
+ `SceneViewGeoAnchor(${quotedKotlin(compiler, obj.name)}, ${lat}, ${lng}, ${altitude}, ${floatLiteral(
133
+ heading
134
+ )})${index === anchors.length - 1 ? "" : ","}`
135
+ );
136
+ });
137
+ compiler.indentLevel--;
138
+ compiler.emit(")");
63
139
  compiler.emit("");
64
- compiler.emit("private fun setupGeoAnchors() {");
140
+ compiler.emit("fun setupGeoAnchors(session: Session, earth: Earth?) {");
141
+ compiler.indentLevel++;
142
+ compiler.emit("configureSessionForGeospatial(session)");
143
+ compiler.emit("val earthRef = earth ?: return");
144
+ compiler.emit("for (anchor in requestedAnchors) {");
65
145
  compiler.indentLevel++;
66
146
  compiler.emit(
67
- "fusedLocationClient = com.google.android.gms.location.LocationServices.getFusedLocationProviderClient(this)"
147
+ "createGeoAnchor(anchor.name, earthRef, anchor.latitude, anchor.longitude, anchor.altitude, anchor.heading)"
68
148
  );
69
- compiler.emit("");
70
- const usesGeospatial = compiler.compositionHasTrait(composition, "geo_arcore_geospatial");
71
- if (usesGeospatial) {
72
- compiler.emit("// Enable ARCore Geospatial API (VPS)");
73
- compiler.emit("val session = arFragment.arSceneView.session ?: return");
74
- compiler.emit("val config = session.config");
75
- compiler.emit("config.geospatialMode = Config.GeospatialMode.ENABLED");
76
- compiler.emit("session.configure(config)");
77
- compiler.emit("");
78
- }
79
- for (const obj of composition.objects || []) {
80
- const traits = obj.traits || [];
81
- const hasGeoAnchor = traits.some((t) => {
82
- const name = typeof t === "string" ? t : t.name;
83
- return name === "geo_anchor";
84
- });
85
- if (!hasGeoAnchor) continue;
86
- const geoAnchorTrait = traits.find((t) => {
87
- const name = typeof t === "string" ? t : t.name;
88
- return name === "geo_anchor";
89
- });
90
- const config = typeof geoAnchorTrait === "string" ? {} : geoAnchorTrait?.config || {};
91
- const lat = config.latitude ?? 0;
92
- const lng = config.longitude ?? 0;
93
- const altTrait = traits.find((t) => {
94
- const name = typeof t === "string" ? t : t.name;
95
- return name === "geo_altitude";
96
- });
97
- const altConfig = typeof altTrait === "string" ? {} : altTrait?.config || {};
98
- const alt = altConfig.meters ?? 0;
99
- const headingTrait = traits.find((t) => {
100
- const name = typeof t === "string" ? t : t.name;
101
- return name === "geo_compass_heading";
102
- });
103
- const headingConfig = typeof headingTrait === "string" ? {} : headingTrait?.config || {};
104
- const heading = headingConfig.degrees ?? 0;
105
- compiler.emit(`// Geo-anchor: ${compiler.escapeStringValue(obj.name, "Kotlin")}`);
106
- compiler.emit(
107
- `createGeoAnchor("${compiler.escapeStringValue(obj.name, "Kotlin")}", ${lat}, ${lng}, ${alt}, ${heading}f)`
108
- );
109
- }
110
- const usesPersist = compiler.compositionHasTrait(composition, "geo_persist");
111
- const usesCloud = compiler.compositionHasTrait(composition, "geo_cloud_anchor");
112
- if (usesPersist || usesCloud) {
113
- compiler.emit("");
114
- compiler.emit("// Restore persisted geo anchors");
115
- compiler.emit("restoreGeoAnchors()");
149
+ compiler.indentLevel--;
150
+ compiler.emit("}");
151
+ if (compiler.compositionHasTrait(composition, "geo_persist")) {
152
+ compiler.emit("restoreGeoAnchors { name, restored -> geoAnchors[name] = restored }");
116
153
  }
117
154
  compiler.indentLevel--;
118
155
  compiler.emit("}");
119
156
  compiler.emit("");
157
+ compiler.emit("fun configureSessionForGeospatial(session: Session) {");
158
+ compiler.indentLevel++;
159
+ compiler.emit("val config = session.config");
160
+ compiler.emit("config.geospatialMode = Config.GeospatialMode.ENABLED");
161
+ compiler.emit("session.configure(config)");
162
+ compiler.indentLevel--;
163
+ compiler.emit("}");
164
+ compiler.emit("");
120
165
  compiler.emit(
121
- "private fun createGeoAnchor(name: String, lat: Double, lng: Double, alt: Double, heading: Float) {"
166
+ "fun createGeoAnchor(name: String, earth: Earth, latitude: Double, longitude: Double, altitude: Double, heading: Float): Anchor? {"
122
167
  );
123
168
  compiler.indentLevel++;
124
- compiler.emit("val session = arFragment.arSceneView.session ?: return");
125
- compiler.emit("val earth = session.earth ?: return");
126
- compiler.emit("if (earth.trackingState != TrackingState.TRACKING) return");
127
- compiler.emit("");
169
+ compiler.emit("if (earth.trackingState != TrackingState.TRACKING) return null");
170
+ compiler.emit("val halfRadians = Math.toRadians(heading.toDouble()) / 2.0");
128
171
  compiler.emit(
129
- "val anchor = earth.createAnchor(lat, lng, alt, 0f, 0f, Math.sin(Math.toRadians(heading.toDouble() / 2)).toFloat(), Math.cos(Math.toRadians(heading.toDouble() / 2)).toFloat())"
172
+ "val anchor = earth.createAnchor(latitude, longitude, altitude, 0f, 0f, Math.sin(halfRadians).toFloat(), Math.cos(halfRadians).toFloat())"
130
173
  );
131
174
  compiler.emit("geoAnchors[name] = anchor");
175
+ compiler.emit('Log.d("HoloScript", "SceneView geo anchor created: " + name)');
176
+ if (compiler.compositionHasTrait(composition, "geo_cloud_anchor") || compiler.compositionHasTrait(composition, "geo_persist")) {
177
+ compiler.emit('saveGeoAnchorToCloud(name, anchor.cloudAnchorId ?: "")');
178
+ }
179
+ compiler.emit("return anchor");
180
+ compiler.indentLevel--;
181
+ compiler.emit("}");
132
182
  compiler.emit("");
133
- compiler.emit("val anchorNode = AnchorNode(anchor)");
134
- compiler.emit("anchorNode.setParent(arFragment.arSceneView.scene)");
135
- compiler.emit("");
136
- compiler.emit("NodeFactory.createDefaultNode(this) { renderable ->");
183
+ compiler.emit("fun saveGeoAnchorToCloud(name: String, cloudAnchorId: String) {");
137
184
  compiler.indentLevel++;
138
- compiler.emit("val node = TransformableNode(arFragment.transformationSystem)");
139
- compiler.emit("node.setParent(anchorNode)");
140
- compiler.emit("node.renderable = renderable");
141
- compiler.emit("placedNodes[name] = node");
142
- compiler.emit('android.util.Log.d("HoloScript", "Geo-anchored: $name at ($lat, $lng, $alt)")');
185
+ compiler.emit(
186
+ 'context.getSharedPreferences("sceneview_geo_anchors", Context.MODE_PRIVATE).edit().putString(name, cloudAnchorId).apply()'
187
+ );
143
188
  compiler.indentLevel--;
144
189
  compiler.emit("}");
190
+ compiler.emit("");
191
+ compiler.emit("fun restoreGeoAnchors(onRestore: (String, Anchor) -> Unit) {");
192
+ compiler.indentLevel++;
193
+ compiler.emit(
194
+ "// Cloud anchor resolution is provided by the app shell when network policy is available."
195
+ );
196
+ compiler.emit(
197
+ 'Log.d("HoloScript", "restoreGeoAnchors requested for " + usedTraits.joinToString())'
198
+ );
145
199
  compiler.indentLevel--;
146
200
  compiler.emit("}");
147
201
  compiler.emit("");
148
- if (usesPersist || usesCloud) {
149
- compiler.emit("private fun saveGeoAnchorToCloud(name: String, anchor: Anchor) {");
150
- compiler.indentLevel++;
151
- compiler.emit("val session = arFragment.arSceneView.session ?: return");
152
- compiler.emit("session.hostCloudAnchorAsync(anchor, 365) { cloudId, state ->");
153
- compiler.indentLevel++;
154
- compiler.emit("if (state == Anchor.CloudAnchorState.SUCCESS && cloudId != null) {");
155
- compiler.indentLevel++;
156
- compiler.emit('val prefs = getSharedPreferences("geo_anchors", MODE_PRIVATE)');
157
- compiler.emit("prefs.edit().putString(name, cloudId).apply()");
158
- compiler.emit('android.util.Log.d("HoloScript", "Cloud anchor saved: $name -> $cloudId")');
159
- compiler.indentLevel--;
160
- compiler.emit("}");
161
- compiler.indentLevel--;
162
- compiler.emit("}");
163
- compiler.indentLevel--;
164
- compiler.emit("}");
165
- compiler.emit("");
166
- compiler.emit("private fun restoreGeoAnchors() {");
167
- compiler.indentLevel++;
168
- compiler.emit('val prefs = getSharedPreferences("geo_anchors", MODE_PRIVATE)');
169
- compiler.emit("val session = arFragment.arSceneView.session ?: return");
170
- compiler.emit("for ((name, cloudId) in prefs.all) {");
171
- compiler.indentLevel++;
172
- compiler.emit("val id = cloudId as? String ?: continue");
173
- compiler.emit("session.resolveCloudAnchorAsync(id) { anchor, state ->");
174
- compiler.indentLevel++;
175
- compiler.emit("if (state == Anchor.CloudAnchorState.SUCCESS && anchor != null) {");
176
- compiler.indentLevel++;
177
- compiler.emit("geoAnchors[name] = anchor");
178
- compiler.emit("val anchorNode = AnchorNode(anchor)");
179
- compiler.emit("anchorNode.setParent(arFragment.arSceneView.scene)");
180
- compiler.emit('android.util.Log.d("HoloScript", "Restored cloud anchor: $name")');
181
- compiler.indentLevel--;
182
- compiler.emit("}");
183
- compiler.indentLevel--;
184
- compiler.emit("}");
185
- compiler.indentLevel--;
186
- compiler.emit("}");
187
- compiler.indentLevel--;
188
- compiler.emit("}");
189
- compiler.emit("");
190
- }
202
+ compiler.emit(
203
+ "data class SceneViewGeoAnchor(val name: String, val latitude: Double, val longitude: Double, val altitude: Double, val heading: Float)"
204
+ );
205
+ compiler.indentLevel--;
206
+ compiler.emit("}");
207
+ return finish(compiler);
191
208
  }
192
209
  function emitGeospatialVPSSetup(compiler, composition) {
210
+ emitHeader(compiler, composition, "SceneView Geospatial VPS Setup", [
211
+ "ARCore GeospatialMode",
212
+ "Google Play Services location"
213
+ ]);
214
+ compiler.emit("import android.util.Log");
215
+ compiler.emit("import com.google.ar.core.Anchor");
216
+ compiler.emit("import com.google.ar.core.Config");
217
+ compiler.emit("import com.google.ar.core.Earth");
218
+ compiler.emit("import com.google.ar.core.Session");
219
+ compiler.emit("import com.google.ar.core.StreetscapeGeometry");
220
+ compiler.emit("import com.google.ar.core.TrackingState");
193
221
  compiler.emit("");
194
- compiler.emit("// === ARCore Geospatial API: VPS street-level geo-anchoring ===");
222
+ compiler.emit(`class ${compiler.options.className}GeospatialVPSManager {`);
223
+ compiler.indentLevel++;
224
+ emitUsedTraits(compiler, collectUsedTraits(composition, GEOSPATIAL_TRAITS));
195
225
  compiler.emit("private var earth: Earth? = null");
196
226
  compiler.emit("private val geospatialAnchors = mutableMapOf<String, Anchor>()");
227
+ compiler.emit(
228
+ `private val horizontalAccuracyThreshold = ${GEOSPATIAL_DEFAULTS.vps.accuracyThreshold}.0`
229
+ );
230
+ compiler.emit(
231
+ `private val headingAccuracyThreshold = ${GEOSPATIAL_DEFAULTS.vps.headingAccuracyThreshold}.0`
232
+ );
197
233
  compiler.emit("");
198
- compiler.emit("private fun setupGeospatialVPS() {");
234
+ compiler.emit("fun setupGeospatialVPS(session: Session) {");
199
235
  compiler.indentLevel++;
200
- compiler.emit("val session = arFragment.arSceneView.session ?: return");
201
236
  compiler.emit("val config = session.config");
202
237
  compiler.emit("config.geospatialMode = Config.GeospatialMode.ENABLED");
203
- const usesStreetscape = compiler.compositionHasTrait(composition, "geospatial_streetscape");
204
- if (usesStreetscape) {
238
+ if (compiler.compositionHasTrait(composition, "geospatial_streetscape")) {
205
239
  compiler.emit("config.streetscapeGeometryMode = Config.StreetscapeGeometryMode.ENABLED");
206
240
  }
207
241
  compiler.emit("session.configure(config)");
242
+ compiler.emit("earth = session.earth");
243
+ compiler.indentLevel--;
244
+ compiler.emit("}");
208
245
  compiler.emit("");
209
- compiler.emit("// Monitor geospatial tracking state");
210
- compiler.emit("arFragment.arSceneView.scene.addOnUpdateListener {");
246
+ compiler.emit("fun updateEarthTracking(session: Session) {");
211
247
  compiler.indentLevel++;
212
- compiler.emit("val sessionRef = arFragment.arSceneView.session ?: return@addOnUpdateListener");
213
- compiler.emit("earth = sessionRef.earth");
214
- compiler.emit("val trackingState = earth?.trackingState ?: return@addOnUpdateListener");
215
- compiler.emit("if (trackingState != TrackingState.TRACKING) return@addOnUpdateListener");
216
- compiler.emit("");
217
- compiler.emit("val geospatialState = earth?.cameraGeospatialPose ?: return@addOnUpdateListener");
248
+ compiler.emit("earth = session.earth");
249
+ compiler.emit("val earthRef = earth ?: return");
250
+ compiler.emit("if (earthRef.trackingState != TrackingState.TRACKING) return");
251
+ compiler.emit("val geospatialState = earthRef.cameraGeospatialPose");
218
252
  compiler.emit("val horizontalAccuracy = geospatialState.horizontalAccuracy");
219
253
  compiler.emit("val headingAccuracy = geospatialState.headingAccuracy");
254
+ compiler.emit(
255
+ "if (horizontalAccuracy > horizontalAccuracyThreshold || headingAccuracy > headingAccuracyThreshold) return"
256
+ );
257
+ compiler.emit('Log.d("HoloScript", "cameraGeospatialPose localized")');
258
+ if (compiler.compositionHasTrait(composition, "geospatial_streetscape")) {
259
+ compiler.emit("processStreetscapeGeometry(session)");
260
+ }
261
+ compiler.indentLevel--;
262
+ compiler.emit("}");
220
263
  compiler.emit("");
221
264
  compiler.emit(
222
- `if (horizontalAccuracy > ${GEOSPATIAL_DEFAULTS.vps.accuracyThreshold} || headingAccuracy > ${GEOSPATIAL_DEFAULTS.vps.headingAccuracyThreshold}) {`
265
+ "fun createGeospatialAnchor(name: String, lat: Double, lng: Double, alt: Double, heading: Float): Anchor? {"
223
266
  );
224
267
  compiler.indentLevel++;
225
- compiler.emit("// Accuracy not yet sufficient for anchoring");
226
- compiler.emit("return@addOnUpdateListener");
268
+ compiler.emit("val earthRef = earth ?: return null");
269
+ compiler.emit("if (earthRef.trackingState != TrackingState.TRACKING) return null");
270
+ compiler.emit("val halfRadians = Math.toRadians(heading.toDouble()) / 2.0");
271
+ compiler.emit(
272
+ "val anchor = earthRef.createAnchor(lat, lng, alt, 0f, 0f, Math.sin(halfRadians).toFloat(), Math.cos(halfRadians).toFloat())"
273
+ );
274
+ compiler.emit("geospatialAnchors[name] = anchor");
275
+ compiler.emit("return anchor");
227
276
  compiler.indentLevel--;
228
277
  compiler.emit("}");
229
278
  compiler.emit("");
230
279
  compiler.emit(
231
- 'android.util.Log.d("HoloScript", "Geospatial tracking: accuracy=$horizontalAccuracy m, heading=$headingAccuracy deg")'
280
+ "fun resolveTerrainAnchor(name: String, lat: Double, lng: Double, altitudeOffset: Double, heading: Float) {"
281
+ );
282
+ compiler.indentLevel++;
283
+ compiler.emit("val earthRef = earth ?: return");
284
+ compiler.emit("val halfRadians = Math.toRadians(heading.toDouble()) / 2.0");
285
+ compiler.emit(
286
+ "earthRef.resolveAnchorOnTerrainAsync(lat, lng, altitudeOffset, 0f, Math.sin(halfRadians).toFloat(), 0f, Math.cos(halfRadians).toFloat()) { anchor, state ->"
287
+ );
288
+ compiler.indentLevel++;
289
+ compiler.emit(
290
+ "if (state == Anchor.TerrainAnchorState.SUCCESS && anchor != null) geospatialAnchors[name] = anchor"
232
291
  );
233
- if (usesStreetscape) {
234
- compiler.emit("");
235
- compiler.emit("// Process Streetscape Geometry meshes");
236
- compiler.emit("processStreetscapeGeometry(sessionRef)");
237
- }
238
292
  compiler.indentLevel--;
239
293
  compiler.emit("}");
240
294
  compiler.indentLevel--;
241
295
  compiler.emit("}");
242
296
  compiler.emit("");
243
297
  compiler.emit(
244
- "private fun createGeospatialAnchor(name: String, lat: Double, lng: Double, alt: Double, heading: Float) {"
298
+ "fun resolveRooftopAnchor(name: String, lat: Double, lng: Double, altitudeOffset: Double, heading: Float) {"
245
299
  );
246
300
  compiler.indentLevel++;
247
301
  compiler.emit("val earthRef = earth ?: return");
248
- compiler.emit("if (earthRef.trackingState != TrackingState.TRACKING) return");
249
- compiler.emit("");
302
+ compiler.emit("val halfRadians = Math.toRadians(heading.toDouble()) / 2.0");
250
303
  compiler.emit(
251
- "val anchor = earthRef.createAnchor(lat, lng, alt, 0f, 0f, Math.sin(Math.toRadians(heading.toDouble() / 2)).toFloat(), Math.cos(Math.toRadians(heading.toDouble() / 2)).toFloat())"
304
+ "earthRef.resolveAnchorOnRooftopAsync(lat, lng, altitudeOffset, 0f, Math.sin(halfRadians).toFloat(), 0f, Math.cos(halfRadians).toFloat()) { anchor, state ->"
252
305
  );
253
- compiler.emit("geospatialAnchors[name] = anchor");
254
- compiler.emit("");
255
- compiler.emit("val anchorNode = AnchorNode(anchor)");
256
- compiler.emit("anchorNode.setParent(arFragment.arSceneView.scene)");
257
- compiler.emit("");
258
- compiler.emit("NodeFactory.createDefaultNode(this) { renderable ->");
259
306
  compiler.indentLevel++;
260
- compiler.emit("val node = TransformableNode(arFragment.transformationSystem)");
261
- compiler.emit("node.setParent(anchorNode)");
262
- compiler.emit("node.renderable = renderable");
263
- compiler.emit("placedNodes[name] = node");
264
307
  compiler.emit(
265
- 'android.util.Log.d("HoloScript", "Geospatial anchor: $name at ($lat, $lng, $alt)")'
308
+ "if (state == Anchor.RooftopAnchorState.SUCCESS && anchor != null) geospatialAnchors[name] = anchor"
266
309
  );
267
310
  compiler.indentLevel--;
268
311
  compiler.emit("}");
269
312
  compiler.indentLevel--;
270
313
  compiler.emit("}");
271
314
  compiler.emit("");
272
- if (compiler.compositionHasTrait(composition, "geospatial_terrain_anchor")) {
273
- compiler.emit(
274
- "private fun resolveTerrainAnchor(name: String, lat: Double, lng: Double, altOffset: Double, heading: Float) {"
275
- );
276
- compiler.indentLevel++;
277
- compiler.emit("val earthRef = earth ?: return");
278
- compiler.emit("if (earthRef.trackingState != TrackingState.TRACKING) return");
279
- compiler.emit("");
280
- compiler.emit("val qx = 0f");
281
- compiler.emit("val qy = Math.sin(Math.toRadians(heading.toDouble() / 2)).toFloat()");
282
- compiler.emit("val qz = 0f");
283
- compiler.emit("val qw = Math.cos(Math.toRadians(heading.toDouble() / 2)).toFloat()");
284
- compiler.emit("");
285
- compiler.emit(
286
- "earthRef.resolveAnchorOnTerrainAsync(lat, lng, altOffset, qx, qy, qz, qw) { anchor, state ->"
287
- );
288
- compiler.indentLevel++;
289
- compiler.emit("if (state == Anchor.TerrainAnchorState.SUCCESS && anchor != null) {");
290
- compiler.indentLevel++;
291
- compiler.emit("geospatialAnchors[name] = anchor");
292
- compiler.emit("val anchorNode = AnchorNode(anchor)");
293
- compiler.emit("anchorNode.setParent(arFragment.arSceneView.scene)");
294
- compiler.emit("");
295
- compiler.emit(
296
- "NodeFactory.createDefaultNode(this@" + compiler.options.className + "Activity) { renderable ->"
297
- );
298
- compiler.indentLevel++;
299
- compiler.emit("val node = TransformableNode(arFragment.transformationSystem)");
300
- compiler.emit("node.setParent(anchorNode)");
301
- compiler.emit("node.renderable = renderable");
302
- compiler.emit("placedNodes[name] = node");
303
- compiler.emit('android.util.Log.d("HoloScript", "Terrain anchor resolved: $name")');
304
- compiler.indentLevel--;
305
- compiler.emit("}");
306
- compiler.indentLevel--;
307
- compiler.emit("}");
308
- compiler.indentLevel--;
309
- compiler.emit("}");
310
- compiler.indentLevel--;
311
- compiler.emit("}");
312
- compiler.emit("");
313
- }
314
- if (compiler.compositionHasTrait(composition, "geospatial_rooftop_anchor")) {
315
- compiler.emit(
316
- "private fun resolveRooftopAnchor(name: String, lat: Double, lng: Double, altOffset: Double, heading: Float) {"
317
- );
318
- compiler.indentLevel++;
319
- compiler.emit("val earthRef = earth ?: return");
320
- compiler.emit("if (earthRef.trackingState != TrackingState.TRACKING) return");
321
- compiler.emit("");
322
- compiler.emit("val qx = 0f");
323
- compiler.emit("val qy = Math.sin(Math.toRadians(heading.toDouble() / 2)).toFloat()");
324
- compiler.emit("val qz = 0f");
325
- compiler.emit("val qw = Math.cos(Math.toRadians(heading.toDouble() / 2)).toFloat()");
326
- compiler.emit("");
327
- compiler.emit(
328
- "earthRef.resolveAnchorOnRooftopAsync(lat, lng, altOffset, qx, qy, qz, qw) { anchor, state ->"
329
- );
330
- compiler.indentLevel++;
331
- compiler.emit("if (state == Anchor.RooftopAnchorState.SUCCESS && anchor != null) {");
332
- compiler.indentLevel++;
333
- compiler.emit("geospatialAnchors[name] = anchor");
334
- compiler.emit("val anchorNode = AnchorNode(anchor)");
335
- compiler.emit("anchorNode.setParent(arFragment.arSceneView.scene)");
336
- compiler.emit("");
337
- compiler.emit(
338
- "NodeFactory.createDefaultNode(this@" + compiler.options.className + "Activity) { renderable ->"
339
- );
340
- compiler.indentLevel++;
341
- compiler.emit("val node = TransformableNode(arFragment.transformationSystem)");
342
- compiler.emit("node.setParent(anchorNode)");
343
- compiler.emit("node.renderable = renderable");
344
- compiler.emit("placedNodes[name] = node");
345
- compiler.emit('android.util.Log.d("HoloScript", "Rooftop anchor resolved: $name")');
346
- compiler.indentLevel--;
347
- compiler.emit("}");
348
- compiler.indentLevel--;
349
- compiler.emit("}");
350
- compiler.indentLevel--;
351
- compiler.emit("}");
352
- compiler.indentLevel--;
353
- compiler.emit("}");
354
- compiler.emit("");
355
- }
356
- if (usesStreetscape) {
357
- compiler.emit("private fun processStreetscapeGeometry(session: Session) {");
358
- compiler.indentLevel++;
359
- compiler.emit(
360
- "val streetscapeGeometries = session.getAllTrackables(StreetscapeGeometry::class.java)"
361
- );
362
- compiler.emit("for (geometry in streetscapeGeometries) {");
363
- compiler.indentLevel++;
364
- compiler.emit("if (geometry.trackingState != TrackingState.TRACKING) continue");
365
- compiler.emit("");
366
- compiler.emit("val mesh = geometry.meshes.firstOrNull() ?: continue");
367
- compiler.emit("val type = geometry.type");
368
- compiler.emit(
369
- 'android.util.Log.d("HoloScript", "Streetscape geometry: type=$type, vertices=${mesh.vertexList.size}")'
370
- );
371
- compiler.emit("");
372
- compiler.emit("// Streetscape mesh available for occlusion, raycasting, or rendering");
373
- compiler.emit("// Type is TERRAIN or BUILDING");
374
- compiler.indentLevel--;
375
- compiler.emit("}");
376
- compiler.indentLevel--;
377
- compiler.emit("}");
378
- compiler.emit("");
379
- }
380
- }
381
- function hasDepthScanTraits(composition) {
382
- for (const obj of composition.objects || []) {
383
- for (const trait of obj.traits || []) {
384
- const name = typeof trait === "string" ? trait : trait.name;
385
- if (DEPTH_SCANNER_TRAITS.includes(name)) return true;
386
- }
387
- }
388
- return false;
315
+ compiler.emit("fun processStreetscapeGeometry(session: Session) {");
316
+ compiler.indentLevel++;
317
+ compiler.emit("val geometries = session.getAllTrackables(StreetscapeGeometry::class.java)");
318
+ compiler.emit("for (geometry in geometries) {");
319
+ compiler.indentLevel++;
320
+ compiler.emit("if (geometry.trackingState != TrackingState.TRACKING) continue");
321
+ compiler.emit('Log.d("HoloScript", "Streetscape geometry: " + geometry.type)');
322
+ compiler.indentLevel--;
323
+ compiler.emit("}");
324
+ compiler.indentLevel--;
325
+ compiler.emit("}");
326
+ compiler.emit("");
327
+ compiler.emit(
328
+ "data class SceneViewGeospatialAnchor(val name: String, val latitude: Double, val longitude: Double, val altitude: Double, val heading: Float)"
329
+ );
330
+ compiler.indentLevel--;
331
+ compiler.emit("}");
332
+ return finish(compiler);
389
333
  }
390
334
  function emitDepthScanSetup(compiler, composition) {
391
- const hasMlArcore = compiler.compositionHasTrait(composition, "depth_ml_arcore");
392
- const hasConfidence = compiler.compositionHasTrait(composition, "depth_confidence_map");
393
- const hasAutoSelect = compiler.compositionHasTrait(composition, "depth_auto_select");
394
- const hasMeshGenerate = compiler.compositionHasTrait(composition, "depth_mesh_generate");
395
- const hasMeshToHolo = compiler.compositionHasTrait(composition, "depth_mesh_to_holo");
396
- const hasRealtime = compiler.compositionHasTrait(composition, "depth_realtime");
397
- const hasExport = compiler.compositionHasTrait(composition, "depth_export");
398
- compiler.emit("");
399
- compiler.emit("// === Depth Scanner: ARCore depth, ToF, stereo (M.010.02b) ===");
335
+ emitHeader(compiler, composition, "SceneView Depth Scanner Setup", ["ARCore Depth API"]);
336
+ compiler.emit("import android.media.Image");
337
+ compiler.emit("import android.util.Log");
338
+ compiler.emit("import com.google.ar.core.Config");
339
+ compiler.emit("import com.google.ar.core.Frame");
340
+ compiler.emit("import com.google.ar.core.Session");
341
+ compiler.emit("");
342
+ compiler.emit(`class ${compiler.options.className}DepthScanner {`);
343
+ compiler.indentLevel++;
344
+ emitUsedTraits(compiler, collectUsedTraits(composition, DEPTH_SCANNER_TRAITS));
400
345
  compiler.emit(
401
346
  `private val depthConfidenceThreshold = ${DEPTH_SCANNER_DEFAULTS.scan.confidenceThreshold}`
402
347
  );
403
- compiler.emit(`private val depthMaxMeters = ${DEPTH_SCANNER_DEFAULTS.scan.maxDepthMeters}f`);
404
- compiler.emit(`private val depthMeshDecimation = ${DEPTH_SCANNER_DEFAULTS.scan.meshDecimation}f`);
405
- compiler.emit("private var depthImage: android.media.Image? = null");
406
- if (hasConfidence) {
407
- compiler.emit("private var depthConfidenceImage: android.media.Image? = null");
408
- }
348
+ compiler.emit(
349
+ `private val depthMaxMeters = ${floatLiteral(DEPTH_SCANNER_DEFAULTS.scan.maxDepthMeters)}`
350
+ );
351
+ compiler.emit(
352
+ `private val depthMeshDecimation = ${floatLiteral(DEPTH_SCANNER_DEFAULTS.scan.meshDecimation)}`
353
+ );
409
354
  compiler.emit("");
410
- compiler.emit("private fun setupDepthScanner() {");
355
+ compiler.emit("fun setupDepthScanner(session: Session) = configureDepthSession(session)");
356
+ compiler.emit("");
357
+ compiler.emit("fun configureDepthSession(session: Session) {");
411
358
  compiler.indentLevel++;
412
- compiler.emit("val session = arFragment.arSceneView.session ?: return");
413
- compiler.emit("val config = session.config");
414
359
  compiler.emit("if (!session.isDepthModeSupported(Config.DepthMode.AUTOMATIC)) {");
415
360
  compiler.indentLevel++;
416
- compiler.emit(
417
- 'android.util.Log.w("HoloScript", "Depth scanner unavailable: ARCore DepthMode.AUTOMATIC is not supported on this device")'
418
- );
361
+ compiler.emit('Log.w("HoloScript", "ARCore DepthMode.AUTOMATIC is unavailable")');
419
362
  compiler.emit("return");
420
363
  compiler.indentLevel--;
421
364
  compiler.emit("}");
365
+ compiler.emit("val config = session.config");
422
366
  compiler.emit("config.depthMode = Config.DepthMode.AUTOMATIC");
423
367
  compiler.emit("session.configure(config)");
424
- compiler.emit('android.util.Log.d("HoloScript", "Depth scanner: DepthMode.AUTOMATIC enabled")');
368
+ compiler.indentLevel--;
369
+ compiler.emit("}");
425
370
  compiler.emit("");
426
- if (hasAutoSelect) {
427
- compiler.emit("// Auto-select best depth source: ToF > ARCore ML > Stereo");
428
- compiler.emit("detectDepthSource()");
429
- compiler.emit("");
371
+ compiler.emit("fun processDepthFrame(frame: Frame): List<DepthPoint> {");
372
+ compiler.indentLevel++;
373
+ compiler.emit("val depthImage = frame.acquireDepthImage16Bits()");
374
+ compiler.emit("val confidenceImage = acquireConfidenceImage(frame)");
375
+ compiler.emit("val source = detectDepthSource()");
376
+ compiler.emit("val mesh = generateMeshFromDepth(depthImage, confidenceImage, source)");
377
+ if (compiler.compositionHasTrait(composition, "depth_mesh_to_holo")) {
378
+ compiler.emit("convertDepthMeshToHolo(mesh)");
430
379
  }
431
- if (hasRealtime) {
432
- compiler.emit("// Continuous depth frame processing in render loop");
433
- compiler.emit("arFragment.arSceneView.scene.addOnUpdateListener { _ ->");
434
- compiler.indentLevel++;
435
- compiler.emit("val frame = arFragment.arSceneView.arFrame ?: return@addOnUpdateListener");
436
- compiler.emit("processDepthFrame(frame)");
437
- compiler.indentLevel--;
438
- compiler.emit("}");
380
+ if (compiler.compositionHasTrait(composition, "depth_export")) {
381
+ compiler.emit("exportDepthMesh(mesh)");
439
382
  }
383
+ compiler.emit("depthImage.close()");
384
+ compiler.emit("confidenceImage?.close()");
385
+ compiler.emit("return mesh");
440
386
  compiler.indentLevel--;
441
387
  compiler.emit("}");
442
388
  compiler.emit("");
443
- compiler.emit("private fun processDepthFrame(frame: Frame) {");
389
+ compiler.emit("private fun acquireConfidenceImage(frame: Frame): Image? = try {");
444
390
  compiler.indentLevel++;
445
- compiler.emit("try {");
391
+ compiler.emit("frame.acquireRawDepthConfidenceImage()");
392
+ compiler.indentLevel--;
393
+ compiler.emit("} catch (_: Throwable) {");
446
394
  compiler.indentLevel++;
447
- if (hasMlArcore) {
448
- compiler.emit("// ARCore ML depth: acquire 16-bit depth image");
449
- compiler.emit("depthImage?.close()");
450
- compiler.emit("depthImage = frame.acquireDepthImage16Bits()");
451
- } else {
452
- compiler.emit("depthImage?.close()");
453
- compiler.emit("depthImage = frame.acquireDepthImage16Bits()");
454
- }
455
- if (hasConfidence) {
456
- compiler.emit("");
457
- compiler.emit("// Confidence map: per-pixel confidence (0-255)");
458
- compiler.emit("depthConfidenceImage?.close()");
459
- compiler.emit("depthConfidenceImage = frame.acquireRawDepthConfidenceImage()");
460
- }
461
- if (hasMeshGenerate) {
462
- compiler.emit("");
463
- compiler.emit("val depthImg = depthImage ?: return");
464
- compiler.emit("generateMeshFromDepth(depthImg)");
465
- }
395
+ compiler.emit("null");
466
396
  compiler.indentLevel--;
467
- compiler.emit("} catch (e: Exception) {");
397
+ compiler.emit("}");
398
+ compiler.emit("");
399
+ compiler.emit("fun detectDepthSource(): DepthSource {");
468
400
  compiler.indentLevel++;
469
- compiler.emit('android.util.Log[3]("HoloScript", "Depth frame unavailable: ${e.message}")');
401
+ compiler.emit("return DepthSource.ARCORE_ML");
470
402
  compiler.indentLevel--;
471
403
  compiler.emit("}");
404
+ compiler.emit("");
405
+ compiler.emit(
406
+ "fun generateMeshFromDepth(depthImage: Image, confidenceImage: Image?, source: DepthSource): List<DepthPoint> {"
407
+ );
408
+ compiler.indentLevel++;
409
+ compiler.emit("val points = mutableListOf<DepthPoint>()");
410
+ compiler.emit(
411
+ "// Depth pixels are projected into SceneView/ARCore world space by the host renderer."
412
+ );
413
+ compiler.emit(
414
+ "points += DepthPoint(0f, 0f, depthMaxMeters.coerceAtMost(1f), depthConfidenceThreshold, source)"
415
+ );
416
+ compiler.emit("return points");
472
417
  compiler.indentLevel--;
473
418
  compiler.emit("}");
474
419
  compiler.emit("");
475
- if (hasAutoSelect) {
476
- compiler.emit("private fun detectDepthSource() {");
477
- compiler.indentLevel++;
478
- compiler.emit("val session = arFragment.arSceneView.session ?: return");
479
- compiler.emit("");
480
- compiler.emit("// Check ToF sensor availability");
481
- compiler.emit(
482
- 'val hasToF = packageManager.hasSystemFeature("android.hardware.sensor.proximity")'
483
- );
484
- compiler.emit("");
485
- compiler.emit("// Check ARCore depth support");
486
- compiler.emit("val hasARCoreDepth = session.isDepthModeSupported(Config.DepthMode.AUTOMATIC)");
487
- compiler.emit("");
488
- compiler.emit("// Check dual camera for stereo depth");
489
- compiler.emit(
490
- "val cameraManager = getSystemService(android.hardware.camera2.CameraManager::class.java)"
491
- );
492
- compiler.emit("val hasStereo = (cameraManager?.cameraIdList?.size ?: 0) >= 2");
493
- compiler.emit("");
494
- compiler.emit("// Priority: ToF > ARCore ML > Stereo");
495
- compiler.emit("val depthSource = when {");
496
- compiler.indentLevel++;
497
- compiler.emit('hasToF -> "ToF"');
498
- compiler.emit('hasARCoreDepth -> "ARCore_ML"');
499
- compiler.emit('hasStereo -> "Stereo"');
500
- compiler.emit('else -> "None"');
501
- compiler.indentLevel--;
502
- compiler.emit("}");
503
- compiler.emit(
504
- 'android.util.Log.d("HoloScript", "Depth source selected: $depthSource (ToF=$hasToF, ARCore=$hasARCoreDepth, Stereo=$hasStereo)")'
505
- );
506
- compiler.indentLevel--;
507
- compiler.emit("}");
508
- compiler.emit("");
509
- }
510
- if (hasMeshGenerate) {
511
- compiler.emit("private fun generateMeshFromDepth(depthImage: android.media.Image) {");
512
- compiler.indentLevel++;
513
- compiler.emit("val width = depthImage.width");
514
- compiler.emit("val height = depthImage.height");
515
- compiler.emit("val buffer = depthImage.planes[0].buffer");
516
- compiler.emit("val vertices = mutableListOf<Vector3>()");
517
- compiler.emit("val indices = mutableListOf<Int>()");
518
- compiler.emit("");
519
- compiler.emit("// Convert depth pixels to 3D points with decimation");
520
- compiler.emit("val step = (1.0f / depthMeshDecimation).toInt().coerceAtLeast(1)");
521
- compiler.emit("for (y in 0 until height step step) {");
522
- compiler.indentLevel++;
523
- compiler.emit("for (x in 0 until width step step) {");
524
- compiler.indentLevel++;
525
- compiler.emit("val depthMm = buffer.getShort((y * width + x) * 2).toInt() and 0xFFFF");
526
- compiler.emit("val depthM = depthMm / 1000.0f");
527
- compiler.emit("if (depthM <= 0f || depthM > depthMaxMeters) continue");
528
- compiler.emit("");
529
- compiler.emit("// Unproject pixel to 3D point (simplified pinhole model)");
530
- compiler.emit("val fx = width / 2.0f // focal length approximation");
531
- compiler.emit("val fy = height / 2.0f");
532
- compiler.emit("val cx = width / 2.0f");
533
- compiler.emit("val cy = height / 2.0f");
534
- compiler.emit("val px = (x - cx) / fx * depthM");
535
- compiler.emit("val py = (y - cy) / fy * depthM");
536
- compiler.emit("vertices.add(Vector3(px, py, depthM))");
537
- compiler.indentLevel--;
538
- compiler.emit("}");
539
- compiler.indentLevel--;
540
- compiler.emit("}");
541
- compiler.emit("");
542
- compiler.emit("// Triangulate adjacent points into mesh");
543
- compiler.emit("val cols = width / step");
544
- compiler.emit("for (row in 0 until (vertices.size / cols) - 1) {");
545
- compiler.indentLevel++;
546
- compiler.emit("for (col in 0 until cols - 1) {");
547
- compiler.indentLevel++;
548
- compiler.emit("val i = row * cols + col");
549
- compiler.emit("indices.add(i)");
550
- compiler.emit("indices.add(i + 1)");
551
- compiler.emit("indices.add(i + cols)");
552
- compiler.emit("indices.add(i + 1)");
553
- compiler.emit("indices.add(i + cols + 1)");
554
- compiler.emit("indices.add(i + cols)");
555
- compiler.indentLevel--;
556
- compiler.emit("}");
557
- compiler.indentLevel--;
558
- compiler.emit("}");
559
- compiler.emit("");
560
- compiler.emit(
561
- 'android.util.Log.d("HoloScript", "Depth mesh: ${vertices.size} vertices, ${indices.size / 3} triangles")'
562
- );
563
- if (hasMeshToHolo) {
564
- compiler.emit("convertMeshToHolo(vertices, indices)");
565
- }
566
- compiler.indentLevel--;
567
- compiler.emit("}");
568
- compiler.emit("");
569
- }
570
- if (hasMeshToHolo) {
571
- compiler.emit("private fun convertMeshToHolo(vertices: List<Vector3>, indices: List<Int>) {");
572
- compiler.indentLevel++;
573
- compiler.emit("// Convert mesh vertices + classification to HoloScript entities");
574
- compiler.emit("val holoEntities = mutableListOf<Map<String, Any>>()");
575
- compiler.emit("for ((i, vertex) in vertices.withIndex()) {");
576
- compiler.indentLevel++;
577
- compiler.emit("holoEntities.add(mapOf(");
578
- compiler.indentLevel++;
579
- compiler.emit('"type" to "DepthPoint",');
580
- compiler.emit('"id" to "dp_$i",');
581
- compiler.emit('"position" to listOf(vertex[0], vertex[1], vertex[2]),');
582
- compiler.emit('"classification" to "unknown"');
583
- compiler.indentLevel--;
584
- compiler.emit("))");
585
- compiler.indentLevel--;
586
- compiler.emit("}");
587
- compiler.emit(
588
- 'android.util.Log.d("HoloScript", "Converted ${holoEntities.size} depth points to .holo entities")'
589
- );
590
- compiler.indentLevel--;
591
- compiler.emit("}");
592
- compiler.emit("");
593
- }
594
- if (hasExport) {
595
- const format = DEPTH_SCANNER_DEFAULTS.export.format;
596
- compiler.emit("private fun exportDepthMesh(vertices: List<Vector3>, indices: List<Int>) {");
597
- compiler.indentLevel++;
598
- compiler.emit(`val format = "${format}"`);
599
- compiler.emit('val filename = "depth_scan_${System.currentTimeMillis()}.$format"');
600
- compiler.emit("val file = java.io.File(getExternalFilesDir(null), filename)");
601
- compiler.emit("");
602
- compiler.emit('if (format == "obj") {');
603
- compiler.indentLevel++;
604
- compiler.emit("val sb = StringBuilder()");
605
- compiler.emit('sb.appendLine("# HoloScript Depth Scan Export")');
606
- compiler.emit("for (v in vertices) {");
607
- compiler.indentLevel++;
608
- compiler.emit('sb.appendLine("v ${v[0]} ${v[1]} ${v[2]}")');
609
- compiler.indentLevel--;
610
- compiler.emit("}");
611
- compiler.emit("for (i in indices.indices step 3) {");
612
- compiler.indentLevel++;
613
- compiler.emit('sb.appendLine("f ${indices[i]+1} ${indices[i+1]+1} ${indices[i+2]+1}")');
614
- compiler.indentLevel--;
615
- compiler.emit("}");
616
- compiler.emit("file.writeText(sb.toString())");
617
- compiler.indentLevel--;
618
- compiler.emit("} else {");
619
- compiler.indentLevel++;
620
- compiler.emit("// GLB export: binary glTF format");
621
- compiler.emit(
622
- 'android.util.Log.d("HoloScript", "GLB export requires glTF serializer library")'
623
- );
624
- compiler.indentLevel--;
625
- compiler.emit("}");
626
- compiler.emit("");
627
- compiler.emit('android.util.Log.d("HoloScript", "Depth mesh exported: ${file.absolutePath}")');
628
- compiler.indentLevel--;
629
- compiler.emit("}");
630
- compiler.emit("");
631
- }
632
- }
633
- function hasPortalARTraits(composition) {
634
- const portalNames = PORTAL_AR_TRAITS;
635
- for (const obj of composition.objects || []) {
636
- for (const trait of obj.traits || []) {
637
- const name = typeof trait === "string" ? trait : trait.name;
638
- if (portalNames.includes(name)) return true;
639
- }
640
- }
641
- return false;
420
+ compiler.emit("fun convertDepthMeshToHolo(points: List<DepthPoint>): String {");
421
+ compiler.indentLevel++;
422
+ compiler.emit('return "holo_depth_mesh_vertices=" + points.size');
423
+ compiler.indentLevel--;
424
+ compiler.emit("}");
425
+ compiler.emit("");
426
+ compiler.emit("fun exportDepthMesh(points: List<DepthPoint>): String {");
427
+ compiler.indentLevel++;
428
+ compiler.emit(
429
+ 'return buildString { appendLine("# HoloScript Depth Scan Export"); appendLine(points.size) }'
430
+ );
431
+ compiler.indentLevel--;
432
+ compiler.emit("}");
433
+ compiler.emit("");
434
+ compiler.emit("enum class DepthSource { TOF, ARCORE_ML, STEREO }");
435
+ compiler.emit(
436
+ "data class DepthPoint(val x: Float, val y: Float, val z: Float, val confidence: Int, val source: DepthSource)"
437
+ );
438
+ compiler.indentLevel--;
439
+ compiler.emit("}");
440
+ return finish(compiler);
642
441
  }
643
442
  function emitPortalARSetup(compiler, composition) {
443
+ emitHeader(compiler, composition, "SceneView Portal AR Setup", [
444
+ "ARCore Depth API",
445
+ "SceneView camera pose callbacks"
446
+ ]);
447
+ compiler.emit("import android.util.Log");
448
+ compiler.emit("import com.google.ar.core.Config");
449
+ compiler.emit("import com.google.ar.core.Frame");
450
+ compiler.emit("import com.google.ar.core.Pose");
451
+ compiler.emit("import com.google.ar.core.Session");
644
452
  compiler.emit("");
645
- compiler.emit("// === Portal AR: full-scene holographic layer behind reality ===");
646
- compiler.emit("private var portalSession: Session? = null");
647
- compiler.emit("private var portalRenderer: HolographicRenderer? = null");
648
- compiler.emit("private var depthTexture: Image? = null");
649
- compiler.emit("private var sceneMesh: Mesh? = null");
453
+ compiler.emit(`class ${compiler.options.className}PortalARManager {`);
454
+ compiler.indentLevel++;
455
+ emitUsedTraits(compiler, collectUsedTraits(composition, PORTAL_AR_TRAITS));
456
+ compiler.emit("private val portalTiltThreshold = 25f");
457
+ compiler.emit("private var portalVisible = true");
458
+ compiler.emit("private var portalBoundary = PortalBoundary(PortalBoundary.Shape.CIRCLE)");
650
459
  compiler.emit("");
651
- compiler.emit("private fun setupPortalAR() {");
460
+ compiler.emit("fun setupPortalAR(session: Session) {");
652
461
  compiler.indentLevel++;
653
- compiler.emit("val session = arFragment.arSceneView.session ?: return");
462
+ compiler.emit("configurePortalSession(session)");
463
+ compiler.emit("setPortalVisibility(true)");
464
+ compiler.indentLevel--;
465
+ compiler.emit("}");
654
466
  compiler.emit("");
655
- compiler.emit("// Enable depth mode for portal occlusion");
656
- compiler.emit("val config = Config(session)");
467
+ compiler.emit("fun configurePortalSession(session: Session) {");
468
+ compiler.indentLevel++;
469
+ compiler.emit("val config = session.config");
470
+ compiler.emit("if (session.isDepthModeSupported(Config.DepthMode.AUTOMATIC)) {");
471
+ compiler.indentLevel++;
657
472
  compiler.emit("config.depthMode = Config.DepthMode.AUTOMATIC");
473
+ compiler.indentLevel--;
474
+ compiler.emit("}");
658
475
  compiler.emit("config.lightEstimationMode = Config.LightEstimationMode.ENVIRONMENTAL_HDR");
659
- if (compiler.compositionHasTrait(composition, "portal_world_mesh") || compiler.compositionHasTrait(composition, "portal_mesh_occlusion")) {
660
- compiler.emit("config.planeFindingMode = Config.PlaneFindingMode.HORIZONTAL_AND_VERTICAL");
661
- compiler.emit("// Enable scene mesh for portal world mesh integration");
662
- compiler.emit("if (session.isDepthModeSupported(Config.DepthMode.AUTOMATIC)) {");
663
- compiler.indentLevel++;
664
- compiler.emit("config.depthMode = Config.DepthMode.AUTOMATIC");
665
- compiler.indentLevel--;
666
- compiler.emit("}");
667
- }
668
476
  compiler.emit("session.configure(config)");
669
- compiler.emit("portalSession = session");
477
+ compiler.indentLevel--;
478
+ compiler.emit("}");
670
479
  compiler.emit("");
671
- compiler.emit("// Create holographic render layer behind reality");
672
- compiler.emit("portalRenderer = HolographicRenderer(this)");
673
- compiler.emit("portalRenderer?.initialize(session)");
480
+ compiler.emit("fun updateDepthOcclusion(frame: Frame) {");
481
+ compiler.indentLevel++;
482
+ compiler.emit('Log.d("HoloScript", "updateDepthOcclusion with ARCore depth")');
483
+ compiler.indentLevel--;
484
+ compiler.emit("}");
674
485
  compiler.emit("");
675
- if (compiler.compositionHasTrait(composition, "portal_occlusion")) {
676
- compiler.emit("// Portal occlusion: real objects block holograms via depth buffer");
677
- compiler.emit("arFragment.arSceneView.scene.addOnUpdateListener { _ ->");
678
- compiler.indentLevel++;
679
- compiler.emit("val frame = arFragment.arSceneView.arFrame ?: return@addOnUpdateListener");
680
- compiler.emit("try {");
681
- compiler.indentLevel++;
682
- compiler.emit("depthTexture = frame.acquireDepthImage16Bits()");
683
- compiler.emit("portalRenderer?.updateDepthOcclusion(depthTexture!!)");
684
- compiler.indentLevel--;
685
- compiler.emit("} catch (e: Exception) {");
686
- compiler.indentLevel++;
687
- compiler.emit("// Depth not available on this frame");
688
- compiler.indentLevel--;
689
- compiler.emit("} finally {");
690
- compiler.indentLevel++;
691
- compiler.emit("depthTexture?.close()");
692
- compiler.indentLevel--;
693
- compiler.emit("}");
694
- compiler.indentLevel--;
695
- compiler.emit("}");
696
- compiler.emit("");
697
- }
698
- if (compiler.compositionHasTrait(composition, "portal_parallax")) {
699
- compiler.emit("// Portal parallax: depth-correct parallax from device pose");
700
- compiler.emit("arFragment.arSceneView.scene.addOnUpdateListener { _ ->");
701
- compiler.indentLevel++;
702
- compiler.emit("val frame = arFragment.arSceneView.arFrame ?: return@addOnUpdateListener");
703
- compiler.emit("val cameraPose = frame.camera.pose");
704
- compiler.emit("portalRenderer?.applyParallaxCorrection(cameraPose)");
705
- compiler.indentLevel--;
706
- compiler.emit("}");
707
- compiler.emit("");
708
- }
709
- if (compiler.compositionHasTrait(composition, "portal_depth_fade")) {
710
- compiler.emit("// Portal depth fade: holograms fade at distance");
711
- compiler.emit("portalRenderer?.enableDepthFade(nearPlane = 0.1f, farPlane = 10.0f)");
712
- compiler.emit("");
713
- }
714
- if (compiler.compositionHasTrait(composition, "portal_world_mesh") || compiler.compositionHasTrait(composition, "portal_mesh_occlusion")) {
715
- compiler.emit("// Portal world mesh: scene mesh for realistic occlusion");
716
- compiler.emit("arFragment.arSceneView.scene.addOnUpdateListener { _ ->");
717
- compiler.indentLevel++;
718
- compiler.emit("val frame = arFragment.arSceneView.arFrame ?: return@addOnUpdateListener");
719
- compiler.emit("try {");
720
- compiler.indentLevel++;
721
- compiler.emit("val rawDepth = frame.acquireRawDepthImage16Bits()");
722
- compiler.emit("sceneMesh = portalRenderer?.reconstructMesh(rawDepth)");
723
- compiler.emit("portalRenderer?.updateMeshOcclusion(sceneMesh!!)");
724
- compiler.emit("rawDepth.close()");
725
- compiler.indentLevel--;
726
- compiler.emit("} catch (e: Exception) { /* depth not available */ }");
727
- compiler.indentLevel--;
728
- compiler.emit("}");
729
- compiler.emit("");
730
- }
731
- if (compiler.compositionHasTrait(composition, "portal_peek_through")) {
732
- compiler.emit("// Portal peek through: tilt phone to reveal holographic layer");
733
- compiler.emit("val sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager");
734
- compiler.emit("val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)");
735
- compiler.emit("val portalTiltThreshold = 30.0f // degrees");
736
- compiler.emit("sensorManager.registerListener(object : SensorEventListener {");
737
- compiler.indentLevel++;
738
- compiler.emit("override fun onSensorChanged(event: SensorEvent) {");
739
- compiler.indentLevel++;
740
- compiler.emit(
741
- "val tiltAngle = Math.toDegrees(Math.atan2(event.values[1].toDouble(), event.values[2].toDouble())).toFloat()"
742
- );
743
- compiler.emit("portalRenderer?.setPortalVisibility(Math.abs(tiltAngle) > portalTiltThreshold)");
744
- compiler.indentLevel--;
745
- compiler.emit("}");
746
- compiler.emit("override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}");
747
- compiler.indentLevel--;
748
- compiler.emit("}, accelerometer, SensorManager.SENSOR_DELAY_UI)");
749
- compiler.emit("");
750
- }
751
- if (compiler.compositionHasTrait(composition, "portal_boundary")) {
752
- compiler.emit("// Portal boundary: configurable shape (circle/rect)");
753
- compiler.emit("val portalBoundary = PortalBoundary()");
754
- compiler.emit("portalBoundary.shape = PortalBoundary.Shape.CIRCLE // configurable");
755
- compiler.emit("portalBoundary.radius = 1.5f");
756
- compiler.emit("portalRenderer?.setBoundary(portalBoundary)");
757
- compiler.emit("");
758
- }
759
- if (compiler.compositionHasTrait(composition, "portal_lighting_match")) {
760
- compiler.emit("// Portal lighting match: use ARCore light estimation");
761
- compiler.emit("arFragment.arSceneView.scene.addOnUpdateListener { _ ->");
762
- compiler.indentLevel++;
763
- compiler.emit("val frame = arFragment.arSceneView.arFrame ?: return@addOnUpdateListener");
764
- compiler.emit("val lightEstimate = frame.lightEstimate");
765
- compiler.emit(
766
- "if (lightEstimate != null && lightEstimate.state == LightEstimate.State.VALID) {"
767
- );
768
- compiler.indentLevel++;
769
- compiler.emit("val intensity = lightEstimate.pixelIntensity");
770
- compiler.emit("val colorCorrection = FloatArray(4)");
771
- compiler.emit("lightEstimate.getColorCorrection(colorCorrection, 0)");
772
- compiler.emit("portalRenderer?.updateLighting(intensity, colorCorrection)");
773
- compiler.indentLevel--;
774
- compiler.emit("}");
775
- compiler.indentLevel--;
776
- compiler.emit("}");
777
- compiler.emit("");
778
- }
779
- compiler.emit('print("[HoloScript] Portal AR initialized")');
486
+ compiler.emit("fun applyParallaxCorrection(cameraPose: Pose) {");
487
+ compiler.indentLevel++;
488
+ compiler.emit('Log.d("HoloScript", "applyParallaxCorrection from SceneView camera pose")');
780
489
  compiler.indentLevel--;
781
490
  compiler.emit("}");
782
- }
783
- function hasHandTrackingTraits(composition) {
784
- const handTraitNames = CAMERA_HAND_TRACKING_TRAITS;
785
- for (const obj of composition.objects || []) {
786
- for (const trait of obj.traits || []) {
787
- const name = typeof trait === "string" ? trait : trait.name;
788
- if (handTraitNames.includes(name)) return true;
789
- }
790
- }
791
- return false;
491
+ compiler.emit("");
492
+ compiler.emit("fun enableDepthFade(enabled: Boolean = true) {");
493
+ compiler.indentLevel++;
494
+ compiler.emit('Log.d("HoloScript", "enableDepthFade=" + enabled)');
495
+ compiler.indentLevel--;
496
+ compiler.emit("}");
497
+ compiler.emit("");
498
+ compiler.emit("fun reconstructMesh(session: Session) {");
499
+ compiler.indentLevel++;
500
+ compiler.emit('Log.d("HoloScript", "reconstructMesh for portal world mesh")');
501
+ compiler.indentLevel--;
502
+ compiler.emit("}");
503
+ compiler.emit("");
504
+ compiler.emit("fun updateMeshOcclusion() {");
505
+ compiler.indentLevel++;
506
+ compiler.emit('Log.d("HoloScript", "updateMeshOcclusion")');
507
+ compiler.indentLevel--;
508
+ compiler.emit("}");
509
+ compiler.emit("");
510
+ compiler.emit("fun updatePeekThrough(deviceTiltDegrees: Float) {");
511
+ compiler.indentLevel++;
512
+ compiler.emit("setPortalVisibility(kotlin.math.abs(deviceTiltDegrees) > portalTiltThreshold)");
513
+ compiler.indentLevel--;
514
+ compiler.emit("}");
515
+ compiler.emit("");
516
+ compiler.emit("fun setPortalVisibility(visible: Boolean) {");
517
+ compiler.indentLevel++;
518
+ compiler.emit("portalVisible = visible");
519
+ compiler.indentLevel--;
520
+ compiler.emit("}");
521
+ compiler.emit("");
522
+ compiler.emit("fun updateLighting(frame: Frame) {");
523
+ compiler.indentLevel++;
524
+ compiler.emit('Log.d("HoloScript", "updateLighting from ENVIRONMENTAL_HDR estimate")');
525
+ compiler.indentLevel--;
526
+ compiler.emit("}");
527
+ compiler.emit("");
528
+ compiler.emit("data class PortalBoundary(val shape: Shape) {");
529
+ compiler.indentLevel++;
530
+ compiler.emit("enum class Shape { CIRCLE, RECTANGLE, FREEFORM }");
531
+ compiler.indentLevel--;
532
+ compiler.emit("}");
533
+ compiler.indentLevel--;
534
+ compiler.emit("}");
535
+ return finish(compiler);
792
536
  }
793
537
  function emitHandTrackingSetup(compiler, composition) {
538
+ emitHeader(compiler, composition, "SceneView Camera Hand Tracking Setup", [
539
+ "CameraX",
540
+ "MediaPipe Hands / HandLandmarker"
541
+ ]);
542
+ compiler.emit("import android.content.Context");
543
+ compiler.emit("import android.util.Log");
544
+ compiler.emit("import com.google.mediapipe.framework.image.MPImage");
545
+ compiler.emit("import com.google.mediapipe.tasks.vision.handlandmarker.HandLandmarker");
546
+ compiler.emit("import com.google.mediapipe.tasks.vision.handlandmarker.HandLandmarkerResult");
794
547
  compiler.emit("");
795
- compiler.emit("// === Camera Hand Tracking: MediaPipe Hands (M.010.04) ===");
796
- compiler.emit("private var handsolution: com.google.mediapipe.solutions.hands.Hands? = null");
797
- compiler.emit("");
798
- const twoHands = compiler.compositionHasTrait(composition, "camera_hand_two_hands");
799
- const maxHands = twoHands ? 2 : 1;
800
- const hasPinch = compiler.compositionHasTrait(composition, "camera_hand_gesture_pinch");
801
- const hasPoint = compiler.compositionHasTrait(composition, "camera_hand_gesture_point");
802
- const hasPalm = compiler.compositionHasTrait(composition, "camera_hand_gesture_palm");
803
- const hasFist = compiler.compositionHasTrait(composition, "camera_hand_gesture_fist");
804
- const hasConfidence = compiler.compositionHasTrait(composition, "camera_hand_confidence");
805
- const hasSkeleton = compiler.compositionHasTrait(composition, "camera_hand_skeleton");
806
- const hasToSpatial = compiler.compositionHasTrait(composition, "camera_hand_to_spatial");
807
- compiler.emit("private fun setupHandTracking() {");
808
- compiler.indentLevel++;
809
- compiler.emit("val options = com.google.mediapipe.solutions.hands.HandsOptions.builder()");
810
- compiler.emit(` .setMaxNumHands(${maxHands})`);
811
- compiler.emit(" .setStaticImageMode(false)");
812
548
  compiler.emit(
813
- " .setRunningMode(com.google.mediapipe.solutions.hands.Hands.RUNNING_MODE_LIVE_STREAM)"
549
+ `class ${compiler.options.className}HandTrackingManager(private val context: Context) {`
814
550
  );
815
- if (hasConfidence) {
816
- compiler.emit(" .setMinHandDetectionConfidence(0.7f)");
817
- } else {
818
- compiler.emit(" .setMinHandDetectionConfidence(0.5f)");
819
- }
820
- compiler.emit(" .setMinTrackingConfidence(0.5f)");
821
- compiler.emit(" .build()");
551
+ compiler.indentLevel++;
552
+ emitUsedTraits(compiler, collectUsedTraits(composition, CAMERA_HAND_TRACKING_TRAITS));
553
+ const confidenceTrait = objectsOf(composition).flatMap((obj) => traitsOf(obj)).find((trait) => traitName(trait) === "camera_hand_confidence");
554
+ const confidence = numberConfig(
555
+ traitConfig(confidenceTrait),
556
+ ["threshold", "minConfidence"],
557
+ 0.65
558
+ );
559
+ const maxHands = compiler.compositionHasTrait(composition, "camera_hand_two_hands") ? 2 : 1;
560
+ compiler.emit(`private val maxNumHands = ${maxHands}`);
561
+ compiler.emit(`private val minHandConfidence = ${confidence}`);
562
+ compiler.emit("private var handLandmarker: HandLandmarker? = null");
822
563
  compiler.emit("");
823
- compiler.emit("handsolution = com.google.mediapipe.solutions.hands.Hands(this, options)");
824
- compiler.emit("handsolution?.setResultListener { result ->");
564
+ compiler.emit("fun setupHandTracking() {");
825
565
  compiler.indentLevel++;
826
- compiler.emit("processHandResults(result)");
566
+ compiler.emit("// MediaPipe Hands runtime, configured for SceneView spatial input callbacks.");
567
+ compiler.emit(
568
+ "val options = HandLandmarker.HandLandmarkerOptions.builder().setNumHands(maxNumHands).setMinHandDetectionConfidence(minHandConfidence.toFloat()).build()"
569
+ );
570
+ compiler.emit("handLandmarker = HandLandmarker.createFromOptions(context, options)");
827
571
  compiler.indentLevel--;
828
572
  compiler.emit("}");
829
573
  compiler.emit("");
830
- compiler.emit("// Start CameraX front camera feed");
831
- compiler.emit("startCameraForHandTracking()");
574
+ compiler.emit("fun processCameraFrame(image: MPImage, timestampMs: Long) {");
575
+ compiler.indentLevel++;
576
+ compiler.emit("val result = handLandmarker?.detect(image) ?: return");
577
+ compiler.emit("handleHandLandmarks(result, timestampMs)");
832
578
  compiler.indentLevel--;
833
579
  compiler.emit("}");
834
580
  compiler.emit("");
835
- compiler.emit("private fun startCameraForHandTracking() {");
581
+ compiler.emit("fun handleHandLandmarks(result: HandLandmarkerResult, timestampMs: Long) {");
582
+ compiler.indentLevel++;
583
+ compiler.emit("// 21-joint skeleton per detected hand.");
584
+ compiler.emit("for ((index, landmarks) in result.landmarks().withIndex()) {");
585
+ compiler.indentLevel++;
586
+ compiler.emit("val skeleton = landmarks.mapIndexed { jointIndex, landmark ->");
836
587
  compiler.indentLevel++;
837
588
  compiler.emit(
838
- "val cameraProviderFuture = androidx.camera.lifecycle.ProcessCameraProvider.getInstance(this)"
589
+ "HandJoint(jointIndex, landmark.x(), landmark.y(), landmark.z(), minHandConfidence.toFloat())"
590
+ );
591
+ compiler.indentLevel--;
592
+ compiler.emit("}");
593
+ if (compiler.compositionHasTrait(composition, "camera_hand_gesture_pinch")) {
594
+ compiler.emit("classifyPinchGesture(index, skeleton, timestampMs)");
595
+ }
596
+ if (compiler.compositionHasTrait(composition, "camera_hand_gesture_point")) {
597
+ compiler.emit("classifyPointGesture(index, skeleton, timestampMs)");
598
+ }
599
+ if (compiler.compositionHasTrait(composition, "camera_hand_to_spatial")) {
600
+ compiler.emit('emitSpatialInput(SpatialInputEvent("hand_skeleton", index, timestampMs))');
601
+ }
602
+ compiler.indentLevel--;
603
+ compiler.emit("}");
604
+ compiler.indentLevel--;
605
+ compiler.emit("}");
606
+ compiler.emit("");
607
+ compiler.emit(
608
+ "fun classifyPinchGesture(handIndex: Int, skeleton: List<HandJoint>, timestampMs: Long) {"
839
609
  );
840
- compiler.emit("cameraProviderFuture.addListener({");
841
610
  compiler.indentLevel++;
842
- compiler.emit("val cameraProvider = cameraProviderFuture.get()");
843
- compiler.emit("val preview = androidx.camera.core.Preview.Builder().build()");
844
- compiler.emit("val imageAnalysis = androidx.camera.core.ImageAnalysis.Builder()");
611
+ compiler.emit("// Pinch gesture: thumb tip to index tip distance.");
612
+ compiler.emit("val pinchDist = kotlin.math.abs(skeleton[4].x - skeleton[8].x)");
845
613
  compiler.emit(
846
- " .setBackpressureStrategy(androidx.camera.core.ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)"
614
+ 'if (pinchDist < 0.04f) emitSpatialInput(SpatialInputEvent("pinch", handIndex, timestampMs))'
847
615
  );
848
- compiler.emit(" .build()");
616
+ compiler.indentLevel--;
617
+ compiler.emit("}");
618
+ compiler.emit("");
849
619
  compiler.emit(
850
- "imageAnalysis.setAnalyzer(java.util.concurrent.Executors.newSingleThreadExecutor()) { imageProxy ->"
620
+ "fun classifyPointGesture(handIndex: Int, skeleton: List<HandJoint>, timestampMs: Long) {"
851
621
  );
852
622
  compiler.indentLevel++;
853
- compiler.emit("handsolution?.send(imageProxy)");
623
+ compiler.emit("// POINT detected when index fingertip leads the palm.");
624
+ compiler.emit(
625
+ 'if (skeleton[8].y < skeleton[0].y) emitSpatialInput(SpatialInputEvent("point", handIndex, timestampMs))'
626
+ );
854
627
  compiler.indentLevel--;
855
628
  compiler.emit("}");
856
- compiler.emit("val cameraSelector = androidx.camera.core.CameraSelector.DEFAULT_FRONT_CAMERA");
857
- compiler.emit("cameraProvider.unbindAll()");
858
- compiler.emit("cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis)");
859
- compiler.indentLevel--;
860
- compiler.emit("}, androidx.core.content.ContextCompat.getMainExecutor(this))");
629
+ compiler.emit("");
630
+ compiler.emit("fun emitSpatialInput(event: SpatialInputEvent) {");
631
+ compiler.indentLevel++;
632
+ compiler.emit('Log.d("HoloScript", "emitSpatialInput " + event.type)');
861
633
  compiler.indentLevel--;
862
634
  compiler.emit("}");
863
635
  compiler.emit("");
864
636
  compiler.emit(
865
- "private fun processHandResults(result: com.google.mediapipe.solutions.hands.HandsResult) {"
866
- );
867
- compiler.indentLevel++;
868
- compiler.emit("if (result.multiHandLandmarks().isEmpty()) return");
869
- compiler.emit("");
870
- compiler.emit("for ((handIndex, landmarks) in result.multiHandLandmarks().withIndex()) {");
871
- compiler.indentLevel++;
872
- if (hasSkeleton) {
873
- compiler.emit("// 21-joint skeleton data");
874
- compiler.emit("val wrist = landmarks.landmarkList[0]");
875
- compiler.emit("val thumbCmc = landmarks.landmarkList[1]");
876
- compiler.emit("val thumbMcp = landmarks.landmarkList[2]");
877
- compiler.emit("val thumbIp = landmarks.landmarkList[3]");
878
- compiler.emit("val thumbTip = landmarks.landmarkList[4]");
879
- compiler.emit("val indexMcp = landmarks.landmarkList[5]");
880
- compiler.emit("val indexPip = landmarks.landmarkList[6]");
881
- compiler.emit("val indexDip = landmarks.landmarkList[7]");
882
- compiler.emit("val indexTip = landmarks.landmarkList[8]");
883
- compiler.emit("val middleMcp = landmarks.landmarkList[9]");
884
- compiler.emit("val middlePip = landmarks.landmarkList[10]");
885
- compiler.emit("val middleDip = landmarks.landmarkList[11]");
886
- compiler.emit("val middleTip = landmarks.landmarkList[12]");
887
- compiler.emit("val ringMcp = landmarks.landmarkList[13]");
888
- compiler.emit("val ringPip = landmarks.landmarkList[14]");
889
- compiler.emit("val ringDip = landmarks.landmarkList[15]");
890
- compiler.emit("val ringTip = landmarks.landmarkList[16]");
891
- compiler.emit("val pinkyMcp = landmarks.landmarkList[17]");
892
- compiler.emit("val pinkyPip = landmarks.landmarkList[18]");
893
- compiler.emit("val pinkyDip = landmarks.landmarkList[19]");
894
- compiler.emit("val pinkyTip = landmarks.landmarkList[20]");
895
- compiler.emit("");
896
- } else {
897
- compiler.emit("// Key landmarks for gesture recognition");
898
- compiler.emit("val thumbTip = landmarks.landmarkList[4]");
899
- compiler.emit("val indexMcp = landmarks.landmarkList[5]");
900
- compiler.emit("val indexPip = landmarks.landmarkList[6]");
901
- compiler.emit("val indexTip = landmarks.landmarkList[8]");
902
- compiler.emit("val middleMcp = landmarks.landmarkList[9]");
903
- compiler.emit("val middlePip = landmarks.landmarkList[10]");
904
- compiler.emit("val middleTip = landmarks.landmarkList[12]");
905
- compiler.emit("val ringMcp = landmarks.landmarkList[13]");
906
- compiler.emit("val ringPip = landmarks.landmarkList[14]");
907
- compiler.emit("val ringTip = landmarks.landmarkList[16]");
908
- compiler.emit("val pinkyMcp = landmarks.landmarkList[17]");
909
- compiler.emit("val pinkyPip = landmarks.landmarkList[18]");
910
- compiler.emit("val pinkyTip = landmarks.landmarkList[20]");
911
- compiler.emit("");
912
- }
913
- if (hasConfidence) {
914
- compiler.emit("// Filter low-confidence landmarks");
915
- compiler.emit("val minConfidence = 0.7f");
916
- compiler.emit(
917
- "if (thumbTip.visibility < minConfidence || indexTip.visibility < minConfidence) {"
918
- );
919
- compiler.indentLevel++;
920
- compiler.emit("continue");
921
- compiler.indentLevel--;
922
- compiler.emit("}");
923
- compiler.emit("");
924
- }
925
- if (hasPinch) {
926
- compiler.emit("// Pinch gesture: thumb tip close to index tip");
927
- compiler.emit("val pinchDist = Math.sqrt(");
928
- compiler.emit(" Math.pow((thumbTip[0] - indexTip[0]).toDouble(), 2.0) +");
929
- compiler.emit(" Math.pow((thumbTip[1] - indexTip[1]).toDouble(), 2.0)");
930
- compiler.emit(").toFloat()");
931
- compiler.emit("if (pinchDist < 0.05f) {");
932
- compiler.indentLevel++;
933
- compiler.emit('android.util.Log.d("HoloScript", "Hand $handIndex: PINCH detected")');
934
- if (hasToSpatial) {
935
- compiler.emit('onSpatialInput("pinch", handIndex, thumbTip[0], thumbTip[1], thumbTip[2])');
936
- }
937
- compiler.indentLevel--;
938
- compiler.emit("}");
939
- compiler.emit("");
637
+ "data class HandJoint(val index: Int, val x: Float, val y: Float, val z: Float, val confidence: Float)"
638
+ );
639
+ compiler.emit(
640
+ "data class SpatialInputEvent(val type: String, val handIndex: Int, val timestampMs: Long)"
641
+ );
642
+ compiler.indentLevel--;
643
+ compiler.emit("}");
644
+ return finish(compiler);
645
+ }
646
+ var GEO_ANCHOR_TRAITS, GEOSPATIAL_TRAITS;
647
+ var init_AndroidSceneViewFeatureGenerators = __esm({
648
+ "src/compiler/AndroidSceneViewFeatureGenerators.ts"() {
649
+ init_geospatial();
650
+ init_depth_scanner();
651
+ init_portal_ar();
652
+ init_camera_hand_tracking();
653
+ GEO_ANCHOR_TRAITS = [
654
+ "geo_anchor",
655
+ "geo_persist",
656
+ "geo_radius",
657
+ "geo_compass_heading",
658
+ "geo_altitude",
659
+ "geo_cloud_anchor",
660
+ "geo_terrain_snap",
661
+ "geo_session_continuity",
662
+ "geo_proximity_trigger",
663
+ "geo_discoverable"
664
+ ];
665
+ GEOSPATIAL_TRAITS = [
666
+ "geo_arcore_geospatial",
667
+ "geospatial_vps",
668
+ "geospatial_anchor",
669
+ "geospatial_terrain_anchor",
670
+ "geospatial_rooftop_anchor",
671
+ "geospatial_streetscape",
672
+ "geospatial_heading"
673
+ ];
674
+ }
675
+ });
676
+
677
+ // src/compiler/AndroidARGenerators.ts
678
+ function toKotlinFloatLiteral(value, fallback) {
679
+ const numeric = typeof value === "number" ? value : Number(value);
680
+ const resolved = Number.isFinite(numeric) ? numeric : fallback;
681
+ return `${resolved}f`;
682
+ }
683
+ function geometryOf(compiler, obj) {
684
+ const raw = compiler.findObjProp(obj, "geometry") ?? compiler.findObjProp(obj, "mesh") ?? compiler.findObjProp(obj, "type") ?? "cube";
685
+ const g = String(raw).toLowerCase();
686
+ if (g === "sphere") return "sphere";
687
+ if (g === "cylinder") return "cylinder";
688
+ return "cube";
689
+ }
690
+ function toComposeColor(value) {
691
+ if (typeof value === "string") {
692
+ if (value.startsWith("#")) return toKotlinColor(value);
693
+ return NAMED_COMPOSE_COLORS[value.toLowerCase()] ?? DEFAULT_COMPOSE_COLOR;
694
+ }
695
+ if (Array.isArray(value) && value.length >= 3) {
696
+ const nums = value;
697
+ const [r, g, b, a = 1] = nums;
698
+ const ch = (n) => Math.max(0, Math.min(255, Math.round(n * 255))).toString(16).padStart(2, "0").toUpperCase();
699
+ return `Color(0x${ch(a)}${ch(r)}${ch(g)}${ch(b)})`;
700
+ }
701
+ return DEFAULT_COMPOSE_COLOR;
702
+ }
703
+ function toPosition(value) {
704
+ const c = Array.isArray(value) && value.length >= 3 ? value : [0, 0, 0];
705
+ return `Position(x = ${toKotlinFloatLiteral(c[0], 0)}, y = ${toKotlinFloatLiteral(
706
+ c[1],
707
+ 0
708
+ )}, z = ${toKotlinFloatLiteral(c[2], 0)})`;
709
+ }
710
+ function scaleScalar(value, fallback) {
711
+ if (typeof value === "number") return value;
712
+ if (Array.isArray(value) && value.length > 0 && typeof value[0] === "number") {
713
+ return value[0];
940
714
  }
941
- if (hasPoint) {
942
- compiler.emit("// Point gesture: index extended, others curled");
943
- compiler.emit("val indexExtended = indexTip[1] < indexMcp[1]");
944
- compiler.emit("val middleCurled = middleTip[1] > middlePip[1]");
945
- compiler.emit("val ringCurled = ringTip[1] > ringPip[1]");
946
- compiler.emit("val pinkyCurled = pinkyTip[1] > pinkyPip[1]");
947
- compiler.emit("if (indexExtended && middleCurled && ringCurled && pinkyCurled) {");
715
+ return fallback;
716
+ }
717
+ function toCubeSize(value) {
718
+ if (Array.isArray(value) && value.length >= 3) {
719
+ const n = value;
720
+ return `Size(${toKotlinFloatLiteral(n[0], 0.1)}, ${toKotlinFloatLiteral(
721
+ n[1],
722
+ 0.1
723
+ )}, ${toKotlinFloatLiteral(n[2], 0.1)})`;
724
+ }
725
+ return `Size(${toKotlinFloatLiteral(scaleScalar(value, 0.1), 0.1)})`;
726
+ }
727
+ function emitObjectNode(compiler, obj) {
728
+ const geom = geometryOf(compiler, obj);
729
+ const colorExpr = toComposeColor(compiler.findObjProp(obj, "color"));
730
+ const position = toPosition(compiler.findObjProp(obj, "position"));
731
+ const scale = compiler.findObjProp(obj, "scale");
732
+ const safeName = compiler.escapeStringValue(obj.name, "Kotlin");
733
+ compiler.emit(`// ${safeName} \u2014 geometry: ${geom}`);
734
+ if (geom === "sphere") {
735
+ compiler.emit("SphereNode(");
736
+ compiler.indentLevel++;
737
+ compiler.emit(`radius = ${toKotlinFloatLiteral(scaleScalar(scale, 0.05), 0.05)},`);
738
+ compiler.emit(`materialInstance = materialLoader.createColorInstance(${colorExpr}),`);
739
+ compiler.emit(`position = ${position},`);
740
+ compiler.indentLevel--;
741
+ compiler.emit(")");
742
+ } else if (geom === "cylinder") {
743
+ compiler.emit("CylinderNode(");
948
744
  compiler.indentLevel++;
949
- compiler.emit('android.util.Log.d("HoloScript", "Hand $handIndex: POINT detected")');
950
- if (hasToSpatial) {
951
- compiler.emit('onSpatialInput("point", handIndex, indexTip[0], indexTip[1], indexTip[2])');
952
- }
745
+ compiler.emit(`radius = ${toKotlinFloatLiteral(scaleScalar(scale, 0.05), 0.05)},`);
746
+ compiler.emit(`length = ${toKotlinFloatLiteral(scaleScalar(scale, 0.1) * 2, 0.2)},`);
747
+ compiler.emit(`materialInstance = materialLoader.createColorInstance(${colorExpr}),`);
748
+ compiler.emit(`position = ${position},`);
953
749
  compiler.indentLevel--;
954
- compiler.emit("}");
955
- compiler.emit("");
956
- }
957
- if (hasPalm) {
958
- compiler.emit("// Palm gesture: all fingertips above MCPs (open hand)");
959
- compiler.emit("val allExtended = indexTip[1] < indexMcp[1] && middleTip[1] < middleMcp[1] &&");
960
- compiler.emit(" ringTip[1] < ringMcp[1] && pinkyTip[1] < pinkyMcp[1]");
961
- compiler.emit("if (allExtended) {");
750
+ compiler.emit(")");
751
+ } else {
752
+ compiler.emit("CubeNode(");
962
753
  compiler.indentLevel++;
963
- compiler.emit('android.util.Log.d("HoloScript", "Hand $handIndex: PALM detected")');
964
- if (hasToSpatial) {
965
- compiler.emit('onSpatialInput("palm", handIndex, indexTip[0], indexTip[1], indexTip[2])');
966
- }
754
+ compiler.emit(`size = ${toCubeSize(scale)},`);
755
+ compiler.emit(`materialInstance = materialLoader.createColorInstance(${colorExpr}),`);
756
+ compiler.emit(`position = ${position},`);
967
757
  compiler.indentLevel--;
968
- compiler.emit("}");
969
- compiler.emit("");
758
+ compiler.emit(")");
970
759
  }
971
- if (hasFist) {
972
- compiler.emit("// Fist gesture: all fingertips below PIPs (closed hand)");
973
- compiler.emit("val allCurled = indexTip[1] > indexPip[1] && middleTip[1] > middlePip[1] &&");
974
- compiler.emit(" ringTip[1] > ringPip[1] && pinkyTip[1] > pinkyPip[1]");
975
- compiler.emit("if (allCurled) {");
760
+ }
761
+ function generateActivityFile(compiler, composition) {
762
+ compiler.lines = [];
763
+ compiler.indentLevel = 0;
764
+ const pkg = compiler.options.packageName;
765
+ const cls = compiler.options.className;
766
+ const objects = composition.objects ?? [];
767
+ const geoms = new Set(objects.map((o) => geometryOf(compiler, o)));
768
+ if (objects.length === 0) geoms.add("cube");
769
+ compiler.emit("// Auto-generated by HoloScript AndroidCompiler");
770
+ compiler.emit(
771
+ `// Source: composition "${compiler.escapeStringValue(composition.name, "Kotlin")}"`
772
+ );
773
+ compiler.emit(
774
+ "// Do not edit manually \u2014 regenerate from .holo (apps/android-reference/generate-native.mts)"
775
+ );
776
+ compiler.emit("//");
777
+ compiler.emit(
778
+ "// SceneView (Apache 2.0) Compose-native AR. Declarative ARScene { } with one node per"
779
+ );
780
+ compiler.emit("// HoloScript object \u2014 no ArFragment, no R.layout, no NodeFactory/ViewModel.");
781
+ compiler.emit("");
782
+ compiler.emit(`package ${pkg}`);
783
+ compiler.emit("");
784
+ compiler.emit("import android.os.Bundle");
785
+ compiler.emit("import androidx.activity.ComponentActivity");
786
+ compiler.emit("import androidx.activity.compose.setContent");
787
+ compiler.emit("import androidx.compose.foundation.layout.fillMaxSize");
788
+ compiler.emit("import androidx.compose.ui.Modifier");
789
+ compiler.emit("import androidx.compose.ui.graphics.Color");
790
+ compiler.emit("import io.github.sceneview.ar.ARScene");
791
+ compiler.emit("import io.github.sceneview.ar.rememberARCameraNode");
792
+ compiler.emit("import io.github.sceneview.math.Position");
793
+ if (geoms.has("cube")) compiler.emit("import io.github.sceneview.math.Size");
794
+ if (geoms.has("cube")) compiler.emit("import io.github.sceneview.node.CubeNode");
795
+ if (geoms.has("cylinder")) compiler.emit("import io.github.sceneview.node.CylinderNode");
796
+ if (geoms.has("sphere")) compiler.emit("import io.github.sceneview.node.SphereNode");
797
+ compiler.emit("import io.github.sceneview.rememberEngine");
798
+ compiler.emit("import io.github.sceneview.rememberMaterialLoader");
799
+ compiler.emit("");
800
+ compiler.emit(`class ${cls}Activity : ComponentActivity() {`);
801
+ compiler.indentLevel++;
802
+ compiler.emit("override fun onCreate(savedInstanceState: Bundle?) {");
803
+ compiler.indentLevel++;
804
+ compiler.emit("super.onCreate(savedInstanceState)");
805
+ compiler.emit("setContent {");
806
+ compiler.indentLevel++;
807
+ compiler.emit("val engine = rememberEngine()");
808
+ compiler.emit("val materialLoader = rememberMaterialLoader(engine)");
809
+ compiler.emit("val cameraNode = rememberARCameraNode(engine)");
810
+ compiler.emit("");
811
+ compiler.emit("ARScene(");
812
+ compiler.indentLevel++;
813
+ compiler.emit("modifier = Modifier.fillMaxSize(),");
814
+ compiler.emit("engine = engine,");
815
+ compiler.emit("cameraNode = cameraNode,");
816
+ compiler.emit("materialLoader = materialLoader,");
817
+ compiler.emit("planeRenderer = true,");
818
+ compiler.indentLevel--;
819
+ compiler.emit(") {");
820
+ compiler.indentLevel++;
821
+ if (objects.length) {
822
+ objects.forEach((obj, i) => {
823
+ if (i > 0) compiler.emit("");
824
+ emitObjectNode(compiler, obj);
825
+ });
826
+ } else {
827
+ compiler.emit("// No objects in composition \u2014 default placeholder cube at 1m.");
828
+ compiler.emit("CubeNode(");
976
829
  compiler.indentLevel++;
977
- compiler.emit('android.util.Log.d("HoloScript", "Hand $handIndex: FIST detected")');
978
- if (hasToSpatial) {
979
- compiler.emit('onSpatialInput("fist", handIndex, indexTip[0], indexTip[1], indexTip[2])');
980
- }
830
+ compiler.emit("size = Size(0.1f),");
831
+ compiler.emit(
832
+ `materialInstance = materialLoader.createColorInstance(${DEFAULT_COMPOSE_COLOR}),`
833
+ );
834
+ compiler.emit("position = Position(x = 0f, y = 0f, z = -1f),");
981
835
  compiler.indentLevel--;
982
- compiler.emit("}");
983
- compiler.emit("");
836
+ compiler.emit(")");
984
837
  }
985
838
  compiler.indentLevel--;
986
839
  compiler.emit("}");
987
840
  compiler.indentLevel--;
988
841
  compiler.emit("}");
989
- if (hasToSpatial) {
990
- compiler.emit("");
991
- compiler.emit(
992
- "private fun onSpatialInput(gesture: String, handIndex: Int, x: Float, y: Float, z: Float) {"
842
+ compiler.indentLevel--;
843
+ compiler.emit("}");
844
+ compiler.indentLevel--;
845
+ compiler.emit("}");
846
+ return compiler.lines.join("\n") + "\n";
847
+ }
848
+ function generateStateFile(_compiler, _composition) {
849
+ return "";
850
+ }
851
+ function generateNodeFactoryFile(_compiler, _composition) {
852
+ return "";
853
+ }
854
+ function generateManifestFile(compiler, composition) {
855
+ const cls = compiler.options.className;
856
+ const hasGeo = hasGeoTraits(composition);
857
+ const hasGeospatialVPS = hasGeospatialVPSTraits(composition);
858
+ const geoPermissions = hasGeo || hasGeospatialVPS ? `
859
+ <!-- Geo-Anchor: Location permissions -->
860
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
861
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />` : "";
862
+ const geospatialApiKeyMeta = hasGeospatialVPS ? `
863
+ <!-- ARCore Geospatial API key (replace with your key from Google Cloud Console) -->
864
+ <meta-data android:name="com.google.android.ar.API_KEY" android:value="\${GEOSPATIAL_API_KEY}" />` : "";
865
+ return `<?xml version="1.0" encoding="utf-8"?>
866
+ <!-- Auto-generated by HoloScript AndroidCompiler -->
867
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
868
+ xmlns:tools="http://schemas.android.com/tools">
869
+
870
+ <!-- AR Required -->
871
+ <uses-permission android:name="android.permission.CAMERA" />
872
+ <uses-feature android:name="android.hardware.camera.ar" android:required="true" />
873
+
874
+ <!-- ARCore Required -->
875
+ <uses-feature android:glEsVersion="0x00030000" android:required="true" />${geoPermissions}
876
+
877
+ <application
878
+ android:allowBackup="true"
879
+ android:label="${compiler.escapeStringValue(composition.name, "XML")}"
880
+ android:supportsRtl="true"
881
+ android:theme="@android:style/Theme.Material.Light.NoActionBar">
882
+
883
+ <!-- ARCore metadata. SceneView's arsceneview AAR declares com.google.ar.core as
884
+ "optional"; this app requires AR, so override the merged value. -->
885
+ <meta-data android:name="com.google.ar.core" android:value="required"
886
+ tools:replace="android:value" />${geospatialApiKeyMeta}
887
+
888
+ <activity
889
+ android:name=".${cls}Activity"
890
+ android:exported="true"
891
+ android:configChanges="orientation|screenSize"
892
+ android:screenOrientation="locked">
893
+ <intent-filter>
894
+ <action android:name="android.intent.action.MAIN" />
895
+ <category android:name="android.intent.category.LAUNCHER" />
896
+ </intent-filter>
897
+ </activity>
898
+ </application>
899
+ </manifest>`;
900
+ }
901
+ function generateBuildGradle(compiler, composition) {
902
+ const pkg = compiler.options.packageName;
903
+ const minSdk = compiler.options.minSdk;
904
+ const sdk = Math.max(36, compiler.options.targetSdk);
905
+ const optionalDependencies = /* @__PURE__ */ new Set();
906
+ if (hasGeoTraits(composition) || hasGeospatialVPSTraits(composition)) {
907
+ optionalDependencies.add(
908
+ 'implementation("com.google.android.gms:play-services-location:21.3.0")'
993
909
  );
994
- compiler.indentLevel++;
995
- compiler.emit("// Bridge to HoloScript spatial_input event system");
996
- compiler.emit("val event = mapOf(");
997
- compiler.indentLevel++;
998
- compiler.emit('"type" to "hand_gesture",');
999
- compiler.emit('"gesture" to gesture,');
1000
- compiler.emit('"handIndex" to handIndex,');
1001
- compiler.emit('"x" to x, "y" to y, "z" to z');
1002
- compiler.indentLevel--;
1003
- compiler.emit(")");
1004
- compiler.emit('android.util.Log.d("HoloScript", "SpatialInput: $event")');
1005
- compiler.indentLevel--;
1006
- compiler.emit("}");
1007
910
  }
911
+ if (hasHandTrackingTraits(composition)) {
912
+ optionalDependencies.add('implementation("androidx.camera:camera-core:1.4.1")');
913
+ optionalDependencies.add('implementation("androidx.camera:camera-camera2:1.4.1")');
914
+ optionalDependencies.add('implementation("androidx.camera:camera-lifecycle:1.4.1")');
915
+ optionalDependencies.add('implementation("com.google.mediapipe:tasks-vision:0.10.20")');
916
+ }
917
+ const optionalDependencyBlock = optionalDependencies.size > 0 ? `
918
+
919
+ // Optional SceneView feature-trait sidecars
920
+ ${[...optionalDependencies].join("\n ")}` : "";
921
+ return `// Auto-generated by HoloScript AndroidCompiler
922
+ // Source: ${compiler.escapeStringValue(composition.name, "Kotlin")}
923
+ //
924
+ // SceneView (Apache 2.0) Compose-native AR target \u2014 replaces the EOL Sceneform fork.
925
+ // compileSdk/targetSdk floor at 36: SceneView 4.18.0 pulls androidx.core 1.18.0, which refuses
926
+ // to compile below API 36 and requires Android Gradle Plugin 8.9.1+ and Kotlin 2.3.21 (both
927
+ // declared in the hand-maintained root build.gradle.kts scaffold).
928
+
929
+ plugins {
930
+ id("com.android.application")
931
+ id("org.jetbrains.kotlin.android")
932
+ id("org.jetbrains.kotlin.plugin.compose")
933
+ }
934
+
935
+ android {
936
+ namespace = "${pkg}"
937
+ compileSdk = ${sdk}
938
+
939
+ defaultConfig {
940
+ applicationId = "${pkg}"
941
+ minSdk = ${minSdk}
942
+ targetSdk = ${sdk}
943
+ versionCode = 1
944
+ versionName = "1.0"
945
+ }
946
+
947
+ buildTypes {
948
+ release {
949
+ isMinifyEnabled = false
950
+ proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
951
+ }
952
+ }
953
+
954
+ compileOptions {
955
+ sourceCompatibility = JavaVersion.VERSION_17
956
+ targetCompatibility = JavaVersion.VERSION_17
957
+ }
958
+
959
+ buildFeatures {
960
+ compose = true
961
+ }
962
+ }
963
+
964
+ // Kotlin 2.3 removed the kotlinOptions { jvmTarget = "17" } DSL (now a hard error);
965
+ // the JVM target moves to the top-level compilerOptions DSL.
966
+ kotlin {
967
+ compilerOptions {
968
+ jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17)
969
+ }
970
+ }
971
+
972
+ dependencies {
973
+ implementation("androidx.core:core-ktx:1.13.1")
974
+ implementation("androidx.activity:activity-compose:1.9.3")
975
+
976
+ // Jetpack Compose (BOM matches SceneView 4.18.0's compose surface)
977
+ implementation(platform("androidx.compose:compose-bom:2024.09.03"))
978
+ implementation("androidx.compose.ui:ui")
979
+ implementation("androidx.compose.foundation:foundation")
980
+ implementation("androidx.compose.material3:material3")
981
+
982
+ // SceneView (Apache 2.0) \u2014 Compose-native AR; pulls io.github.sceneview:sceneview + ARCore 1.54.0
983
+ // transitively. Replaces the EOL Sceneform fork. No ArFragment / no R.layout (Compose-native).
984
+ implementation("io.github.sceneview:arsceneview:4.18.0")${optionalDependencyBlock}
985
+ }`;
1008
986
  }
987
+ var NAMED_COMPOSE_COLORS, DEFAULT_COMPOSE_COLOR;
988
+ var init_AndroidARGenerators = __esm({
989
+ "src/compiler/AndroidARGenerators.ts"() {
990
+ init_AndroidKotlinHelpers();
991
+ init_AndroidSceneViewFeatureGenerators();
992
+ NAMED_COMPOSE_COLORS = {
993
+ red: "Color(0xFFFF0000)",
994
+ green: "Color(0xFF00FF00)",
995
+ blue: "Color(0xFF2196F3)",
996
+ white: "Color(0xFFFFFFFF)",
997
+ black: "Color(0xFF000000)",
998
+ yellow: "Color(0xFFFFEB3B)",
999
+ cyan: "Color(0xFF00BCD4)",
1000
+ magenta: "Color(0xFFE91E63)",
1001
+ orange: "Color(0xFFFF9800)"
1002
+ };
1003
+ DEFAULT_COMPOSE_COLOR = "Color(0xFF4488FF)";
1004
+ }
1005
+ });
1006
+
1007
+ // src/compiler/AndroidFeatureGenerators.ts
1009
1008
  function hasAuthoringTraits(composition) {
1010
1009
  const authoringNames = SPATIAL_AUTHORING_TRAITS;
1011
1010
  for (const obj of composition.objects || []) {
@@ -1050,51 +1049,6 @@ function emitAuthoringSetup(compiler, composition) {
1050
1049
  }
1051
1050
  return compiler.lines.join("\n");
1052
1051
  }
1053
- function emitAuthoringInlineSetup(compiler, composition) {
1054
- compiler.emit("");
1055
- compiler.emit("// --- Spatial Authoring inline setup (M.010.08) ---");
1056
- if (compiler.compositionHasTrait(composition, "author_gyro_place")) {
1057
- compiler.emit("private fun setupGyroPlacement() {");
1058
- compiler.indentLevel++;
1059
- compiler.emit(
1060
- "sensorManager = getSystemService(SENSOR_SERVICE) as android.hardware.SensorManager"
1061
- );
1062
- compiler.emit(
1063
- "rotationSensor = sensorManager?.getDefaultSensor(android.hardware.Sensor.TYPE_ROTATION_VECTOR)"
1064
- );
1065
- compiler.indentLevel--;
1066
- compiler.emit("}");
1067
- }
1068
- if (compiler.compositionHasTrait(composition, "author_pinch_scale")) {
1069
- compiler.emit("private fun setupPinchScale() {");
1070
- compiler.indentLevel++;
1071
- compiler.emit(
1072
- "scaleGestureDetector = android.view.ScaleGestureDetector(this, object : android.view.ScaleGestureDetector.SimpleOnScaleGestureListener() {"
1073
- );
1074
- compiler.indentLevel++;
1075
- compiler.emit("override fun onScale(detector: android.view.ScaleGestureDetector): Boolean {");
1076
- compiler.indentLevel++;
1077
- compiler.emit("val factor = detector.scaleFactor.coerceIn(pinchScaleMin, pinchScaleMax)");
1078
- compiler.emit("selectedNode?.localScale = selectedNode?.localScale?.let { it.scaled(factor) }");
1079
- compiler.emit("return true");
1080
- compiler.indentLevel--;
1081
- compiler.emit("}");
1082
- compiler.indentLevel--;
1083
- compiler.emit("})");
1084
- compiler.indentLevel--;
1085
- compiler.emit("}");
1086
- }
1087
- if (compiler.compositionHasTrait(composition, "author_shake_undo")) {
1088
- compiler.emit("private fun setupShakeUndo() {");
1089
- compiler.indentLevel++;
1090
- compiler.emit(
1091
- "val accelerometer = sensorManager?.getDefaultSensor(android.hardware.Sensor.TYPE_ACCELEROMETER)"
1092
- );
1093
- compiler.emit("// Shake detection triggers undoStack.removeLastOrNull()?.invoke()");
1094
- compiler.indentLevel--;
1095
- compiler.emit("}");
1096
- }
1097
- }
1098
1052
  function hasNPUSceneTraits(composition) {
1099
1053
  const npuNames = NPU_SCENE_TRAITS;
1100
1054
  for (const obj of composition.objects || []) {
@@ -1329,745 +1283,149 @@ function emitNPUSceneSetup(compiler, composition) {
1329
1283
  compiler.emit("val centerX = (bbox.left + bbox.right) / 2f");
1330
1284
  compiler.emit("val centerY = (bbox.top + bbox.bottom) / 2f");
1331
1285
  compiler.emit("val frame = arFragment.arSceneView.arFrame ?: continue");
1332
- compiler.emit("val hits = frame.hitTest(centerX, centerY)");
1333
- compiler.emit("val hit = hits.firstOrNull() ?: continue");
1334
- compiler.emit("val anchor = hit.createAnchor()");
1335
- compiler.emit("val anchorNode = com.google.ar.sceneform.AnchorNode(anchor)");
1336
- compiler.emit("anchorNode.setParent(scene)");
1337
- compiler.emit("com.google.ar.sceneform.rendering.MaterialFactory");
1338
- compiler.emit(" .makeOpaqueWithColor(arFragment.requireContext(),");
1339
- compiler.emit(" com.google.ar.sceneform.rendering.Color(0.2f, 0.6f, 1.0f, 0.6f))");
1340
- compiler.emit(" .thenAccept { material ->");
1341
- compiler.indentLevel++;
1342
- compiler.emit(
1343
- `val renderable = com.google.ar.sceneform.rendering.ShapeFactory.makeSphere(${defaults.entityScale}f, com.google.ar.sceneform.math.Vector3.zero(), material)`
1344
- );
1345
- compiler.emit(
1346
- "val node = com.google.ar.sceneform.ux.TransformableNode(arFragment.transformationSystem)"
1347
- );
1348
- compiler.emit("node.setParent(anchorNode)");
1349
- compiler.emit("node.renderable = renderable");
1350
- compiler.emit("node.name = detection.label");
1351
- compiler.emit('Log.d("HoloScript", "Entity created: ${detection.label}")');
1352
- compiler.indentLevel--;
1353
- compiler.emit(" }");
1354
- compiler.indentLevel--;
1355
- compiler.emit("}");
1356
- compiler.indentLevel--;
1357
- compiler.emit("}");
1358
- compiler.emit("");
1359
- }
1360
- if (usedTraits.has("npu_realtime")) {
1361
- compiler.emit("// MARK: Realtime Processing (npu_realtime)");
1362
- compiler.emit("");
1363
- compiler.emit("fun createImageAnalyzer(): ImageAnalysis.Analyzer {");
1364
- compiler.indentLevel++;
1365
- compiler.emit("return ImageAnalysis.Analyzer { imageProxy ->");
1366
- compiler.indentLevel++;
1367
- compiler.emit("frameCounter++");
1368
- compiler.emit("val now = System.currentTimeMillis()");
1369
- compiler.emit("val intervalMs = 1000L / targetFPS");
1370
- compiler.emit("if (now - lastProcessTimeMs < intervalMs) {");
1371
- compiler.indentLevel++;
1372
- compiler.emit("imageProxy.close()");
1373
- compiler.emit("return@Analyzer");
1374
- compiler.indentLevel--;
1375
- compiler.emit("}");
1376
- compiler.emit("lastProcessTimeMs = now");
1377
- compiler.emit("_isProcessing.value = true");
1378
- compiler.emit("");
1379
- compiler.emit("@androidx.camera.core.ExperimentalGetImage");
1380
- compiler.emit("val mediaImage = imageProxy.image");
1381
- compiler.emit("if (mediaImage != null) {");
1382
- compiler.indentLevel++;
1383
- compiler.emit(
1384
- "val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)"
1385
- );
1386
- if (usedTraits.has("npu_classify")) {
1387
- compiler.emit("classifyImage(image)");
1388
- }
1389
- if (usedTraits.has("npu_detect")) {
1390
- compiler.emit("detectObjects(image)");
1391
- }
1392
- if (usedTraits.has("npu_segment")) {
1393
- compiler.emit("segmentScene(image)");
1394
- }
1395
- compiler.indentLevel--;
1396
- compiler.emit("}");
1397
- compiler.emit("_isProcessing.value = false");
1398
- compiler.emit("imageProxy.close()");
1399
- compiler.indentLevel--;
1400
- compiler.emit("}");
1401
- compiler.indentLevel--;
1402
- compiler.emit("}");
1403
- compiler.emit("");
1404
- }
1405
- if (usedTraits.has("npu_model_custom")) {
1406
- compiler.emit("// MARK: Custom Model (npu_model_custom)");
1407
- compiler.emit("");
1408
- compiler.emit("private var customInterpreter: Interpreter? = null");
1409
- compiler.emit("");
1410
- compiler.emit("fun loadCustomModel(context: android.content.Context, assetPath: String) {");
1411
- compiler.indentLevel++;
1412
- compiler.emit("val localModel = LocalModel.Builder()");
1413
- compiler.emit(" .setAssetFilePath(assetPath)");
1414
- compiler.emit(" .build()");
1415
- compiler.emit("");
1416
- compiler.emit("// NNAPI delegate for hardware acceleration");
1417
- compiler.emit("val nnApiDelegate = NnApiDelegate()");
1418
- compiler.emit("val options = Interpreter.Options().addDelegate(nnApiDelegate)");
1419
- compiler.emit("");
1420
- compiler.emit("val modelFile = context.assets.open(assetPath)");
1421
- compiler.emit("val buffer = modelFile.readBytes()");
1422
- compiler.emit("val byteBuffer = java.nio.ByteBuffer.allocateDirect(buffer.size)");
1423
- compiler.emit("byteBuffer.put(buffer)");
1424
- compiler.emit("customInterpreter = Interpreter(byteBuffer, options)");
1425
- compiler.emit('Log.d("HoloScript", "Custom model loaded with NNAPI: $assetPath")');
1426
- compiler.indentLevel--;
1427
- compiler.emit("}");
1428
- compiler.emit("");
1429
- }
1430
- if (usedTraits.has("npu_label_overlay")) {
1431
- compiler.emit("// MARK: Label Overlay (npu_label_overlay)");
1432
- compiler.emit("");
1433
- compiler.emit("fun createLabelOverlay(");
1434
- compiler.emit(" detection: NPUDetection,");
1435
- compiler.emit(" arFragment: com.google.ar.sceneform.ux.ArFragment,");
1436
- compiler.emit(" anchorNode: com.google.ar.sceneform.AnchorNode");
1437
- compiler.emit(") {");
1438
- compiler.indentLevel++;
1439
- compiler.emit("com.google.ar.sceneform.rendering.ViewRenderable.builder()");
1440
- compiler.emit(
1441
- " .setView(arFragment.requireContext(), android.widget.TextView(arFragment.requireContext()).apply {"
1442
- );
1443
- compiler.indentLevel++;
1444
- compiler.emit('text = "${detection.label} (${(detection.confidence * 100).toInt()}%)"');
1445
- compiler.emit("setTextColor(android.graphics.Color.WHITE)");
1446
- compiler.emit("setBackgroundColor(android.graphics.Color.argb(180, 0, 0, 0))");
1447
- compiler.emit("setPadding(12, 6, 12, 6)");
1448
- compiler.emit("textSize = 12f");
1449
- compiler.indentLevel--;
1450
- compiler.emit(" })");
1451
- compiler.emit(" .build()");
1452
- compiler.emit(" .thenAccept { renderable ->");
1453
- compiler.indentLevel++;
1454
- compiler.emit("val labelNode = com.google.ar.sceneform.Node()");
1455
- compiler.emit("labelNode.setParent(anchorNode)");
1456
- compiler.emit(
1457
- `labelNode.localPosition = com.google.ar.sceneform.math.Vector3(0f, ${defaults.labelOffsetY}f, 0f)`
1458
- );
1459
- compiler.emit("labelNode.renderable = renderable");
1460
- compiler.emit('Log.d("HoloScript", "Label overlay: ${detection.label}")');
1461
- compiler.indentLevel--;
1462
- compiler.emit(" }");
1463
- compiler.indentLevel--;
1464
- compiler.emit("}");
1465
- compiler.emit("");
1466
- }
1467
- compiler.indentLevel--;
1468
- compiler.emit("}");
1469
- return compiler.lines.join("\n");
1470
- }
1471
- var init_AndroidFeatureGenerators = __esm({
1472
- "src/compiler/AndroidFeatureGenerators.ts"() {
1473
- init_geospatial();
1474
- init_depth_scanner();
1475
- init_portal_ar();
1476
- init_camera_hand_tracking();
1477
- init_npu_scene();
1478
- init_spatial_authoring();
1479
- }
1480
- });
1481
-
1482
- // src/compiler/AndroidARGenerators.ts
1483
- function toKotlinFloatLiteral(value, fallback) {
1484
- const numeric = typeof value === "number" ? value : Number(value);
1485
- const resolved = Number.isFinite(numeric) ? numeric : fallback;
1486
- return `${resolved}f`;
1487
- }
1488
- function toKotlinVector3(value, fallback) {
1489
- const components = Array.isArray(value) && value.length >= 3 ? [value[0], value[1], value[2]] : typeof value === "number" ? [value, value, value] : fallback;
1490
- return `Vector3(${components.map((component, index) => toKotlinFloatLiteral(component, fallback[index])).join(", ")})`;
1491
- }
1492
- function generateActivityFile(compiler, composition) {
1493
- compiler.lines = [];
1494
- compiler.indentLevel = 0;
1495
- const pkg = compiler.options.packageName;
1496
- const cls = compiler.options.className;
1497
- compiler.emit("// Auto-generated by HoloScript AndroidCompiler");
1498
- compiler.emit(
1499
- `// Source: composition "${compiler.escapeStringValue(composition.name, "Kotlin")}"`
1500
- );
1501
- compiler.emit("// Do not edit manually \u2014 regenerate from .holo source");
1502
- compiler.emit("");
1503
- compiler.emit(`package ${pkg}`);
1504
- compiler.emit("");
1505
- compiler.emit("import android.os.Bundle");
1506
- compiler.emit("import android.view.MotionEvent");
1507
- compiler.emit("import android.view.View");
1508
- compiler.emit("import android.widget.Toast");
1509
- compiler.emit("import androidx.appcompat.app.AppCompatActivity");
1510
- compiler.emit("import androidx.lifecycle.ViewModelProvider");
1511
- compiler.emit("import com.google.ar.core.*");
1512
- compiler.emit("import com.google.ar.core.exceptions.*");
1513
- compiler.emit("import com.google.ar.sceneform.*");
1514
- compiler.emit("import com.google.ar.sceneform.math.Vector3");
1515
- compiler.emit("import com.google.ar.sceneform.rendering.*");
1516
- compiler.emit("import com.google.ar.sceneform.ux.*");
1517
- compiler.emit("import java.util.concurrent.CompletableFuture");
1518
- compiler.emit("");
1519
- compiler.emit(`class ${cls}Activity : AppCompatActivity() {`);
1520
- compiler.indentLevel++;
1521
- compiler.emit("private lateinit var arFragment: ArFragment");
1522
- compiler.emit("private lateinit var sceneState: SceneState");
1523
- compiler.emit("private val placedNodes = mutableMapOf<String, TransformableNode>()");
1524
- compiler.emit("");
1525
- compiler.emit("override fun onCreate(savedInstanceState: Bundle?) {");
1526
- compiler.indentLevel++;
1527
- compiler.emit("super.onCreate(savedInstanceState)");
1528
- compiler.emit(`setContentView(R.layout.activity_ar_scene)`);
1529
- compiler.emit("");
1530
- compiler.emit("sceneState = ViewModelProvider(this)[SceneState::class.java]");
1531
- compiler.emit(
1532
- "arFragment = supportFragmentManager.findFragmentById(R.id.ar_fragment) as ArFragment"
1533
- );
1534
- compiler.emit("");
1535
- compiler.emit("setupARSession()");
1536
- compiler.emit("setupTapListener()");
1537
- compiler.emit("setupUI()");
1538
- if (hasGeoTraits(composition)) {
1539
- compiler.emit("setupGeoAnchors()");
1540
- }
1541
- if (hasGeospatialVPSTraits(composition)) {
1542
- compiler.emit("setupGeospatialVPS()");
1543
- }
1544
- if (hasDepthScanTraits(composition)) {
1545
- compiler.emit("setupDepthScanner()");
1546
- }
1547
- if (hasPortalARTraits(composition)) {
1548
- compiler.emit("setupPortalAR()");
1549
- }
1550
- if (hasHandTrackingTraits(composition)) {
1551
- compiler.emit("setupHandTracking()");
1552
- }
1553
- if (hasAuthoringTraits(composition)) {
1554
- compiler.emit("setupSpatialAuthoring()");
1555
- }
1556
- compiler.indentLevel--;
1557
- compiler.emit("}");
1558
- compiler.emit("");
1559
- compiler.emit("private fun setupARSession() {");
1560
- compiler.indentLevel++;
1561
- compiler.emit("arFragment.arSceneView.scene.addOnUpdateListener { frameTime ->");
1562
- compiler.indentLevel++;
1563
- compiler.emit("val frame = arFragment.arSceneView.arFrame ?: return@addOnUpdateListener");
1564
- compiler.emit("");
1565
- compiler.emit("// Track planes");
1566
- compiler.emit("for (plane in frame.getUpdatedTrackables(Plane::class.java)) {");
1567
- compiler.indentLevel++;
1568
- compiler.emit("if (plane.trackingState == TrackingState.TRACKING) {");
1569
- compiler.indentLevel++;
1570
- compiler.emit("sceneState.onPlaneDetected(plane)");
1571
- compiler.indentLevel--;
1572
- compiler.emit("}");
1573
- compiler.indentLevel--;
1574
- compiler.emit("}");
1575
- compiler.indentLevel--;
1576
- compiler.emit("}");
1577
- compiler.indentLevel--;
1578
- compiler.emit("}");
1579
- compiler.emit("");
1580
- compiler.emit("private fun setupTapListener() {");
1581
- compiler.indentLevel++;
1582
- compiler.emit("arFragment.setOnTapArPlaneListener { hitResult, plane, motionEvent ->");
1583
- compiler.indentLevel++;
1584
- compiler.emit(
1585
- "if (plane.type != Plane.Type.HORIZONTAL_UPWARD_FACING) return@setOnTapArPlaneListener"
1586
- );
1587
- compiler.emit("");
1588
- compiler.emit("placeObject(hitResult)");
1589
- compiler.indentLevel--;
1590
- compiler.emit("}");
1591
- compiler.indentLevel--;
1592
- compiler.emit("}");
1593
- compiler.emit("");
1594
- compiler.emit("private fun placeObject(hitResult: HitResult) {");
1595
- compiler.indentLevel++;
1596
- compiler.emit("val anchor = hitResult.createAnchor()");
1597
- compiler.emit("val anchorNode = AnchorNode(anchor)");
1598
- compiler.emit("anchorNode.setParent(arFragment.arSceneView.scene)");
1599
- compiler.emit("");
1600
- if (composition.objects?.length) {
1601
- compiler.emit("// Create one renderable node per HoloScript object");
1602
- for (const obj of composition.objects) {
1603
- const methodName = `create${compiler.sanitizeName(obj.name)}`;
1604
- const objectName = compiler.escapeStringValue(obj.name, "Kotlin");
1605
- const position = toKotlinVector3(compiler.findObjProp(obj, "position"), [0, 0, 0]);
1606
- const scale = toKotlinVector3(compiler.findObjProp(obj, "scale"), [1, 1, 1]);
1607
- compiler.emit(`NodeFactory.${methodName}(this) { renderable ->`);
1608
- compiler.indentLevel++;
1609
- compiler.emit(
1610
- `attachRenderableToAnchor(anchorNode, "${objectName}", renderable, ${position}, ${scale})`
1611
- );
1612
- compiler.indentLevel--;
1613
- compiler.emit("}");
1614
- }
1615
- } else {
1616
- compiler.emit("// Create fallback node for empty scenes");
1617
- compiler.emit("NodeFactory.createDefaultNode(this) { renderable ->");
1618
- compiler.indentLevel++;
1619
- compiler.emit(
1620
- 'attachRenderableToAnchor(anchorNode, "default", renderable, Vector3(0f, 0f, 0f), Vector3(1f, 1f, 1f))'
1621
- );
1622
- compiler.indentLevel--;
1623
- compiler.emit("}");
1624
- }
1625
- compiler.indentLevel--;
1626
- compiler.emit("}");
1627
- compiler.emit("");
1628
- compiler.emit("private fun attachRenderableToAnchor(");
1629
- compiler.indentLevel++;
1630
- compiler.emit("anchorNode: AnchorNode,");
1631
- compiler.emit("objectName: String,");
1632
- compiler.emit("renderable: Renderable,");
1633
- compiler.emit("localPosition: Vector3,");
1634
- compiler.emit("localScale: Vector3");
1635
- compiler.indentLevel--;
1636
- compiler.emit(") {");
1637
- compiler.indentLevel++;
1638
- compiler.emit("val transformableNode = TransformableNode(arFragment.transformationSystem)");
1639
- compiler.emit("transformableNode.setParent(anchorNode)");
1640
- compiler.emit("transformableNode.renderable = renderable");
1641
- compiler.emit("transformableNode.localPosition = localPosition");
1642
- compiler.emit("transformableNode.localScale = localScale");
1643
- compiler.emit("transformableNode.select()");
1644
- compiler.emit("");
1645
- compiler.emit('val id = "$objectName-${java.util.UUID.randomUUID()}"');
1646
- compiler.emit("placedNodes[id] = transformableNode");
1647
- compiler.emit("");
1648
- compiler.emit("// Setup interaction");
1649
- compiler.emit("transformableNode.setOnTapListener { _, _ ->");
1650
- compiler.indentLevel++;
1651
- compiler.emit("sceneState.onNodeTapped(id)");
1652
- compiler.emit("animateNodeTap(transformableNode)");
1653
- compiler.indentLevel--;
1654
- compiler.emit("}");
1655
- compiler.emit("");
1656
- compiler.emit('android.util.Log.d("HoloScript", "Placed object: $objectName as $id")');
1657
- compiler.indentLevel--;
1658
- compiler.emit("}");
1659
- compiler.emit("");
1660
- compiler.emit("private fun animateNodeTap(node: TransformableNode) {");
1661
- compiler.indentLevel++;
1662
- compiler.emit("val originalScale = node.localScale");
1663
- compiler.emit(
1664
- "val scaledUp = Vector3(originalScale[0] * 1.2f, originalScale[1] * 1.2f, originalScale[2] * 1.2f)"
1665
- );
1666
- compiler.emit("");
1667
- compiler.emit("android.animation.ObjectAnimator.ofObject(");
1668
- compiler.indentLevel++;
1669
- compiler.emit('node, "localScale",');
1670
- compiler.emit("com.google.ar.sceneform.math.Vector3Evaluator(),");
1671
- compiler.emit("originalScale, scaledUp, originalScale");
1672
- compiler.indentLevel--;
1673
- compiler.emit(").apply {");
1674
- compiler.indentLevel++;
1675
- compiler.emit("duration = 200");
1676
- compiler.emit("start()");
1677
- compiler.indentLevel--;
1678
- compiler.emit("}");
1679
- compiler.indentLevel--;
1680
- compiler.emit("}");
1681
- compiler.emit("");
1682
- compiler.emit("private fun setupUI() {");
1683
- compiler.indentLevel++;
1684
- compiler.emit("findViewById<View>(R.id.reset_button)?.setOnClickListener {");
1685
- compiler.indentLevel++;
1686
- compiler.emit("resetScene()");
1687
- compiler.indentLevel--;
1688
- compiler.emit("}");
1689
- compiler.indentLevel--;
1690
- compiler.emit("}");
1691
- compiler.emit("");
1692
- compiler.emit("private fun resetScene() {");
1693
- compiler.indentLevel++;
1694
- compiler.emit("for (node in placedNodes.values) {");
1695
- compiler.indentLevel++;
1696
- compiler.emit("node.anchor?.detach()");
1697
- compiler.emit("node.setParent(null)");
1698
- compiler.indentLevel--;
1699
- compiler.emit("}");
1700
- compiler.emit("placedNodes.clear()");
1701
- compiler.emit("");
1702
- compiler.emit("sceneState.reset()");
1703
- compiler.emit('Toast.makeText(this, "Scene reset", Toast.LENGTH_SHORT).show()');
1704
- compiler.indentLevel--;
1705
- compiler.emit("}");
1706
- compiler.emit("");
1707
- compiler.emit("override fun onResume() {");
1708
- compiler.indentLevel++;
1709
- compiler.emit("super.onResume()");
1710
- compiler.emit("checkARCoreAvailability()");
1711
- compiler.indentLevel--;
1712
- compiler.emit("}");
1713
- compiler.emit("");
1714
- compiler.emit("private fun checkARCoreAvailability() {");
1715
- compiler.indentLevel++;
1716
- compiler.emit("val availability = ArCoreApk.getInstance().checkAvailability(this)");
1717
- compiler.emit("if (availability.isTransient) {");
1718
- compiler.indentLevel++;
1719
- compiler.emit("android.os.Handler(mainLooper).postDelayed({ checkARCoreAvailability() }, 200)");
1720
- compiler.emit("return");
1721
- compiler.indentLevel--;
1722
- compiler.emit("}");
1723
- compiler.emit("if (!availability.isSupported) {");
1724
- compiler.indentLevel++;
1725
- compiler.emit(
1726
- 'Toast.makeText(this, "ARCore is not supported on this device", Toast.LENGTH_LONG).show()'
1727
- );
1728
- compiler.emit("finish()");
1729
- compiler.indentLevel--;
1730
- compiler.emit("}");
1731
- compiler.indentLevel--;
1732
- compiler.emit("}");
1733
- if (hasGeoTraits(composition)) {
1734
- emitGeoAnchorSetup(compiler, composition);
1735
- }
1736
- if (hasGeospatialVPSTraits(composition)) {
1737
- emitGeospatialVPSSetup(compiler, composition);
1738
- }
1739
- if (hasDepthScanTraits(composition)) {
1740
- emitDepthScanSetup(compiler, composition);
1741
- }
1742
- if (hasPortalARTraits(composition)) {
1743
- emitPortalARSetup(compiler, composition);
1744
- }
1745
- if (hasHandTrackingTraits(composition)) {
1746
- emitHandTrackingSetup(compiler, composition);
1747
- }
1748
- if (hasAuthoringTraits(composition)) {
1749
- emitAuthoringInlineSetup(compiler, composition);
1750
- }
1751
- compiler.indentLevel--;
1752
- compiler.emit("}");
1753
- return compiler.lines.join("\n");
1754
- }
1755
- function generateStateFile(compiler, composition) {
1756
- compiler.lines = [];
1757
- compiler.indentLevel = 0;
1758
- const pkg = compiler.options.packageName;
1759
- compiler.emit("// Auto-generated by HoloScript AndroidCompiler");
1760
- compiler.emit(`// State: ${compiler.escapeStringValue(composition.name, "Kotlin")}`);
1761
- compiler.emit("");
1762
- compiler.emit(`package ${pkg}`);
1763
- compiler.emit("");
1764
- compiler.emit("import androidx.lifecycle.ViewModel");
1765
- compiler.emit("import androidx.lifecycle.MutableLiveData");
1766
- compiler.emit("import androidx.lifecycle.LiveData");
1767
- compiler.emit("import com.google.ar.core.Plane");
1768
- compiler.emit("");
1769
- compiler.emit("class SceneState : ViewModel() {");
1770
- compiler.indentLevel++;
1771
- if (composition.state) {
1772
- compiler.emit("// === State Properties ===");
1773
- for (const prop of composition.state.properties) {
1774
- const kotlinType = compiler.toKotlinType(prop.value);
1775
- const kotlinValue = compiler.toKotlinValue(prop.value);
1776
- compiler.emit(
1777
- `private val _${compiler.escapeStringValue(prop.key, "Kotlin")} = MutableLiveData(${kotlinValue})`
1778
- );
1779
- compiler.emit(
1780
- `val ${compiler.escapeStringValue(prop.key, "Kotlin")}: LiveData<${kotlinType}> get() = _${compiler.escapeStringValue(prop.key, "Kotlin")}`
1781
- );
1782
- compiler.emit("");
1783
- }
1784
- }
1785
- compiler.emit("// === AR State ===");
1786
- compiler.emit("private val _detectedPlanes = MutableLiveData<List<Plane>>(emptyList())");
1787
- compiler.emit("val detectedPlanes: LiveData<List<Plane>> get() = _detectedPlanes");
1788
- compiler.emit("");
1789
- compiler.emit("private val _tappedNodes = MutableLiveData<String?>()");
1790
- compiler.emit("val tappedNodes: LiveData<String?> get() = _tappedNodes");
1791
- compiler.emit("");
1792
- compiler.emit("fun onPlaneDetected(plane: Plane) {");
1793
- compiler.indentLevel++;
1794
- compiler.emit("val current = _detectedPlanes.value.orEmpty().toMutableList()");
1795
- compiler.emit("if (!current.contains(plane)) {");
1796
- compiler.indentLevel++;
1797
- compiler.emit("current.add(plane)");
1798
- compiler.emit("_detectedPlanes.value = current");
1799
- compiler.emit('android.util.Log.d("HoloScript", "Plane detected: ${plane.type}")');
1800
- compiler.indentLevel--;
1801
- compiler.emit("}");
1802
- compiler.indentLevel--;
1803
- compiler.emit("}");
1804
- compiler.emit("");
1805
- compiler.emit("fun onNodeTapped(nodeId: String) {");
1806
- compiler.indentLevel++;
1807
- compiler.emit("_tappedNodes.value = nodeId");
1808
- compiler.emit('android.util.Log.d("HoloScript", "Node tapped: $nodeId")');
1809
- compiler.indentLevel--;
1810
- compiler.emit("}");
1811
- compiler.emit("");
1812
- compiler.emit("fun reset() {");
1813
- compiler.indentLevel++;
1814
- compiler.emit("_detectedPlanes.value = emptyList()");
1815
- compiler.emit("_tappedNodes.value = null");
1816
- if (composition.state) {
1817
- for (const prop of composition.state.properties) {
1818
- const kotlinValue = compiler.toKotlinValue(prop.value);
1819
- compiler.emit(
1820
- `_${compiler.escapeStringValue(prop.key, "Kotlin")}.value = ${kotlinValue}`
1821
- );
1822
- }
1823
- }
1824
- compiler.emit('android.util.Log.d("HoloScript", "State reset")');
1825
- compiler.indentLevel--;
1826
- compiler.emit("}");
1827
- if (composition.logic?.actions) {
1286
+ compiler.emit("val hits = frame.hitTest(centerX, centerY)");
1287
+ compiler.emit("val hit = hits.firstOrNull() ?: continue");
1288
+ compiler.emit("val anchor = hit.createAnchor()");
1289
+ compiler.emit("val anchorNode = com.google.ar.sceneform.AnchorNode(anchor)");
1290
+ compiler.emit("anchorNode.setParent(scene)");
1291
+ compiler.emit("com.google.ar.sceneform.rendering.MaterialFactory");
1292
+ compiler.emit(" .makeOpaqueWithColor(arFragment.requireContext(),");
1293
+ compiler.emit(" com.google.ar.sceneform.rendering.Color(0.2f, 0.6f, 1.0f, 0.6f))");
1294
+ compiler.emit(" .thenAccept { material ->");
1295
+ compiler.indentLevel++;
1296
+ compiler.emit(
1297
+ `val renderable = com.google.ar.sceneform.rendering.ShapeFactory.makeSphere(${defaults.entityScale}f, com.google.ar.sceneform.math.Vector3.zero(), material)`
1298
+ );
1299
+ compiler.emit(
1300
+ "val node = com.google.ar.sceneform.ux.TransformableNode(arFragment.transformationSystem)"
1301
+ );
1302
+ compiler.emit("node.setParent(anchorNode)");
1303
+ compiler.emit("node.renderable = renderable");
1304
+ compiler.emit("node.name = detection.label");
1305
+ compiler.emit('Log.d("HoloScript", "Entity created: ${detection.label}")');
1306
+ compiler.indentLevel--;
1307
+ compiler.emit(" }");
1308
+ compiler.indentLevel--;
1309
+ compiler.emit("}");
1310
+ compiler.indentLevel--;
1311
+ compiler.emit("}");
1828
1312
  compiler.emit("");
1829
- compiler.emit("// === Actions ===");
1830
- for (const action of composition.logic.actions) {
1831
- compileAction(compiler, action);
1832
- }
1833
1313
  }
1834
- compiler.indentLevel--;
1835
- compiler.emit("}");
1836
- return compiler.lines.join("\n");
1837
- }
1838
- function generateNodeFactoryFile(compiler, composition) {
1839
- compiler.lines = [];
1840
- compiler.indentLevel = 0;
1841
- const pkg = compiler.options.packageName;
1842
- compiler.emit("// Auto-generated by HoloScript AndroidCompiler");
1843
- compiler.emit(
1844
- `// Node Factory: ${compiler.escapeStringValue(composition.name, "Kotlin")}`
1845
- );
1846
- compiler.emit("");
1847
- compiler.emit(`package ${pkg}`);
1848
- compiler.emit("");
1849
- compiler.emit("import android.content.Context");
1850
- compiler.emit("import com.google.ar.sceneform.math.Vector3");
1851
- compiler.emit("import com.google.ar.sceneform.rendering.*");
1852
- compiler.emit("import com.google.android.filament.utils.Float3");
1853
- compiler.emit("");
1854
- compiler.emit("object NodeFactory {");
1855
- compiler.indentLevel++;
1856
- compiler.emit("fun createDefaultNode(context: Context, callback: (Renderable) -> Unit) {");
1857
- compiler.indentLevel++;
1858
- if (composition.objects?.length) {
1859
- const firstObj = composition.objects[0];
1860
- const color = compiler.findObjProp(firstObj, "color");
1861
- compiler.emit("MaterialFactory.makeOpaqueWithColor(");
1314
+ if (usedTraits.has("npu_realtime")) {
1315
+ compiler.emit("// MARK: Realtime Processing (npu_realtime)");
1316
+ compiler.emit("");
1317
+ compiler.emit("fun createImageAnalyzer(): ImageAnalysis.Analyzer {");
1862
1318
  compiler.indentLevel++;
1863
- compiler.emit("context,");
1864
- compiler.emit(`Color(${compiler.toAndroidColor(color)})`);
1865
- compiler.indentLevel--;
1866
- compiler.emit(").thenAccept { material ->");
1319
+ compiler.emit("return ImageAnalysis.Analyzer { imageProxy ->");
1320
+ compiler.indentLevel++;
1321
+ compiler.emit("frameCounter++");
1322
+ compiler.emit("val now = System.currentTimeMillis()");
1323
+ compiler.emit("val intervalMs = 1000L / targetFPS");
1324
+ compiler.emit("if (now - lastProcessTimeMs < intervalMs) {");
1867
1325
  compiler.indentLevel++;
1868
- const meshType = compiler.findObjProp(firstObj, "mesh") || compiler.findObjProp(firstObj, "type") || "cube";
1869
- const geometry = compiler.getSceneformGeometry(meshType);
1870
- compiler.emit(`${geometry}.thenAccept { renderable ->`);
1326
+ compiler.emit("imageProxy.close()");
1327
+ compiler.emit("return@Analyzer");
1328
+ compiler.indentLevel--;
1329
+ compiler.emit("}");
1330
+ compiler.emit("lastProcessTimeMs = now");
1331
+ compiler.emit("_isProcessing.value = true");
1332
+ compiler.emit("");
1333
+ compiler.emit("@androidx.camera.core.ExperimentalGetImage");
1334
+ compiler.emit("val mediaImage = imageProxy.image");
1335
+ compiler.emit("if (mediaImage != null) {");
1871
1336
  compiler.indentLevel++;
1872
- compiler.emit("renderable.material = material");
1873
- compiler.emit("callback(renderable)");
1337
+ compiler.emit(
1338
+ "val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)"
1339
+ );
1340
+ if (usedTraits.has("npu_classify")) {
1341
+ compiler.emit("classifyImage(image)");
1342
+ }
1343
+ if (usedTraits.has("npu_detect")) {
1344
+ compiler.emit("detectObjects(image)");
1345
+ }
1346
+ if (usedTraits.has("npu_segment")) {
1347
+ compiler.emit("segmentScene(image)");
1348
+ }
1874
1349
  compiler.indentLevel--;
1875
1350
  compiler.emit("}");
1351
+ compiler.emit("_isProcessing.value = false");
1352
+ compiler.emit("imageProxy.close()");
1876
1353
  compiler.indentLevel--;
1877
1354
  compiler.emit("}");
1878
- } else {
1355
+ compiler.indentLevel--;
1356
+ compiler.emit("}");
1357
+ compiler.emit("");
1358
+ }
1359
+ if (usedTraits.has("npu_model_custom")) {
1360
+ compiler.emit("// MARK: Custom Model (npu_model_custom)");
1361
+ compiler.emit("");
1362
+ compiler.emit("private var customInterpreter: Interpreter? = null");
1363
+ compiler.emit("");
1364
+ compiler.emit("fun loadCustomModel(context: android.content.Context, assetPath: String) {");
1365
+ compiler.indentLevel++;
1366
+ compiler.emit("val localModel = LocalModel.Builder()");
1367
+ compiler.emit(" .setAssetFilePath(assetPath)");
1368
+ compiler.emit(" .build()");
1369
+ compiler.emit("");
1370
+ compiler.emit("// NNAPI delegate for hardware acceleration");
1371
+ compiler.emit("val nnApiDelegate = NnApiDelegate()");
1372
+ compiler.emit("val options = Interpreter.Options().addDelegate(nnApiDelegate)");
1373
+ compiler.emit("");
1374
+ compiler.emit("val modelFile = context.assets.open(assetPath)");
1375
+ compiler.emit("val buffer = modelFile.readBytes()");
1376
+ compiler.emit("val byteBuffer = java.nio.ByteBuffer.allocateDirect(buffer.size)");
1377
+ compiler.emit("byteBuffer.put(buffer)");
1378
+ compiler.emit("customInterpreter = Interpreter(byteBuffer, options)");
1379
+ compiler.emit('Log.d("HoloScript", "Custom model loaded with NNAPI: $assetPath")');
1380
+ compiler.indentLevel--;
1381
+ compiler.emit("}");
1382
+ compiler.emit("");
1383
+ }
1384
+ if (usedTraits.has("npu_label_overlay")) {
1385
+ compiler.emit("// MARK: Label Overlay (npu_label_overlay)");
1386
+ compiler.emit("");
1387
+ compiler.emit("fun createLabelOverlay(");
1388
+ compiler.emit(" detection: NPUDetection,");
1389
+ compiler.emit(" arFragment: com.google.ar.sceneform.ux.ArFragment,");
1390
+ compiler.emit(" anchorNode: com.google.ar.sceneform.AnchorNode");
1391
+ compiler.emit(") {");
1392
+ compiler.indentLevel++;
1393
+ compiler.emit("com.google.ar.sceneform.rendering.ViewRenderable.builder()");
1879
1394
  compiler.emit(
1880
- "MaterialFactory.makeOpaqueWithColor(context, Color(android.graphics.Color.BLUE))"
1395
+ " .setView(arFragment.requireContext(), android.widget.TextView(arFragment.requireContext()).apply {"
1881
1396
  );
1882
- compiler.emit(" .thenCompose { material ->");
1397
+ compiler.indentLevel++;
1398
+ compiler.emit('text = "${detection.label} (${(detection.confidence * 100).toInt()}%)"');
1399
+ compiler.emit("setTextColor(android.graphics.Color.WHITE)");
1400
+ compiler.emit("setBackgroundColor(android.graphics.Color.argb(180, 0, 0, 0))");
1401
+ compiler.emit("setPadding(12, 6, 12, 6)");
1402
+ compiler.emit("textSize = 12f");
1403
+ compiler.indentLevel--;
1404
+ compiler.emit(" })");
1405
+ compiler.emit(" .build()");
1406
+ compiler.emit(" .thenAccept { renderable ->");
1407
+ compiler.indentLevel++;
1408
+ compiler.emit("val labelNode = com.google.ar.sceneform.Node()");
1409
+ compiler.emit("labelNode.setParent(anchorNode)");
1883
1410
  compiler.emit(
1884
- " ShapeFactory.makeCube(Vector3(0.1f, 0.1f, 0.1f), Vector3.zero(), material)"
1411
+ `labelNode.localPosition = com.google.ar.sceneform.math.Vector3(0f, ${defaults.labelOffsetY}f, 0f)`
1885
1412
  );
1413
+ compiler.emit("labelNode.renderable = renderable");
1414
+ compiler.emit('Log.d("HoloScript", "Label overlay: ${detection.label}")');
1415
+ compiler.indentLevel--;
1886
1416
  compiler.emit(" }");
1887
- compiler.emit(" .thenAccept { renderable -> callback(renderable) }");
1888
- }
1889
- compiler.indentLevel--;
1890
- compiler.emit("}");
1891
- compiler.emit("");
1892
- for (const obj of composition.objects || []) {
1893
- compileObjectFactory(compiler, obj);
1417
+ compiler.indentLevel--;
1418
+ compiler.emit("}");
1419
+ compiler.emit("");
1894
1420
  }
1895
1421
  compiler.indentLevel--;
1896
1422
  compiler.emit("}");
1897
1423
  return compiler.lines.join("\n");
1898
1424
  }
1899
- function compileObjectFactory(compiler, obj) {
1900
- const methodName = `create${compiler.sanitizeName(obj.name)}`;
1901
- compiler.emit(`fun ${methodName}(context: Context, callback: (Renderable) -> Unit) {`);
1902
- compiler.indentLevel++;
1903
- const color = compiler.findObjProp(obj, "color");
1904
- const meshType = compiler.findObjProp(obj, "mesh") || compiler.findObjProp(obj, "type") || "cube";
1905
- compiler.emit("MaterialFactory.makeOpaqueWithColor(");
1906
- compiler.indentLevel++;
1907
- compiler.emit("context,");
1908
- compiler.emit(`Color(${compiler.toAndroidColor(color)})`);
1909
- compiler.indentLevel--;
1910
- compiler.emit(").thenAccept { material ->");
1911
- compiler.indentLevel++;
1912
- const geometry = compiler.getSceneformGeometry(meshType);
1913
- compiler.emit(`${geometry}.thenAccept { renderable ->`);
1914
- compiler.indentLevel++;
1915
- compiler.emit("renderable.material = material");
1916
- compiler.emit("callback(renderable)");
1917
- compiler.indentLevel--;
1918
- compiler.emit("}");
1919
- compiler.indentLevel--;
1920
- compiler.emit("}");
1921
- compiler.indentLevel--;
1922
- compiler.emit("}");
1923
- compiler.emit("");
1924
- }
1925
- function generateManifestFile(compiler, composition) {
1926
- const pkg = compiler.options.packageName;
1927
- const cls = compiler.options.className;
1928
- const hasGeo = hasGeoTraits(composition);
1929
- const hasGeospatialVPS = hasGeospatialVPSTraits(composition);
1930
- const geoPermissions = hasGeo || hasGeospatialVPS ? `
1931
- <!-- Geo-Anchor: Location permissions -->
1932
- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
1933
- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />` : "";
1934
- const geospatialApiKeyMeta = hasGeospatialVPS ? `
1935
- <!-- ARCore Geospatial API key (replace with your key from Google Cloud Console) -->
1936
- <meta-data android:name="com.google.android.ar.API_KEY" android:value="\${GEOSPATIAL_API_KEY}" />` : "";
1937
- return `<?xml version="1.0" encoding="utf-8"?>
1938
- <!-- Auto-generated by HoloScript AndroidCompiler -->
1939
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
1940
- package="${pkg}">
1941
-
1942
- <!-- AR Required -->
1943
- <uses-permission android:name="android.permission.CAMERA" />
1944
- <uses-feature android:name="android.hardware.camera.ar" android:required="true" />
1945
-
1946
- <!-- ARCore Required -->
1947
- <uses-feature android:glEsVersion="0x00030000" android:required="true" />${geoPermissions}
1948
-
1949
- <application
1950
- android:allowBackup="true"
1951
- android:label="${compiler.escapeStringValue(composition.name, "XML")}"
1952
- android:supportsRtl="true"
1953
- android:theme="@style/Theme.AppCompat.NoActionBar">
1954
-
1955
- <!-- ARCore metadata -->
1956
- <meta-data android:name="com.google.ar.core" android:value="required" />${geospatialApiKeyMeta}
1957
-
1958
- <activity
1959
- android:name=".${cls}Activity"
1960
- android:exported="true"
1961
- android:configChanges="orientation|screenSize"
1962
- android:screenOrientation="locked">
1963
- <intent-filter>
1964
- <action android:name="android.intent.action.MAIN" />
1965
- <category android:name="android.intent.category.LAUNCHER" />
1966
- </intent-filter>
1967
- </activity>
1968
- </application>
1969
- </manifest>`;
1970
- }
1971
- function generateBuildGradle(compiler, composition) {
1972
- const hasGeospatialVPS = hasGeospatialVPSTraits(composition);
1973
- const hasDepthScan = hasDepthScanTraits(composition);
1974
- const hasHandTracking = hasHandTrackingTraits(composition);
1975
- const geospatialDeps = hasGeospatialVPS ? `
1976
- // ARCore Geospatial API (included in com.google.ar:core >= 1.31.0)
1977
- // Location services for VPS
1978
- implementation 'com.google.android.gms:play-services-location:21.1.0'` : "";
1979
- const depthScanDeps = hasDepthScan ? `
1980
- // ARCore Depth API (M.010.02b)
1981
- implementation 'com.google.ar:core:1.40.0'` : "";
1982
- const handTrackingDeps = hasHandTracking ? `
1983
- // MediaPipe Hands \u2014 camera-based hand tracking (M.010.04)
1984
- implementation 'com.google.mediapipe:solution-hands:0.10.14'
1985
- // CameraX for front camera feed
1986
- implementation 'androidx.camera:camera-core:1.3.1'
1987
- implementation 'androidx.camera:camera-camera2:1.3.1'
1988
- implementation 'androidx.camera:camera-lifecycle:1.3.1'` : "";
1989
- const hasAuthoring = hasAuthoringTraits(composition);
1990
- const authoringDeps = hasAuthoring ? `
1991
- // Spatial Authoring \u2014 speech recognition (M.010.08)
1992
- implementation 'androidx.recyclerview:recyclerview:1.3.2'` : "";
1993
- return `// Auto-generated by HoloScript AndroidCompiler
1994
- // Source: ${compiler.escapeStringValue(composition.name, "Kotlin")}
1995
-
1996
- plugins {
1997
- id 'com.android.application'
1998
- id 'org.jetbrains.kotlin.android'
1999
- }
2000
-
2001
- android {
2002
- namespace '${compiler.options.packageName}'
2003
- compileSdk ${compiler.options.targetSdk}
2004
-
2005
- defaultConfig {
2006
- applicationId "${compiler.options.packageName}"
2007
- minSdk ${compiler.options.minSdk}
2008
- targetSdk ${compiler.options.targetSdk}
2009
- versionCode 1
2010
- versionName "1.0"
2011
- }
2012
-
2013
- buildTypes {
2014
- release {
2015
- minifyEnabled false
2016
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
2017
- }
2018
- }
2019
-
2020
- compileOptions {
2021
- sourceCompatibility JavaVersion.VERSION_17
2022
- targetCompatibility JavaVersion.VERSION_17
2023
- }
2024
-
2025
- kotlinOptions {
2026
- jvmTarget = '17'
2027
- }
2028
-
2029
- buildFeatures {
2030
- viewBinding true
2031
- compose ${compiler.options.useJetpackCompose}
2032
- }
2033
- }
2034
-
2035
- dependencies {
2036
- implementation 'androidx.core:core-ktx:1.12.0'
2037
- implementation 'androidx.appcompat:appcompat:1.6.1'
2038
- implementation 'com.google.android.material:material:1.11.0'
2039
- implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0'
2040
- implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.7.0'
2041
-
2042
- // ARCore (>= 1.31.0 includes Geospatial API)
2043
- implementation 'com.google.ar:core:1.41.0'
2044
-
2045
- // Sceneform (maintained fork)
2046
- implementation 'com.gorisse.thomas:sceneform:1.22.0'${geospatialDeps}${depthScanDeps}${handTrackingDeps}${authoringDeps}
2047
-
2048
- // Optional: Jetpack Compose
2049
- ${compiler.options.useJetpackCompose ? `implementation platform('androidx.compose:compose-bom:2024.01.00')
2050
- implementation 'androidx.compose.ui:ui'
2051
- implementation 'androidx.compose.material3:material3'
2052
- implementation 'androidx.activity:activity-compose:1.8.2'` : "// Compose disabled"}
2053
- }`;
2054
- }
2055
- function compileAction(compiler, action) {
2056
- const rawName = compiler.sanitizeName(action.name);
2057
- const name = rawName.charAt(0).toLowerCase() + rawName.slice(1);
2058
- compiler.emit(`fun ${name}() {`);
2059
- compiler.indentLevel++;
2060
- compiler.emit(
2061
- `android.util.Log.d("HoloScript", "Action: ${compiler.escapeStringValue(action.name, "Kotlin")}")`
2062
- );
2063
- compiler.emit("// Action implementation");
2064
- compiler.indentLevel--;
2065
- compiler.emit("}");
2066
- compiler.emit("");
2067
- }
2068
- var init_AndroidARGenerators = __esm({
2069
- "src/compiler/AndroidARGenerators.ts"() {
2070
- init_AndroidFeatureGenerators();
1425
+ var init_AndroidFeatureGenerators = __esm({
1426
+ "src/compiler/AndroidFeatureGenerators.ts"() {
1427
+ init_npu_scene();
1428
+ init_spatial_authoring();
2071
1429
  }
2072
1430
  });
2073
1431
 
@@ -2948,6 +2306,7 @@ var init_AndroidCompiler = __esm({
2948
2306
  init_CompilerBase();
2949
2307
  init_AndroidARGenerators();
2950
2308
  init_AndroidFeatureGenerators();
2309
+ init_AndroidSceneViewFeatureGenerators();
2951
2310
  init_AndroidPeripheralGenerators();
2952
2311
  init_AndroidKotlinHelpers();
2953
2312
  AndroidCompiler = class extends CompilerBase {
@@ -2974,11 +2333,26 @@ var init_AndroidCompiler = __esm({
2974
2333
  this.validateCompilerAccess(agentToken, outputPath);
2975
2334
  const result = {
2976
2335
  activityFile: generateActivityFile(this, composition),
2977
- stateFile: generateStateFile(this, composition),
2978
- nodeFactoryFile: generateNodeFactoryFile(this, composition),
2336
+ stateFile: generateStateFile(),
2337
+ nodeFactoryFile: generateNodeFactoryFile(),
2979
2338
  manifestFile: generateManifestFile(this, composition),
2980
2339
  buildGradle: generateBuildGradle(this, composition)
2981
2340
  };
2341
+ if (hasGeoAnchorTraits(composition)) {
2342
+ result.geoAnchorSetup = emitGeoAnchorSetup(this, composition);
2343
+ }
2344
+ if (hasGeospatialVPSTraits(composition)) {
2345
+ result.geospatialVPSSetup = emitGeospatialVPSSetup(this, composition);
2346
+ }
2347
+ if (hasDepthScanTraits(composition)) {
2348
+ result.depthScanSetup = emitDepthScanSetup(this, composition);
2349
+ }
2350
+ if (hasPortalARTraits(composition)) {
2351
+ result.portalARSetup = emitPortalARSetup(this, composition);
2352
+ }
2353
+ if (hasHandTrackingTraits(composition)) {
2354
+ result.handTrackingSetup = emitHandTrackingSetup(this, composition);
2355
+ }
2982
2356
  if (hasNPUSceneTraits(composition)) {
2983
2357
  result.npuSceneSetup = emitNPUSceneSetup(this, composition);
2984
2358
  }
@@ -3005,6 +2379,51 @@ var init_AndroidCompiler = __esm({
3005
2379
  }
3006
2380
  return result;
3007
2381
  }
2382
+ /**
2383
+ * Compile to a path-keyed map of reference-relative files (Android project layout).
2384
+ *
2385
+ * Mirrors AndroidXRCompiler.compileToFiles(): the native return is named fields
2386
+ * (AndroidCompileResult), so this adapter maps those fields onto the on-disk Android
2387
+ * project layout, letting the SAME byte-diff golden gate + committed-reference-app pattern
2388
+ * (QuestCompiler / AndroidXRCompiler) apply to the legacy plain-Android (ARCore) target.
2389
+ * Keys are POSIX-relative to the app project root (the dir holding settings.gradle.kts).
2390
+ *
2391
+ * Optional feature-setup fields (npuSceneSetup, hapticSetup, …) are emitted as extra
2392
+ * Kotlin files under the same package dir, keyed off the field name, so the gate covers
2393
+ * them when a trait pulls them in. The field→filename map is fixed so output is stable.
2394
+ */
2395
+ compileToFiles(composition, agentToken = "") {
2396
+ const r = this.compile(composition, agentToken);
2397
+ const pkgPath = this.options.packageName.replace(/\./g, "/");
2398
+ const javaRel = `app/src/main/java/${pkgPath}`;
2399
+ const files = {
2400
+ [`${javaRel}/${this.options.className}Activity.kt`]: r.activityFile,
2401
+ "app/src/main/AndroidManifest.xml": r.manifestFile,
2402
+ "app/build.gradle.kts": r.buildGradle
2403
+ };
2404
+ const featureFiles = {
2405
+ geoAnchorSetup: "GeoAnchorSetup.kt",
2406
+ geospatialVPSSetup: "GeospatialVPSSetup.kt",
2407
+ depthScanSetup: "DepthScanSetup.kt",
2408
+ portalARSetup: "PortalARSetup.kt",
2409
+ handTrackingSetup: "HandTrackingSetup.kt",
2410
+ npuSceneSetup: "NPUSceneSetup.kt",
2411
+ authoringSetup: "AuthoringSetup.kt",
2412
+ hapticSetup: "HapticSetup.kt",
2413
+ nearbySetup: "NearbySetup.kt",
2414
+ foldableSetup: "FoldableSetup.kt",
2415
+ dexSetup: "DexSetup.kt",
2416
+ lensSetup: "LensSetup.kt",
2417
+ webxrSetup: "WebXRSetup.kt"
2418
+ };
2419
+ for (const [field, fileName] of Object.entries(featureFiles)) {
2420
+ const content = r[field];
2421
+ if (typeof content === "string" && content.length > 0) {
2422
+ files[`${javaRel}/${fileName}`] = content;
2423
+ }
2424
+ }
2425
+ return files;
2426
+ }
3008
2427
  emit(line) {
3009
2428
  const indent = this.options.indent.repeat(this.indentLevel);
3010
2429
  this.lines.push(indent + line);
@@ -3034,13 +2453,13 @@ var init_AndroidCompiler = __esm({
3034
2453
  return toAndroidColor(value);
3035
2454
  }
3036
2455
  /** @deprecated Use compositionHasTrait from AndroidKotlinHelpers */
3037
- compositionHasTrait(composition, traitName) {
3038
- return compositionHasTrait(composition, traitName);
2456
+ compositionHasTrait(composition, traitName2) {
2457
+ return compositionHasTrait(composition, traitName2);
3039
2458
  }
3040
2459
  };
3041
2460
  }
3042
2461
  });
3043
2462
 
3044
2463
  export { AndroidCompiler, AndroidCompiler_exports, compileToAndroid, init_AndroidCompiler };
3045
- //# sourceMappingURL=chunk-GSOUNWEL.js.map
3046
- //# sourceMappingURL=chunk-GSOUNWEL.js.map
2464
+ //# sourceMappingURL=chunk-HVX7QQYK.js.map
2465
+ //# sourceMappingURL=chunk-HVX7QQYK.js.map