@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.
- package/bin/holoscript.cjs +5 -1
- package/dist/GLTFPipeline-L76YTXKA.js +15 -0
- package/dist/GLTFPipeline-ZWJN7GI6.cjs +36 -0
- package/dist/HoloCompositionParser-K76KTEEE.js +12 -0
- package/dist/HoloCompositionParser-UZH6Y4HO.cjs +45 -0
- package/dist/HoloScriptCodeParser-2D4ERFUZ.js +6 -0
- package/dist/HoloScriptCodeParser-UDRLDA7I.cjs +23 -0
- package/dist/HoloScriptPlusParser-FTMCGWXD.js +13 -0
- package/dist/HoloScriptPlusParser-LQR5GIKF.cjs +30 -0
- package/dist/HoloScriptRuntime-UTRLJI5L.js +12 -0
- package/dist/HoloScriptRuntime-YBYXJHJN.cjs +21 -0
- package/dist/SceneIRCompiler-63KA3M2F.js +17 -0
- package/dist/SceneIRCompiler-KWUFHZ4O.cjs +42 -0
- package/dist/{USDZExporter-AUHZODOF.cjs → USDZExporter-ML4UMIGC.cjs} +3 -3
- package/dist/{USDZExporter-GXB4AUSG.js → USDZExporter-ZFKLQ76G.js} +3 -3
- package/dist/agents/index.cjs +1 -1
- package/dist/agents/index.js +1 -1
- package/dist/audit/AuditLogger.d.ts +106 -0
- package/dist/audit/AuditQueryBuilder.d.ts +79 -0
- package/dist/audit/ComplianceReporter.d.ts +90 -0
- package/dist/audit/index.d.ts +13 -0
- package/dist/{chunk-FGMDMJM7.js → chunk-2BYAUHBO.js} +3 -3
- package/dist/{chunk-EDPYCLRC.cjs → chunk-2E6PP5UE.cjs} +83 -59
- package/dist/{chunk-GASCWJK5.js → chunk-2EGGAZT3.js} +65 -287
- package/dist/{chunk-SIEXCILW.js → chunk-2I3XAGMF.js} +3 -3
- package/dist/{chunk-OS533P33.cjs → chunk-2KKOYZYI.cjs} +1074 -1655
- package/dist/chunk-2MQKNDNH.js +51 -0
- package/dist/{chunk-7DMMMBCY.cjs → chunk-2X3IPCBK.cjs} +10 -10
- package/dist/chunk-2ZOTBO25.cjs +202 -0
- package/dist/chunk-356N4NPM.cjs +152 -0
- package/dist/{chunk-X3GJPRVK.cjs → chunk-36NPLOI4.cjs} +92 -81
- package/dist/{chunk-SLU6UPJI.cjs → chunk-37HHY7RH.cjs} +5 -5
- package/dist/{chunk-YDPEHCCI.cjs → chunk-3CDDRUER.cjs} +3 -118
- package/dist/chunk-3F7ZZWIN.js +1651 -0
- package/dist/chunk-3ILD7TKP.cjs +187 -0
- package/dist/{chunk-X27QRG4C.cjs → chunk-3IUHTGDD.cjs} +153 -41
- package/dist/{chunk-PXNZ6TME.js → chunk-4376VHNJ.js} +60 -36
- package/dist/{chunk-YKGPCZEE.cjs → chunk-4FIBOJW6.cjs} +10 -10
- package/dist/chunk-4Q7RKQQI.cjs +14195 -0
- package/dist/{chunk-YCM6QQRT.cjs → chunk-566ZB4LZ.cjs} +180 -8
- package/dist/{chunk-2Y3V22SG.js → chunk-5CURIYGT.js} +3 -3
- package/dist/{chunk-QBWNJXNR.js → chunk-5FYMCVBY.js} +5 -5
- package/dist/{chunk-ZA34AN3R.js → chunk-5LVFTGKH.js} +841 -12
- package/dist/chunk-63AUAIL6.js +48 -0
- package/dist/chunk-655FATJU.js +110 -0
- package/dist/{chunk-TQ377OLB.cjs → chunk-65S62L4D.cjs} +28 -22
- package/dist/chunk-6NTAZN5Z.cjs +502 -0
- package/dist/chunk-6TRX6AR2.js +9376 -0
- package/dist/chunk-6ZCCLKS2.cjs +51 -0
- package/dist/{chunk-MDR235RZ.js → chunk-734OB5SK.js} +721 -8
- package/dist/{chunk-Q2Q34NF3.js → chunk-77QI552M.js} +6 -6
- package/dist/{chunk-WKX5AMOY.js → chunk-7I74JWPW.js} +3 -3
- package/dist/{chunk-5FSKKMR7.cjs → chunk-7IDJDMPU.cjs} +232 -4
- package/dist/chunk-7VBKRGIZ.cjs +847 -0
- package/dist/{chunk-KCPHASCO.js → chunk-AATYYLYK.js} +5 -5
- package/dist/{chunk-WFKVS2K4.cjs → chunk-AUZRKIHQ.cjs} +1101 -55
- package/dist/{chunk-DTGBOSEM.cjs → chunk-AWXFEAQL.cjs} +12 -12
- package/dist/{chunk-THCK6ECW.js → chunk-B3CWTCK2.js} +231 -3
- package/dist/chunk-BCP4E7MD.cjs +997 -0
- package/dist/chunk-BG7RPYJP.js +91 -0
- package/dist/{chunk-VF257YKO.js → chunk-BP4KTMLY.js} +117 -5
- package/dist/{chunk-YN6IETRZ.js → chunk-BQJ3YBF3.js} +6424 -987
- package/dist/{chunk-KOUAQL2B.cjs → chunk-CANAL6CT.cjs} +1569 -168
- package/dist/{chunk-FDSGHPAK.js → chunk-CBSDJF3B.js} +3 -3
- package/dist/{chunk-FEWUHQNM.cjs → chunk-CFVK26P4.cjs} +4 -4
- package/dist/{chunk-M7K4LE66.cjs → chunk-CI33NINL.cjs} +4 -4
- package/dist/{chunk-2OWDB4FB.js → chunk-CKV5NYAE.js} +6 -6
- package/dist/{chunk-LPS5AMQD.cjs → chunk-CM4NHXVO.cjs} +24 -24
- package/dist/chunk-D3HSRXYB.js +115 -0
- package/dist/{chunk-FNHJRI32.js → chunk-DBH3D2MU.js} +1561 -160
- package/dist/{chunk-GW3LKD5C.js → chunk-DJNH4HFW.js} +3 -3
- package/dist/{chunk-2GCNOI2U.cjs → chunk-DN6F4DHH.cjs} +9 -3
- package/dist/chunk-DQRJ5RJG.js +432 -0
- package/dist/{chunk-C7ZBSV2Q.js → chunk-DUG3OQAS.js} +106 -43
- package/dist/chunk-ECUYJOJ2.cjs +199 -0
- package/dist/chunk-EEMTCAK7.js +182 -0
- package/dist/{chunk-3SKLAUDD.cjs → chunk-EI3J6LTW.cjs} +359 -581
- package/dist/{chunk-SSSN7VAM.js → chunk-EM2OGPYE.js} +4 -4
- package/dist/{chunk-56VOWURB.cjs → chunk-ENZCIQZC.cjs} +522 -453
- package/dist/chunk-ESBXUYOC.cjs +836 -0
- package/dist/{chunk-L5U4W6JC.js → chunk-ESSEF6U2.js} +4 -4
- package/dist/chunk-ET3AN4W3.js +824 -0
- package/dist/chunk-EXKSFGSX.cjs +14 -14
- package/dist/{chunk-I76GIKN7.cjs → chunk-F3YT6GUF.cjs} +17 -17
- package/dist/{chunk-WRWEX5ZF.js → chunk-F75DZBBI.js} +3 -3
- package/dist/{chunk-4JGRWHZJ.js → chunk-FG6PYGIZ.js} +12 -6
- package/dist/chunk-FGGJQRLZ.js +14 -14
- package/dist/{chunk-SXOSDZD6.js → chunk-FWCHPCD4.js} +128 -10
- package/dist/{chunk-XW6IXEQH.cjs → chunk-G35CAQ7I.cjs} +5 -5
- package/dist/{chunk-7VMGP2FW.js → chunk-G6KACNMO.js} +132 -188
- package/dist/{chunk-FJPADH77.cjs → chunk-GAWJJAGT.cjs} +6 -6
- package/dist/chunk-GGR7QUKK.cjs +4724 -0
- package/dist/chunk-GIBF4BHH.js +14098 -0
- package/dist/{chunk-AWB7QYY6.cjs → chunk-GILYQ5VH.cjs} +6 -6
- package/dist/{chunk-FWVYAMNW.cjs → chunk-GKFCHGCM.cjs} +4 -4
- package/dist/{chunk-Y3ZFVUUU.js → chunk-GLEJ2TLS.js} +3 -3
- package/dist/{chunk-3GWWJT7L.js → chunk-GP3OKSKT.js} +13 -13
- package/dist/chunk-GTIPOEHN.js +196 -0
- package/dist/{chunk-LMJ5EBV7.cjs → chunk-GZPUA2TL.cjs} +16 -15
- package/dist/{chunk-IELX2OKI.js → chunk-H4LJ4HEA.js} +3 -115
- package/dist/{chunk-ACVWFGBI.cjs → chunk-HCX4SMFK.cjs} +3 -3
- package/dist/{chunk-HYNTS5CP.js → chunk-HHRZ6STP.js} +24 -2
- package/dist/chunk-HIDEIEFG.js +48 -0
- package/dist/{chunk-W6RW64BB.cjs → chunk-HSWBIDZM.cjs} +228 -5
- package/dist/{chunk-GSOUNWEL.js → chunk-HVX7QQYK.js} +1035 -1616
- package/dist/{chunk-TRCGG42I.cjs → chunk-IFW5IW4L.cjs} +6502 -1019
- package/dist/{chunk-F5LKJ6F5.cjs → chunk-IJU6AS67.cjs} +32 -28
- package/dist/{chunk-TVANHNJ7.js → chunk-IK6Z2HNC.js} +173 -3
- package/dist/{chunk-QGMUTVVH.cjs → chunk-IS7NTKY5.cjs} +20 -20
- package/dist/{chunk-YFVQWSNJ.js → chunk-IXWGYWH6.js} +3 -3
- package/dist/chunk-J2DAS2PL.js +148 -0
- package/dist/chunk-JBQXZIWB.js +148 -0
- package/dist/chunk-JBYBMBMW.js +261 -0
- package/dist/{chunk-LWUOUCYL.js → chunk-JEJ7TT54.js} +5 -5
- package/dist/{chunk-DUCB6LGL.js → chunk-JOTCTHN5.js} +211 -5
- package/dist/{chunk-47RUFYKR.js → chunk-K56UVEXV.js} +3 -3
- package/dist/{chunk-XSFNHP2E.js → chunk-KB26H447.js} +3 -3
- package/dist/{chunk-3NGDZZR4.js → chunk-KEYG7HGY.js} +430 -37
- package/dist/{chunk-DY72BMU5.js → chunk-KFVNCW4Q.js} +4 -4
- package/dist/chunk-KPGC7SK2.js +192 -0
- package/dist/chunk-KROXXBK5.cjs +53 -0
- package/dist/{chunk-ZPZAVHXL.cjs → chunk-LB3ZZMKT.cjs} +137 -19
- package/dist/chunk-LDYZWNJW.cjs +1654 -0
- package/dist/{chunk-ULMSSHCJ.cjs → chunk-LMB555QB.cjs} +405 -38
- package/dist/{chunk-CBJY23VL.js → chunk-MD4IVS42.js} +3 -3
- package/dist/{chunk-VMLKSV26.js → chunk-MDDWEBCX.js} +226 -3
- package/dist/chunk-MUWH4QK5.cjs +94 -0
- package/dist/{chunk-T6W3Z3SH.cjs → chunk-N2ILK7BF.cjs} +4 -4
- package/dist/{chunk-6EX3I5P4.cjs → chunk-N74QRJGP.cjs} +6 -6
- package/dist/chunk-NFFHLX37.cjs +132 -0
- package/dist/chunk-NJSYWX7H.js +190 -0
- package/dist/{chunk-SH5PPVK7.cjs → chunk-NQN5LFN4.cjs} +165 -221
- package/dist/chunk-NTQRFOPP.cjs +56 -0
- package/dist/{chunk-YFWRJW4B.js → chunk-NWMJPTVL.js} +51 -55
- package/dist/{chunk-63ZGNR2T.cjs → chunk-OC6GV5QH.cjs} +42 -42
- package/dist/{chunk-7E7GCQCK.js → chunk-OG3MBHM3.js} +9 -3
- package/dist/chunk-OMNHTCS4.cjs +264 -0
- package/dist/chunk-OQXB6NNC.cjs +117 -0
- package/dist/{chunk-Y57W2CT5.cjs → chunk-OV46CCA2.cjs} +51 -55
- package/dist/{chunk-6PRZIHGL.cjs → chunk-OV6HHKLE.cjs} +21 -266
- package/dist/{chunk-C37BHB7N.cjs → chunk-P26YYPOO.cjs} +5 -5
- package/dist/{chunk-2BZHWUSR.cjs → chunk-P7JEKJTZ.cjs} +16 -16
- package/dist/{chunk-NGBXXZLL.cjs → chunk-PDXX5UI4.cjs} +45 -45
- package/dist/{chunk-FHQFPYV4.js → chunk-PJFTTSKE.js} +8 -7
- package/dist/{chunk-GVFJ6T4S.cjs → chunk-PVODJEJ7.cjs} +721 -8
- package/dist/{chunk-ZZ7RO2UQ.js → chunk-Q265VZJ4.js} +3 -3
- package/dist/{chunk-E7JP3BS3.cjs → chunk-Q47JEE2C.cjs} +4 -4
- package/dist/chunk-QBY7LRN2.js +281 -0
- package/dist/{chunk-Z6PMDS4G.js → chunk-QDQWKSU3.js} +1090 -53
- package/dist/{chunk-GH6C2QGW.cjs → chunk-QEDMOGF3.cjs} +857 -16
- package/dist/{chunk-5WUNN6ZN.cjs → chunk-QHSAVOOL.cjs} +24 -2
- package/dist/chunk-QJNCDVYM.cjs +137 -0
- package/dist/chunk-QM7FJB5W.js +4717 -0
- package/dist/chunk-QQFB4RT2.cjs +448 -0
- package/dist/chunk-QSYBHQAD.cjs +196 -0
- package/dist/{chunk-UGXHYIWT.cjs → chunk-QUJ3ZB55.cjs} +28 -28
- package/dist/{chunk-2YSNA2F2.cjs → chunk-QVJMDVYZ.cjs} +5 -5
- package/dist/chunk-RAJMAX6D.js +131 -0
- package/dist/{chunk-VVKVQZI6.js → chunk-RAN3ECAS.js} +3 -3
- package/dist/chunk-RKGUZBOC.js +79 -0
- package/dist/{chunk-HLFDZ35S.cjs → chunk-RRQIAJLQ.cjs} +8 -8
- package/dist/{chunk-PABONWKI.js → chunk-RXQNRZ5F.js} +3 -3
- package/dist/{chunk-7ZHYEITD.cjs → chunk-S4O7CFHQ.cjs} +10 -11
- package/dist/chunk-SE7ANBGN.js +128 -0
- package/dist/{chunk-X2AVEAZM.cjs → chunk-SJIRCTIS.cjs} +176 -2
- package/dist/{chunk-WXQ57LAO.js → chunk-SQXAZHDG.js} +4 -4
- package/dist/chunk-SR73L5ZP.cjs +84 -0
- package/dist/{chunk-OABEO6HH.js → chunk-SZOLTWWD.js} +2349 -214
- package/dist/{chunk-5JEU52DW.js → chunk-TPZ3BN2D.js} +3 -3
- package/dist/{chunk-QFU53KRH.js → chunk-TSTFYGGX.js} +4 -5
- package/dist/{chunk-EBS32AJI.cjs → chunk-TZCFKZ6Z.cjs} +5 -5
- package/dist/chunk-UCVZXQ63.js +724 -0
- package/dist/chunk-UGQ3QNV6.js +992 -0
- package/dist/chunk-UNMVGZVW.js +142 -0
- package/dist/{chunk-TEVX443G.js → chunk-UTUD6GJI.js} +178 -6
- package/dist/chunk-UXBYA7DV.cjs +155 -0
- package/dist/chunk-V6GXFSK7.cjs +443 -0
- package/dist/chunk-VHORVGCG.cjs +761 -0
- package/dist/{chunk-B4EKV6HQ.js → chunk-VKCTYLDN.js} +500 -442
- package/dist/{chunk-O3MGZDCT.cjs → chunk-VTEXJOSD.cjs} +63 -63
- package/dist/chunk-VVAAZITA.cjs +287 -0
- package/dist/{chunk-V7AKE5VT.cjs → chunk-W2GA3EQB.cjs} +435 -42
- package/dist/chunk-W4GABFCR.js +37 -0
- package/dist/chunk-WKEK4NCA.js +490 -0
- package/dist/{chunk-5A4TCHOC.cjs → chunk-WNYXT4TE.cjs} +4 -4
- package/dist/{chunk-S762UEV5.js → chunk-WTH23ISI.js} +6 -6
- package/dist/{chunk-BTKZGHAV.js → chunk-WWNCM473.js} +10 -6
- package/dist/{chunk-7X5PNIQJ.js → chunk-X3YFRH6K.js} +27 -25
- package/dist/{chunk-4YNYPHH3.cjs → chunk-X75H75UY.cjs} +2351 -213
- package/dist/{chunk-LYJJI7ZK.cjs → chunk-XCUDDFKC.cjs} +216 -9
- package/dist/chunk-YAO4HPJL.cjs +120 -0
- package/dist/chunk-YKY2JBER.cjs +9443 -0
- package/dist/chunk-YP5CHEYU.cjs +154 -0
- package/dist/{chunk-WRNEH5MO.js → chunk-YW3I2FQL.js} +18 -7
- package/dist/{chunk-BRNUPDHJ.js → chunk-Z557DVYN.js} +386 -19
- package/dist/{chunk-VSACG2AR.js → chunk-Z6LZUYZF.js} +21 -264
- package/dist/chunk-ZHPMP447.cjs +43 -0
- package/dist/{chunk-LODTHGST.cjs → chunk-ZK7KX5CD.cjs} +133 -70
- package/dist/{chunk-CCPSNT6B.cjs → chunk-ZRPALBQB.cjs} +5 -5
- package/dist/chunk-ZVFHPMC5.js +824 -0
- package/dist/chunk-ZVQMKUGJ.js +443 -0
- package/dist/cli/holoscript-runner.cjs +86 -48
- package/dist/cli/holoscript-runner.js +54 -16
- package/dist/codebase/index.cjs +1 -1
- package/dist/codebase/index.js +1 -1
- package/dist/compiler/agent-inference.cjs +11 -11
- package/dist/compiler/agent-inference.js +9 -6
- package/dist/compiler/android-xr.cjs +13 -12
- package/dist/compiler/android-xr.js +11 -10
- package/dist/compiler/android.cjs +12 -12
- package/dist/compiler/android.js +10 -10
- package/dist/compiler/business-quest.cjs +10 -10
- package/dist/compiler/business-quest.js +2 -2
- package/dist/compiler/coco.cjs +1 -1
- package/dist/compiler/coco.js +1 -1
- package/dist/compiler/context.cjs +9 -9
- package/dist/compiler/context.js +6 -6
- package/dist/compiler/daimon-seed.cjs +36 -0
- package/dist/compiler/daimon-seed.js +12 -0
- package/dist/compiler/domain-block-utils.cjs +205 -156
- package/dist/compiler/domain-block-utils.js +8 -7
- package/dist/compiler/dtdl.cjs +10 -10
- package/dist/compiler/dtdl.js +7 -7
- package/dist/compiler/gltf-pipeline.cjs +9 -9
- package/dist/compiler/gltf-pipeline.js +2 -2
- package/dist/compiler/godot.cjs +10 -9
- package/dist/compiler/godot.js +9 -8
- package/dist/compiler/incremental.cjs +11 -11
- package/dist/compiler/incremental.js +6 -6
- package/dist/compiler/index.cjs +2585 -3273
- package/dist/compiler/index.d.ts +149 -35
- package/dist/compiler/index.js +2197 -3102
- package/dist/compiler/ios.cjs +11 -11
- package/dist/compiler/ios.js +9 -9
- package/dist/compiler/llm-provider-capabilities.cjs +9 -9
- package/dist/compiler/llm-provider-capabilities.js +6 -6
- package/dist/compiler/nodetoy.cjs +1 -1
- package/dist/compiler/nodetoy.js +1 -1
- package/dist/compiler/openxr.cjs +11 -10
- package/dist/compiler/openxr.js +10 -9
- package/dist/compiler/remotion.cjs +1 -1
- package/dist/compiler/remotion.js +1 -1
- package/dist/compiler/reproducibility.cjs +1 -1
- package/dist/compiler/reproducibility.js +1 -1
- package/dist/compiler/sdf.cjs +11 -10
- package/dist/compiler/sdf.js +9 -8
- package/dist/compiler/semantic-scene.cjs +7 -7
- package/dist/compiler/semantic-scene.js +2 -2
- package/dist/compiler/state.cjs +9 -9
- package/dist/compiler/state.js +7 -7
- package/dist/compiler/trait-composition.cjs +11 -11
- package/dist/compiler/trait-composition.js +7 -7
- package/dist/compiler/traits/ProvenanceSemiring.d.ts +167 -0
- package/dist/compiler/traits/Semiring.d.ts +26 -0
- package/dist/compiler/unity.cjs +11 -10
- package/dist/compiler/unity.js +10 -9
- package/dist/compiler/unreal.cjs +12 -11
- package/dist/compiler/unreal.js +10 -9
- package/dist/compiler/urdf.cjs +18 -17
- package/dist/compiler/urdf.js +9 -8
- package/dist/compiler/usd-physics.cjs +11 -10
- package/dist/compiler/usd-physics.js +8 -7
- package/dist/compiler/visionos.cjs +11 -10
- package/dist/compiler/visionos.js +10 -9
- package/dist/compiler/vrchat.cjs +11 -10
- package/dist/compiler/vrchat.js +9 -8
- package/dist/compiler/wasm.cjs +14 -13
- package/dist/compiler/wasm.js +9 -8
- package/dist/compiler/webgpu.cjs +10 -9
- package/dist/compiler/webgpu.js +9 -8
- package/dist/constants.cjs +398 -0
- package/dist/constants.js +9 -0
- package/dist/coordinators/index.cjs +4 -1
- package/dist/coordinators/index.js +4 -1
- package/dist/debugger.cjs +11 -9
- package/dist/debugger.js +9 -7
- package/dist/{dist-ACXG6IH5.cjs → dist-GRMOP2UL.cjs} +341 -65
- package/dist/{dist-VD4L6V7Q.js → dist-ZBUKU2JG.js} +333 -63
- package/dist/entries/interop.cjs +23 -23
- package/dist/entries/interop.js +3 -3
- package/dist/entries/scripting.cjs +12 -11
- package/dist/entries/scripting.js +8 -7
- package/dist/evolution/index.cjs +66 -0
- package/dist/evolution/index.d.ts +162 -0
- package/dist/evolution/index.js +17 -0
- package/dist/hololand/index.cjs +41 -37
- package/dist/hololand/index.js +3 -3
- package/dist/index.cjs +12394 -3224
- package/dist/index.d.ts +260 -18
- package/dist/index.js +10755 -2182
- package/dist/keyword-registry/PluginKeywordRegistry.d.ts +138 -0
- package/dist/keyword-registry/index.cjs +29 -0
- package/dist/keyword-registry/index.d.ts +1 -0
- package/dist/keyword-registry/index.js +4 -0
- package/dist/math/tropical-spmv.cjs +11 -11
- package/dist/math/tropical-spmv.d.ts +1 -0
- package/dist/math/tropical-spmv.js +2 -2
- package/dist/math/tropicalSpmv.d.ts +43 -0
- package/dist/math/vec3.cjs +1 -1
- package/dist/math/vec3.js +1 -1
- package/dist/matter/StagedMatter.d.ts +82 -0
- package/dist/matter/index.cjs +17 -0
- package/dist/matter/index.d.ts +1 -0
- package/dist/matter/index.js +4 -0
- package/dist/{ml-dsa-Z7JDKW4L.js → ml-dsa-J6VKVT4K.js} +3 -3
- package/dist/{ml-dsa-FSKBTE3W.cjs → ml-dsa-MTIK4ZUQ.cjs} +23 -23
- package/dist/paper-0c-spike/index.cjs +1 -1
- package/dist/paper-0c-spike/index.js +1 -1
- package/dist/parameter-envelope/ParameterEnvelope.d.ts +128 -0
- package/dist/parameter-envelope/index.cjs +17 -0
- package/dist/parameter-envelope/index.d.ts +2 -0
- package/dist/parameter-envelope/index.js +4 -0
- package/dist/parser/HoloCompositionTypes.d.ts +2013 -0
- package/dist/parser/PipelineParser.d.ts +162 -0
- package/dist/parser.cjs +36 -20
- package/dist/parser.js +13 -9
- package/dist/plugin-manifest/ManifestAutoLoader.d.ts +35 -0
- package/dist/plugin-manifest/PluginManifest.d.ts +156 -0
- package/dist/plugin-manifest/index.cjs +25 -0
- package/dist/plugin-manifest/index.d.ts +2 -0
- package/dist/plugin-manifest/index.js +4 -0
- package/dist/plugin-solver-contract/PluginSolverContract.d.ts +288 -0
- package/dist/plugin-solver-contract/index.cjs +41 -0
- package/dist/plugin-solver-contract/index.d.ts +1 -0
- package/dist/plugin-solver-contract/index.js +4 -0
- package/dist/policy/ContentPolicyGate.d.ts +51 -0
- package/dist/policy/PolicyPack.d.ts +120 -0
- package/dist/policy/blocklist.d.ts +32 -0
- package/dist/policy/defaults.d.ts +44 -0
- package/dist/policy/index.cjs +106 -0
- package/dist/policy/index.d.ts +17 -0
- package/dist/policy/index.js +5 -0
- package/dist/policy/jsonLogic.d.ts +31 -0
- package/dist/policy/types.d.ts +174 -0
- package/dist/proof-composition/ProofCompositionLaw.d.ts +93 -0
- package/dist/proof-composition/index.cjs +25 -0
- package/dist/proof-composition/index.d.ts +1 -0
- package/dist/proof-composition/index.js +4 -0
- package/dist/receipts/hash-policy.d.ts +85 -0
- package/dist/reconstruction/index.cjs +75 -47
- package/dist/reconstruction/index.js +5 -5
- package/dist/runtime/plugin-trait-registrar.d.ts +36 -0
- package/dist/runtime.cjs +81 -79
- package/dist/runtime.js +9 -7
- package/dist/scene-presets-EDKYZ5GW.js +4 -0
- package/dist/scene-presets-NCW2CFRS.cjs +17 -0
- package/dist/self-improvement/index.cjs +1 -1
- package/dist/self-improvement/index.js +1 -1
- package/dist/{src-PT2FERDV.cjs → src-G3D7ZATQ.cjs} +545 -21
- package/dist/{src-J6CM4AUR.js → src-UXYA7HM6.js} +539 -16
- package/dist/storage/index.cjs +10 -10
- package/dist/storage/index.js +3 -3
- package/dist/testing.cjs +1 -1
- package/dist/testing.js +1 -1
- package/dist/tools/index.cjs +3631 -0
- package/dist/tools/index.js +3581 -0
- package/dist/traitDocs/traitDocs.cjs +9 -9
- package/dist/traitDocs/traitDocs.d.ts +1 -0
- package/dist/traitDocs/traitDocs.js +3 -3
- package/dist/traits/ControlLoopTrait.d.ts +154 -0
- package/dist/traits/KinematicChainTrait.d.ts +116 -0
- package/dist/traits/SensorSamplingTrait.d.ts +154 -0
- package/dist/traits/TraitTypes.d.ts +270 -0
- package/dist/traits/TransactionTrait.d.ts +121 -0
- package/dist/traits/botanical-lotus.cjs +54 -50
- package/dist/traits/botanical-lotus.js +2 -5
- package/dist/traits/control-loop.cjs +21 -0
- package/dist/traits/control-loop.d.ts +1 -0
- package/dist/traits/control-loop.js +4 -0
- package/dist/traits/engines/cloth-verlet.d.ts +65 -0
- package/dist/traits/engines/index.cjs +19 -19
- package/dist/traits/engines/index.d.ts +15 -275
- package/dist/traits/engines/index.js +3 -3
- package/dist/traits/engines/motion-data-schema.d.ts +119 -0
- package/dist/traits/engines/motion-matching.d.ts +102 -0
- package/dist/traits/engines/noise.d.ts +25 -0
- package/dist/traits/engines/onnx-adapter.d.ts +173 -0
- package/dist/traits/engines/onnx-motion-matching.d.ts +163 -0
- package/dist/traits/engines/pfnn-network.d.ts +92 -0
- package/dist/traits/engines/synthetic-walk-cycle.d.ts +38 -0
- package/dist/traits/engines/tensor-ops.d.ts +15 -0
- package/dist/traits/index.cjs +2789 -1259
- package/dist/traits/index.d.ts +35 -0
- package/dist/traits/index.js +1692 -411
- package/dist/traits/kinematic-chain.cjs +25 -0
- package/dist/traits/kinematic-chain.d.ts +1 -0
- package/dist/traits/kinematic-chain.js +4 -0
- package/dist/traits/sensor-sampling.cjs +33 -0
- package/dist/traits/sensor-sampling.d.ts +1 -0
- package/dist/traits/sensor-sampling.js +4 -0
- package/dist/traits/simulation-solver-factory.cjs +1 -1
- package/dist/traits/simulation-solver-factory.js +1 -1
- package/dist/traits/transaction.cjs +29 -0
- package/dist/traits/transaction.d.ts +1 -0
- package/dist/traits/transaction.js +4 -0
- package/dist/traits/webcam-gaze.cjs +1 -1
- package/dist/traits/webcam-gaze.js +1 -1
- package/dist/type-checker.cjs +7 -6
- package/dist/type-checker.js +5 -4
- package/dist/types/AdvancedTypeSystem.d.ts +489 -0
- package/dist/types/HoloScriptPlus.d.ts +810 -0
- package/dist/types/base.d.ts +248 -0
- package/dist/types.d.ts +799 -0
- package/dist/world/index.cjs +3 -4
- package/dist/world/index.js +3 -4
- package/dist/world-model/index.cjs +1 -1
- package/dist/world-model/index.js +1 -1
- package/dist/wot/index.cjs +1 -1
- package/dist/wot/index.js +1 -1
- package/package.json +113 -46
- package/dist/GLTFPipeline-3EJLL3TS.cjs +0 -38
- package/dist/GLTFPipeline-3OWJV2VK.js +0 -17
- package/dist/HoloScriptPlusParser-ADWRY5OS.cjs +0 -698
- package/dist/HoloScriptPlusParser-JLJDXHSC.js +0 -693
- package/dist/HoloScriptPlusParser-QCGFPWIL.cjs +0 -27
- package/dist/HoloScriptPlusParser-WENAFEFV.js +0 -10
- package/dist/HoloScriptRuntime-GGRVEU4T.cjs +0 -19
- package/dist/HoloScriptRuntime-GJK6VJPH.js +0 -10
- package/dist/chunk-22Q5A6RV.js +0 -979
- package/dist/chunk-4C57PR42.js +0 -468
- package/dist/chunk-4W5G5QVL.cjs +0 -847
- package/dist/chunk-5ET6L4NS.js +0 -487
- package/dist/chunk-C4GSLCHE.cjs +0 -7153
- package/dist/chunk-F2G6CWFT.js +0 -7089
- package/dist/chunk-G6PNEASF.cjs +0 -814
- package/dist/chunk-GTA4Q3A3.js +0 -1491
- package/dist/chunk-HCCQLAA4.cjs +0 -74
- package/dist/chunk-HFSVMKM3.cjs +0 -72
- package/dist/chunk-KAIVDEIG.cjs +0 -4539
- package/dist/chunk-KQU64CIX.cjs +0 -1508
- package/dist/chunk-MSYSQ2AJ.js +0 -4533
- package/dist/chunk-NHJLP37F.js +0 -70
- package/dist/chunk-NHYRRAGI.cjs +0 -490
- package/dist/chunk-OIQYIIO3.cjs +0 -473
- package/dist/chunk-OL46QLBJ.js +0 -61
- package/dist/chunk-SKZPC5AG.cjs +0 -984
- package/dist/chunk-SLHLXUMO.js +0 -445
- package/dist/chunk-UOIGFQXC.cjs +0 -9750
- package/dist/chunk-UOL6Y5TD.cjs +0 -759
- package/dist/chunk-UVFI7XIR.cjs +0 -452
- package/dist/chunk-VEPGBETF.js +0 -844
- package/dist/chunk-XQ5MWMP2.js +0 -756
- package/dist/chunk-XT6JY5W5.js +0 -9684
- package/dist/chunk-YRRAUB35.js +0 -811
- package/dist/compiler/GasOptimizationAnalyzer.d.ts +0 -73
- package/dist/compiler/NFTMarketplaceCompiler.d.ts +0 -23
- package/dist/compiler/ar.cjs +0 -23
- package/dist/compiler/ar.js +0 -11
- package/dist/compiler/babylon.cjs +0 -21
- package/dist/compiler/babylon.js +0 -15
- package/dist/compiler/multi-layer.cjs +0 -24
- package/dist/compiler/multi-layer.js +0 -15
- package/dist/compiler/playcanvas.cjs +0 -19
- package/dist/compiler/playcanvas.js +0 -13
- package/dist/compiler/r3f.cjs +0 -39
- package/dist/compiler/r3f.d.ts +0 -22
- package/dist/compiler/r3f.js +0 -17
- package/dist/compiler/vrr.cjs +0 -24
- package/dist/compiler/vrr.js +0 -12
- package/dist/parser/NFTMarketplaceTypes.d.ts +0 -191
- package/dist/playwright-3AT3AKTV.cjs +0 -98673
- package/dist/playwright-VZPDVUEQ.js +0 -98660
|
@@ -1,1011 +1,1010 @@
|
|
|
1
|
-
import { init_AndroidKotlinHelpers, sanitizeNameCapitalized, getSceneformGeometry, findObjProp, toKotlinType, toKotlinValue, toAndroidColor, compositionHasTrait } from './chunk-
|
|
2
|
-
import { init_CompilerBase, CompilerBase } from './chunk-
|
|
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
|
|
4
|
-
import { init_portal_ar, init_camera_hand_tracking, init_npu_scene, NPU_SCENE_TRAITS, NPU_SCENE_DEFAULTS,
|
|
5
|
-
import { __esm, __export } from './chunk-
|
|
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/
|
|
9
|
-
function
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
|
38
|
+
return [...used].sort();
|
|
38
39
|
}
|
|
39
|
-
function
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
"
|
|
43
|
-
|
|
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
|
|
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
|
-
|
|
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("
|
|
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
|
-
"
|
|
147
|
+
"createGeoAnchor(anchor.name, earthRef, anchor.latitude, anchor.longitude, anchor.altitude, anchor.heading)"
|
|
68
148
|
);
|
|
69
|
-
compiler.
|
|
70
|
-
|
|
71
|
-
if (
|
|
72
|
-
compiler.emit("
|
|
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
|
-
"
|
|
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("
|
|
125
|
-
compiler.emit("val
|
|
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(
|
|
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("
|
|
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(
|
|
139
|
-
|
|
140
|
-
|
|
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
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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(
|
|
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("
|
|
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
|
-
|
|
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("
|
|
210
|
-
compiler.emit("arFragment.arSceneView.scene.addOnUpdateListener {");
|
|
246
|
+
compiler.emit("fun updateEarthTracking(session: Session) {");
|
|
211
247
|
compiler.indentLevel++;
|
|
212
|
-
compiler.emit("
|
|
213
|
-
compiler.emit("
|
|
214
|
-
compiler.emit("
|
|
215
|
-
compiler.emit("
|
|
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
|
-
|
|
265
|
+
"fun createGeospatialAnchor(name: String, lat: Double, lng: Double, alt: Double, heading: Float): Anchor? {"
|
|
223
266
|
);
|
|
224
267
|
compiler.indentLevel++;
|
|
225
|
-
compiler.emit("
|
|
226
|
-
compiler.emit("return
|
|
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
|
-
|
|
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
|
-
"
|
|
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("
|
|
249
|
-
compiler.emit("");
|
|
302
|
+
compiler.emit("val halfRadians = Math.toRadians(heading.toDouble()) / 2.0");
|
|
250
303
|
compiler.emit(
|
|
251
|
-
"
|
|
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
|
-
|
|
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
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
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
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
compiler.emit(
|
|
399
|
-
compiler.
|
|
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(
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
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("
|
|
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.
|
|
368
|
+
compiler.indentLevel--;
|
|
369
|
+
compiler.emit("}");
|
|
425
370
|
compiler.emit("");
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
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 (
|
|
432
|
-
compiler.emit("
|
|
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
|
|
389
|
+
compiler.emit("private fun acquireConfidenceImage(frame: Frame): Image? = try {");
|
|
444
390
|
compiler.indentLevel++;
|
|
445
|
-
compiler.emit("
|
|
391
|
+
compiler.emit("frame.acquireRawDepthConfidenceImage()");
|
|
392
|
+
compiler.indentLevel--;
|
|
393
|
+
compiler.emit("} catch (_: Throwable) {");
|
|
446
394
|
compiler.indentLevel++;
|
|
447
|
-
|
|
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("}
|
|
397
|
+
compiler.emit("}");
|
|
398
|
+
compiler.emit("");
|
|
399
|
+
compiler.emit("fun detectDepthSource(): DepthSource {");
|
|
468
400
|
compiler.indentLevel++;
|
|
469
|
-
compiler.emit(
|
|
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
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
)
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
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(
|
|
646
|
-
compiler.
|
|
647
|
-
compiler
|
|
648
|
-
compiler.emit("private
|
|
649
|
-
compiler.emit("private var
|
|
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("
|
|
460
|
+
compiler.emit("fun setupPortalAR(session: Session) {");
|
|
652
461
|
compiler.indentLevel++;
|
|
653
|
-
compiler.emit("
|
|
462
|
+
compiler.emit("configurePortalSession(session)");
|
|
463
|
+
compiler.emit("setPortalVisibility(true)");
|
|
464
|
+
compiler.indentLevel--;
|
|
465
|
+
compiler.emit("}");
|
|
654
466
|
compiler.emit("");
|
|
655
|
-
compiler.emit("
|
|
656
|
-
compiler.
|
|
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.
|
|
477
|
+
compiler.indentLevel--;
|
|
478
|
+
compiler.emit("}");
|
|
670
479
|
compiler.emit("");
|
|
671
|
-
compiler.emit("
|
|
672
|
-
compiler.
|
|
673
|
-
compiler.emit(
|
|
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
|
-
|
|
676
|
-
|
|
677
|
-
|
|
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
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
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
|
-
|
|
549
|
+
`class ${compiler.options.className}HandTrackingManager(private val context: Context) {`
|
|
814
550
|
);
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
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("
|
|
824
|
-
compiler.emit("handsolution?.setResultListener { result ->");
|
|
564
|
+
compiler.emit("fun setupHandTracking() {");
|
|
825
565
|
compiler.indentLevel++;
|
|
826
|
-
compiler.emit("
|
|
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("
|
|
831
|
-
compiler.
|
|
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("
|
|
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
|
-
"
|
|
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("
|
|
843
|
-
compiler.emit("val
|
|
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
|
-
|
|
614
|
+
'if (pinchDist < 0.04f) emitSpatialInput(SpatialInputEvent("pinch", handIndex, timestampMs))'
|
|
847
615
|
);
|
|
848
|
-
compiler.
|
|
616
|
+
compiler.indentLevel--;
|
|
617
|
+
compiler.emit("}");
|
|
618
|
+
compiler.emit("");
|
|
849
619
|
compiler.emit(
|
|
850
|
-
"
|
|
620
|
+
"fun classifyPointGesture(handIndex: Int, skeleton: List<HandJoint>, timestampMs: Long) {"
|
|
851
621
|
);
|
|
852
622
|
compiler.indentLevel++;
|
|
853
|
-
compiler.emit("
|
|
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("
|
|
857
|
-
compiler.emit("
|
|
858
|
-
compiler.
|
|
859
|
-
compiler.
|
|
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
|
-
"
|
|
866
|
-
);
|
|
867
|
-
compiler.
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
compiler.
|
|
871
|
-
compiler.
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
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
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
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(
|
|
950
|
-
|
|
951
|
-
|
|
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
|
-
|
|
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(
|
|
964
|
-
|
|
965
|
-
|
|
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
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
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(
|
|
978
|
-
|
|
979
|
-
|
|
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
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
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
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
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("
|
|
1864
|
-
compiler.
|
|
1865
|
-
compiler.
|
|
1866
|
-
compiler.emit("
|
|
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
|
-
|
|
1869
|
-
|
|
1870
|
-
compiler.
|
|
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(
|
|
1873
|
-
|
|
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
|
-
|
|
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
|
-
"
|
|
1395
|
+
" .setView(arFragment.requireContext(), android.widget.TextView(arFragment.requireContext()).apply {"
|
|
1881
1396
|
);
|
|
1882
|
-
compiler.
|
|
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
|
-
|
|
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.
|
|
1888
|
-
|
|
1889
|
-
|
|
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
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
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(
|
|
2978
|
-
nodeFactoryFile: generateNodeFactoryFile(
|
|
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,
|
|
3038
|
-
return compositionHasTrait(composition,
|
|
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-
|
|
3046
|
-
//# sourceMappingURL=chunk-
|
|
2464
|
+
//# sourceMappingURL=chunk-HVX7QQYK.js.map
|
|
2465
|
+
//# sourceMappingURL=chunk-HVX7QQYK.js.map
|