@cimplify/sdk 0.108.0 → 0.110.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/advanced.d.mts +4 -3
- package/dist/advanced.d.ts +4 -3
- package/dist/advanced.js +24 -24
- package/dist/advanced.mjs +5 -5
- package/dist/animation-4EXBXRVX.js +27 -0
- package/dist/animation-6DICNWUP.mjs +6 -0
- package/dist/audio-DhvyjqdA.d.mts +249 -0
- package/dist/audio-m0w8cnxq.d.ts +249 -0
- package/dist/avatars.d.mts +110 -0
- package/dist/avatars.d.ts +110 -0
- package/dist/avatars.js +82 -0
- package/dist/avatars.mjs +5 -0
- package/dist/backend-gUCzs5Kg.d.mts +3866 -0
- package/dist/backend-gUCzs5Kg.d.ts +3866 -0
- package/dist/{catalogue-B4eLL8Mi.d.ts → catalogue-CPTMyBUz.d.mts} +109 -221
- package/dist/catalogue-DzrTXP3v.d.mts +541 -0
- package/dist/catalogue-DzrTXP3v.d.ts +541 -0
- package/dist/{catalogue-OT89_Ifs.d.mts → catalogue-OTuS5zp-.d.ts} +109 -221
- package/dist/chunk-22BD3RHN.mjs +1809 -0
- package/dist/chunk-25T4JHEA.mjs +21 -0
- package/dist/chunk-2AQ237Y4.js +508 -0
- package/dist/chunk-2IC4H6OV.mjs +48 -0
- package/dist/chunk-2LHLG4OB.mjs +71 -0
- package/dist/chunk-2O2CG465.js +1709 -0
- package/dist/chunk-2Q4DTHXK.js +316 -0
- package/dist/chunk-2QTQ6BUH.mjs +46 -0
- package/dist/chunk-2UN4SFLR.mjs +100 -0
- package/dist/chunk-2V75I7K3.js +454 -0
- package/dist/chunk-2V7IL4HC.js +10 -0
- package/dist/chunk-34XBXUMW.js +296 -0
- package/dist/chunk-3C4C654I.js +71 -0
- package/dist/chunk-3DAD2LDF.mjs +72 -0
- package/dist/chunk-3GXH2NFD.mjs +4 -0
- package/dist/chunk-3O47ZFW3.js +961 -0
- package/dist/chunk-3OY3VYNF.mjs +11 -0
- package/dist/chunk-3S6WPBZL.js +2936 -0
- package/dist/chunk-3TUOUP5T.js +399 -0
- package/dist/chunk-3VEH23I5.mjs +1380 -0
- package/dist/chunk-3ZYSAW2T.mjs +263 -0
- package/dist/chunk-4ANVF274.js +103 -0
- package/dist/chunk-4C7I3ELN.js +388 -0
- package/dist/chunk-4DYKAYFO.mjs +8 -0
- package/dist/chunk-4ZDR72SG.js +329 -0
- package/dist/chunk-52YS45RR.js +1066 -0
- package/dist/chunk-5325XSCH.js +107 -0
- package/dist/chunk-5AD5X6AV.js +13 -0
- package/dist/chunk-5BYDGGWO.mjs +197 -0
- package/dist/chunk-5C3C7VDM.mjs +55 -0
- package/dist/chunk-5HFMY3D7.js +660 -0
- package/dist/chunk-5LH2QN3T.js +1862 -0
- package/dist/chunk-5PJEXSOW.js +44 -0
- package/dist/chunk-5SXDH3Y7.js +90 -0
- package/dist/chunk-5YFBGGCK.mjs +502 -0
- package/dist/chunk-5YWN6H5Q.mjs +133 -0
- package/dist/chunk-66QP3SMN.js +402 -0
- package/dist/chunk-6DAEZKIG.mjs +385 -0
- package/dist/chunk-6DATW7TB.mjs +420 -0
- package/dist/{chunk-JRGK3NXR.mjs → chunk-6ETDAU62.mjs} +72 -212
- package/dist/chunk-6H254EVP.mjs +178 -0
- package/dist/chunk-6PFNJPBJ.mjs +820 -0
- package/dist/chunk-6PJWXIFX.mjs +357 -0
- package/dist/chunk-6SWKWCMS.js +80 -0
- package/dist/chunk-6VVXXX7S.js +808 -0
- package/dist/chunk-6WUBSMTX.js +1403 -0
- package/dist/chunk-73SGZLAQ.mjs +35 -0
- package/dist/chunk-76L2V6KD.mjs +4 -0
- package/dist/chunk-7AAIAVAA.js +1531 -0
- package/dist/chunk-7ARSJPV3.mjs +93 -0
- package/dist/chunk-7BHW5GTC.mjs +1234 -0
- package/dist/chunk-7DQSDKDU.js +6 -0
- package/dist/chunk-7IQQQENP.mjs +401 -0
- package/dist/chunk-7KFTYENS.js +11357 -0
- package/dist/chunk-7SM6XSPZ.js +3171 -0
- package/dist/chunk-7SXOHAIR.mjs +28 -0
- package/dist/chunk-A2MAX6S4.js +90 -0
- package/dist/chunk-A33OORT7.mjs +1530 -0
- package/dist/{chunk-U6ACF76H.mjs → chunk-A36JRXXH.mjs} +1075 -1845
- package/dist/chunk-A7BU3BK4.js +52 -0
- package/dist/chunk-A7MQSN2V.mjs +77 -0
- package/dist/chunk-A7V4L2IT.mjs +416 -0
- package/dist/chunk-AABEK6XU.js +226 -0
- package/dist/chunk-AGV33FWC.mjs +5005 -0
- package/dist/chunk-AHNR3BXI.js +108 -0
- package/dist/chunk-AQ5RLBU2.mjs +286 -0
- package/dist/chunk-AQOE6WCG.js +1270 -0
- package/dist/chunk-ATAWRACV.mjs +62 -0
- package/dist/chunk-ATCURNUV.js +14 -0
- package/dist/chunk-AWPV33OO.js +6 -0
- package/dist/chunk-AYJPHKYV.js +337 -0
- package/dist/chunk-AZ5BGWHB.js +162 -0
- package/dist/chunk-AZAXD44P.js +1373 -0
- package/dist/chunk-BBGKQIJJ.mjs +406 -0
- package/dist/chunk-BP4JLSUA.js +1453 -0
- package/dist/{chunk-SUCE7FWA.mjs → chunk-BTUSVHIE.mjs} +539 -978
- package/dist/chunk-BU6OK542.mjs +818 -0
- package/dist/chunk-CVSRWM6W.js +418 -0
- package/dist/chunk-CYBMFMJD.mjs +247 -0
- package/dist/chunk-DDJLDOUX.mjs +217 -0
- package/dist/{chunk-V32BCG7M.js → chunk-DFZWHNRG.js} +75 -215
- package/dist/chunk-DJ2C7AVG.js +644 -0
- package/dist/chunk-DS2VU4WW.mjs +102 -0
- package/dist/chunk-DSAG7T5P.js +7290 -0
- package/dist/chunk-E2QPPH7I.js +327 -0
- package/dist/chunk-E65WCTIG.mjs +1187 -0
- package/dist/{chunk-33VCYWVL.mjs → chunk-E6QQKDNE.mjs} +30 -42
- package/dist/chunk-ECDK6QBF.mjs +981 -0
- package/dist/chunk-EIB4OWVQ.mjs +620 -0
- package/dist/chunk-EQUZYCGO.js +250 -0
- package/dist/chunk-F3UJ6ZRM.mjs +313 -0
- package/dist/chunk-F63N2ZTQ.js +7023 -0
- package/dist/chunk-F6XRYEM3.mjs +26 -0
- package/dist/chunk-FE6VCE4K.js +5030 -0
- package/dist/chunk-FLWD6GRR.js +1372 -0
- package/dist/chunk-FQBFWJBS.mjs +110 -0
- package/dist/chunk-FXVJ2HFU.js +26 -0
- package/dist/chunk-FZMQMQBW.js +312 -0
- package/dist/chunk-G3EEC44R.js +53 -0
- package/dist/{chunk-KG3WT4PR.mjs → chunk-GCKWKLZF.mjs} +73 -104
- package/dist/chunk-GCX7TY4D.mjs +6826 -0
- package/dist/chunk-GDB6TCSD.js +450 -0
- package/dist/chunk-GDCV4IWO.mjs +21 -0
- package/dist/chunk-GDZT5LZ5.js +170 -0
- package/dist/chunk-GHPUYD4I.mjs +213 -0
- package/dist/chunk-GHS6MIL6.mjs +1432 -0
- package/dist/chunk-GPS2THCL.mjs +11 -0
- package/dist/{chunk-EV2EVOYS.js → chunk-GTJWQAGU.js} +31 -42
- package/dist/chunk-GVTI6UJQ.mjs +130 -0
- package/dist/chunk-GXKI64OT.mjs +1138 -0
- package/dist/chunk-GYDYF2WX.js +275 -0
- package/dist/chunk-GYLP6UG4.mjs +705 -0
- package/dist/chunk-H3OQKK6X.js +1158 -0
- package/dist/chunk-H5DFSCJ6.js +40 -0
- package/dist/chunk-HAGEIC2L.mjs +186 -0
- package/dist/chunk-HAJ4JRFO.js +293 -0
- package/dist/chunk-HDR72GB6.js +188 -0
- package/dist/chunk-HF5HPS4T.mjs +40 -0
- package/dist/chunk-HK6LOFDS.js +218 -0
- package/dist/chunk-HMWYTXCY.mjs +143 -0
- package/dist/chunk-HPCSRCMA.js +89 -0
- package/dist/chunk-HSEO6TPU.js +247 -0
- package/dist/chunk-I5FOHCLH.js +132 -0
- package/dist/chunk-IDLW4NWA.mjs +85 -0
- package/dist/chunk-IIDZ5WUX.js +61 -0
- package/dist/chunk-IR74FJHU.js +2332 -0
- package/dist/chunk-IRVFYAKP.mjs +100 -0
- package/dist/{chunk-XBL3TMPC.mjs → chunk-IZDWAL53.mjs} +1795 -3287
- package/dist/chunk-J2KZXIU3.js +51 -0
- package/dist/chunk-J2U6PJSO.js +91 -0
- package/dist/chunk-J5AJNY2N.js +283 -0
- package/dist/chunk-J6KQZ4FO.mjs +821 -0
- package/dist/{chunk-OWW5GUSB.js → chunk-JGBCIKJV.js} +7 -6
- package/dist/chunk-JKGTBMU7.mjs +25 -0
- package/dist/chunk-JR3TNEQC.js +422 -0
- package/dist/chunk-JURRXY2J.mjs +29 -0
- package/dist/chunk-K3HW5I2A.mjs +317 -0
- package/dist/chunk-K46SMZ66.mjs +103 -0
- package/dist/chunk-K4UDGE3Z.mjs +6 -0
- package/dist/chunk-KDQOR4QQ.mjs +350 -0
- package/dist/chunk-KDTVOLHI.mjs +288 -0
- package/dist/chunk-KGHJH5KJ.mjs +35 -0
- package/dist/chunk-KIZOA5LX.mjs +140 -0
- package/dist/chunk-KK6HYVBI.mjs +242 -0
- package/dist/chunk-KMKWGXMK.js +856 -0
- package/dist/chunk-KPA6K5IB.js +80 -0
- package/dist/chunk-KU7O4IXU.mjs +260 -0
- package/dist/chunk-KVFNRJOR.mjs +11142 -0
- package/dist/chunk-KZJRSXHK.js +2432 -0
- package/dist/chunk-LHWPRUJL.js +79 -0
- package/dist/chunk-LIV3KXJG.mjs +369 -0
- package/dist/chunk-LKV4LACG.js +21 -0
- package/dist/chunk-LUY45X3U.mjs +263 -0
- package/dist/chunk-LYEZZEEF.mjs +17 -0
- package/dist/chunk-M5EXQZYY.mjs +1519 -0
- package/dist/chunk-ME6HGG4I.mjs +1338 -0
- package/dist/chunk-MEXP6DA6.js +31 -0
- package/dist/chunk-MG52AW3H.js +902 -0
- package/dist/chunk-MIPO6F72.js +334 -0
- package/dist/{chunk-5QW7CQBA.js → chunk-MKIJQL5Q.js} +211 -321
- package/dist/chunk-MN3YETVN.mjs +17 -0
- package/dist/chunk-MOBSBXVE.mjs +2391 -0
- package/dist/chunk-MOMOZEUM.mjs +88 -0
- package/dist/chunk-MRFUNRAP.js +62 -0
- package/dist/chunk-MTIHEW2M.js +433 -0
- package/dist/chunk-N4RGGDEL.mjs +73 -0
- package/dist/chunk-NH654HAT.js +10 -0
- package/dist/chunk-NHJUGZUR.mjs +253 -0
- package/dist/chunk-NMQT4HG3.mjs +757 -0
- package/dist/chunk-NPSYB6DC.mjs +906 -0
- package/dist/chunk-NW2GPMSO.js +857 -0
- package/dist/chunk-NXKQOQ6L.js +76 -0
- package/dist/chunk-NXLAZIJZ.js +309 -0
- package/dist/chunk-NYWNA5CF.js +148 -0
- package/dist/chunk-NZTKLY2W.js +1442 -0
- package/dist/chunk-O2ICABUD.js +36 -0
- package/dist/chunk-OIVVQQ22.js +862 -0
- package/dist/chunk-OKC2B4O3.mjs +312 -0
- package/dist/chunk-OLWFPDBK.js +2220 -0
- package/dist/chunk-OMTVH334.js +3779 -0
- package/dist/chunk-OQRVEM56.mjs +362 -0
- package/dist/chunk-OXMIBOD4.js +337 -0
- package/dist/chunk-PBL6YL5L.mjs +288 -0
- package/dist/chunk-PDOELNNQ.js +97 -0
- package/dist/chunk-PDQJY2GZ.js +136 -0
- package/dist/chunk-PKOZXD2Q.js +1274 -0
- package/dist/chunk-PPF2BYFL.mjs +2191 -0
- package/dist/chunk-PQTQKNKD.js +539 -0
- package/dist/chunk-PRSR4FAV.mjs +81 -0
- package/dist/chunk-PTRNO5UD.js +95 -0
- package/dist/chunk-Q2Y3VMKH.js +2000 -0
- package/dist/chunk-QCZOE65N.js +96 -0
- package/dist/chunk-QDYFLATW.mjs +52 -0
- package/dist/chunk-QQABGCMM.js +22 -0
- package/dist/chunk-QS6TRHMR.js +345 -0
- package/dist/chunk-R56P64LB.mjs +208 -0
- package/dist/chunk-RCQ2MPBV.js +428 -0
- package/dist/chunk-RFVRPYR2.mjs +856 -0
- package/dist/chunk-RKBLPGPV.js +11521 -0
- package/dist/chunk-RM2V4IND.mjs +327 -0
- package/dist/chunk-RQXN5A34.mjs +613 -0
- package/dist/chunk-RUVGVNOF.mjs +2687 -0
- package/dist/chunk-SAFJIGYB.mjs +165 -0
- package/dist/chunk-SKQFLBDD.js +263 -0
- package/dist/chunk-SMK6JU2F.mjs +2092 -0
- package/dist/{chunk-UVRPC2P7.js → chunk-SNNEOS5Z.js} +1984 -3476
- package/dist/chunk-SPCRQ6NO.mjs +1246 -0
- package/dist/chunk-SWX4SALA.mjs +19 -0
- package/dist/{chunk-JVODCGFP.mjs → chunk-SYEO2WV4.mjs} +128 -238
- package/dist/chunk-T2QQMX2N.js +10 -0
- package/dist/chunk-T3AFF3L7.mjs +57 -0
- package/dist/chunk-T6Z2EXYL.js +712 -0
- package/dist/chunk-T7LOXGYX.js +118 -0
- package/dist/chunk-TJCAE7RC.mjs +1315 -0
- package/dist/chunk-TJI3K6RP.js +137 -0
- package/dist/chunk-TL2SVO4P.mjs +55 -0
- package/dist/chunk-TM63CYGN.mjs +399 -0
- package/dist/chunk-TU5RYTYU.mjs +13 -0
- package/dist/chunk-TVJZ4GPS.js +1553 -0
- package/dist/chunk-TWM6DLYF.js +371 -0
- package/dist/chunk-U63OC4TQ.js +30 -0
- package/dist/{chunk-L5GKVQVJ.js → chunk-U6BVSJZ6.js} +25 -57
- package/dist/chunk-U6UVWEAK.mjs +792 -0
- package/dist/chunk-UCEPNO6N.mjs +11048 -0
- package/dist/{chunk-ANT574FD.js → chunk-UCR5HRYM.js} +74 -105
- package/dist/chunk-UG5BTOTF.mjs +334 -0
- package/dist/chunk-UGH37BQW.mjs +157 -0
- package/dist/chunk-V7ZRH3PY.mjs +271 -0
- package/dist/chunk-VBGHBL3E.mjs +1394 -0
- package/dist/chunk-VRBDAS5I.js +920 -0
- package/dist/chunk-VVE3Y76O.js +230 -0
- package/dist/chunk-W65JIRI4.mjs +1182 -0
- package/dist/chunk-WHYKAT7G.js +62 -0
- package/dist/{chunk-YOIVZ6OA.mjs → chunk-WIZRUIZB.mjs} +25 -57
- package/dist/chunk-WKWTDZS7.js +385 -0
- package/dist/chunk-WLMINRC4.mjs +78 -0
- package/dist/chunk-WOF3AD3J.js +22 -0
- package/dist/chunk-WWKMOA76.js +1262 -0
- package/dist/chunk-X5A5FOWW.js +615 -0
- package/dist/chunk-X6CN6KQF.mjs +192 -0
- package/dist/chunk-XD2PMH46.mjs +517 -0
- package/dist/chunk-XJA2NGTI.mjs +88 -0
- package/dist/chunk-XJIHN3BY.mjs +8 -0
- package/dist/chunk-XK6UDWJS.js +203 -0
- package/dist/chunk-XPG3N5CF.mjs +415 -0
- package/dist/chunk-XVZ2NKSU.mjs +74 -0
- package/dist/chunk-XYP45OLE.js +117 -0
- package/dist/chunk-XZSDGZX6.mjs +301 -0
- package/dist/chunk-Y2EMGN4T.mjs +120 -0
- package/dist/chunk-Y3XWP5XW.mjs +298 -0
- package/dist/chunk-Y4K22JL6.js +228 -0
- package/dist/chunk-Y65LXQGA.mjs +3164 -0
- package/dist/chunk-Y66WVMO5.mjs +87 -0
- package/dist/chunk-Y7JWLB25.mjs +7280 -0
- package/dist/chunk-YCDXAJKU.js +175 -0
- package/dist/chunk-YRDQCCIS.js +152 -0
- package/dist/chunk-YV52DGSA.js +111 -0
- package/dist/chunk-YXGZQPUD.js +94 -0
- package/dist/chunk-Z3A3AFVU.mjs +102 -0
- package/dist/chunk-ZCY6YKKP.mjs +475 -0
- package/dist/chunk-ZEQHXVU5.js +215 -0
- package/dist/chunk-ZF7JCXCI.js +284 -0
- package/dist/chunk-ZJBRUH6V.js +29 -0
- package/dist/chunk-ZMIL4ZOA.js +365 -0
- package/dist/chunk-ZR5ULMN2.mjs +337 -0
- package/dist/chunk-ZXREOYOW.js +87 -0
- package/dist/{client-BSP9U1O1.d.mts → client-CX_WR0-J.d.mts} +2 -2
- package/dist/client-Dytx_ZTC.d.ts +230 -0
- package/dist/{client-B878xeAP.d.ts → client-dqOhP9Nc.d.ts} +2 -2
- package/dist/client-hTKbCuhG.d.mts +230 -0
- package/dist/clock-B-UAjkKa.d.mts +5 -0
- package/dist/clock-B-UAjkKa.d.ts +5 -0
- package/dist/config-BlXQluJR.d.mts +36 -0
- package/dist/config-BlXQluJR.d.ts +36 -0
- package/dist/courier-Cnn-edJ4.d.ts +95 -0
- package/dist/courier-FmGfkvIN.d.mts +95 -0
- package/dist/crowd-DdHFbqKK.d.ts +186 -0
- package/dist/crowd-hOVSAmA3.d.mts +186 -0
- package/dist/danfo-BEBapFlX.d.mts +146 -0
- package/dist/danfo-UQ_PTIIx.d.ts +146 -0
- package/dist/{elements-Bty6Qs_N.d.mts → elements-DdsRig-2.d.mts} +1548 -257
- package/dist/{elements-Bty6Qs_N.d.ts → elements-DdsRig-2.d.ts} +1548 -257
- package/dist/engines/godot.d.mts +56 -0
- package/dist/engines/godot.d.ts +56 -0
- package/dist/engines/godot.js +28 -0
- package/dist/engines/godot.mjs +3 -0
- package/dist/engines/wasm.d.mts +11 -0
- package/dist/engines/wasm.d.ts +11 -0
- package/dist/engines/wasm.js +178 -0
- package/dist/engines/wasm.mjs +176 -0
- package/dist/fallback-CrG_lTFk.d.mts +270 -0
- package/dist/fallback-CrG_lTFk.d.ts +270 -0
- package/dist/fallback-KDB4Y2CE.mjs +6 -0
- package/dist/fallback-Y26TQENE.js +19 -0
- package/dist/features-CZB4rmcD.d.mts +118 -0
- package/dist/features-CZB4rmcD.d.ts +118 -0
- package/dist/fit-BWiE7rgA.d.mts +44 -0
- package/dist/fit-DK0oT7zO.d.ts +44 -0
- package/dist/five-a-side-Bv1AOUy3.d.mts +115 -0
- package/dist/five-a-side-EC51SJY1.d.ts +115 -0
- package/dist/fluid-ARr0qUIL.d.ts +939 -0
- package/dist/fluid-DLlEj2cs.d.mts +939 -0
- package/dist/game/conformance.d.mts +84 -0
- package/dist/game/conformance.d.ts +84 -0
- package/dist/game/conformance.js +1025 -0
- package/dist/game/conformance.mjs +994 -0
- package/dist/game/heap.d.mts +40 -0
- package/dist/game/heap.d.ts +40 -0
- package/dist/game/heap.js +48 -0
- package/dist/game/heap.mjs +7 -0
- package/dist/game/kit/canvas.d.mts +240 -0
- package/dist/game/kit/canvas.d.ts +240 -0
- package/dist/game/kit/canvas.js +3566 -0
- package/dist/game/kit/canvas.mjs +1039 -0
- package/dist/game/kit/courier.d.mts +17 -0
- package/dist/game/kit/courier.d.ts +17 -0
- package/dist/game/kit/courier.js +66 -0
- package/dist/game/kit/courier.mjs +49 -0
- package/dist/game/kit/danfo.d.mts +11 -0
- package/dist/game/kit/danfo.d.ts +11 -0
- package/dist/game/kit/danfo.js +109 -0
- package/dist/game/kit/danfo.mjs +44 -0
- package/dist/game/kit/engine.d.mts +29 -0
- package/dist/game/kit/engine.d.ts +29 -0
- package/dist/game/kit/engine.js +183 -0
- package/dist/game/kit/engine.mjs +30 -0
- package/dist/game/kit/five-a-side.d.mts +11 -0
- package/dist/game/kit/five-a-side.d.ts +11 -0
- package/dist/game/kit/five-a-side.js +86 -0
- package/dist/game/kit/five-a-side.mjs +41 -0
- package/dist/game/kit/frontier.d.mts +344 -0
- package/dist/game/kit/frontier.d.ts +344 -0
- package/dist/game/kit/frontier.js +435 -0
- package/dist/game/kit/frontier.mjs +14 -0
- package/dist/game/kit/genesis.d.mts +752 -0
- package/dist/game/kit/genesis.d.ts +752 -0
- package/dist/game/kit/genesis.js +380 -0
- package/dist/game/kit/genesis.mjs +15 -0
- package/dist/game/kit/ludo.d.mts +15 -0
- package/dist/game/kit/ludo.d.ts +15 -0
- package/dist/game/kit/ludo.js +87 -0
- package/dist/game/kit/ludo.mjs +42 -0
- package/dist/game/kit/runner.d.mts +12 -0
- package/dist/game/kit/runner.d.ts +12 -0
- package/dist/game/kit/runner.js +83 -0
- package/dist/game/kit/runner.mjs +46 -0
- package/dist/game/kit/shootout.d.mts +13 -0
- package/dist/game/kit/shootout.d.ts +13 -0
- package/dist/game/kit/shootout.js +122 -0
- package/dist/game/kit/shootout.mjs +57 -0
- package/dist/game/kit/slots.d.mts +392 -0
- package/dist/game/kit/slots.d.ts +392 -0
- package/dist/game/kit/slots.js +215 -0
- package/dist/game/kit/slots.mjs +6 -0
- package/dist/game/kit/tycoon.d.mts +16 -0
- package/dist/game/kit/tycoon.d.ts +16 -0
- package/dist/game/kit/tycoon.js +145 -0
- package/dist/game/kit/tycoon.mjs +44 -0
- package/dist/game/kit/word.d.mts +11 -0
- package/dist/game/kit/word.d.ts +11 -0
- package/dist/game/kit/word.js +78 -0
- package/dist/game/kit/word.mjs +41 -0
- package/dist/game/kit/worlds.d.mts +18 -0
- package/dist/game/kit/worlds.d.ts +18 -0
- package/dist/game/kit/worlds.js +74 -0
- package/dist/game/kit/worlds.mjs +49 -0
- package/dist/game/kit.d.mts +53 -0
- package/dist/game/kit.d.ts +53 -0
- package/dist/game/kit.js +2610 -0
- package/dist/game/kit.mjs +101 -0
- package/dist/game/prepared.d.mts +14 -0
- package/dist/game/prepared.d.ts +14 -0
- package/dist/game/prepared.js +81 -0
- package/dist/game/prepared.mjs +32 -0
- package/dist/game-Bx8onkhX.d.mts +1451 -0
- package/dist/game-fgQy2YIm.d.ts +1451 -0
- package/dist/game-theme-CBTw1b_d.d.mts +35 -0
- package/dist/game-theme-Dg-ict5A.d.ts +35 -0
- package/dist/game.d.mts +3546 -0
- package/dist/game.d.ts +3546 -0
- package/dist/game.js +4455 -0
- package/dist/game.mjs +50 -0
- package/dist/graphics-C6YjWYvP.d.ts +5 -0
- package/dist/graphics-Dk2yQnYN.d.mts +5 -0
- package/dist/guest-DrsA00XD.d.mts +732 -0
- package/dist/guest-wIdfoT05.d.ts +732 -0
- package/dist/hit-stop-BKkVwTq7.d.mts +43 -0
- package/dist/hit-stop-D-8pPYnM.d.ts +43 -0
- package/dist/hot-Crn9XpHJ.d.ts +29 -0
- package/dist/hot-DH3nOhQD.d.mts +29 -0
- package/dist/{index-CQStGb3B.d.mts → index-6gkHMGAq.d.mts} +2 -2
- package/dist/index-B8ybCKJI.d.ts +41 -0
- package/dist/{index-DJwXmoaP.d.ts → index-B98Xac8e.d.ts} +2 -2
- package/dist/{index-B7oA_1XI.d.ts → index-B_ByTtIT.d.ts} +2 -2
- package/dist/index-DHjNHb1c.d.mts +41 -0
- package/dist/{index-DhUSTAhT.d.mts → index-DbAN_VQE.d.mts} +2 -2
- package/dist/index.d.mts +134 -24
- package/dist/index.d.ts +134 -24
- package/dist/index.js +407 -248
- package/dist/index.mjs +184 -58
- package/dist/interactives-authoring.d.mts +231 -0
- package/dist/interactives-authoring.d.ts +231 -0
- package/dist/interactives-authoring.js +1743 -0
- package/dist/interactives-authoring.mjs +1704 -0
- package/dist/interactives-canvas.global.js +148 -0
- package/dist/interactives-guest.d.mts +20 -0
- package/dist/interactives-guest.d.ts +20 -0
- package/dist/interactives-guest.js +63 -0
- package/dist/interactives-guest.json +1 -0
- package/dist/interactives-guest.mjs +61 -0
- package/dist/interactives-jsc.global.js +9357 -0
- package/dist/interactives-meters.d.mts +93 -0
- package/dist/interactives-meters.d.ts +93 -0
- package/dist/interactives-meters.js +252 -0
- package/dist/interactives-meters.mjs +68 -0
- package/dist/interactives-production.d.mts +430 -0
- package/dist/interactives-production.d.ts +430 -0
- package/dist/interactives-production.js +1231 -0
- package/dist/interactives-production.mjs +1170 -0
- package/dist/interactives-record.d.mts +112 -0
- package/dist/interactives-record.d.ts +112 -0
- package/dist/interactives-record.js +302 -0
- package/dist/interactives-record.mjs +295 -0
- package/dist/interactives-runtime.d.mts +61 -0
- package/dist/interactives-runtime.d.ts +61 -0
- package/dist/interactives-runtime.js +442 -0
- package/dist/interactives-runtime.mjs +25 -0
- package/dist/interactives-studio-kernel.global.js +1 -0
- package/dist/interactives-studio.d.mts +806 -0
- package/dist/interactives-studio.d.ts +806 -0
- package/dist/interactives-studio.js +5741 -0
- package/dist/interactives-studio.mjs +5651 -0
- package/dist/interactives-tick.d.mts +90 -0
- package/dist/interactives-tick.d.ts +90 -0
- package/dist/interactives-tick.js +203 -0
- package/dist/interactives-tick.mjs +6 -0
- package/dist/interactives-web.d.mts +762 -0
- package/dist/interactives-web.d.ts +762 -0
- package/dist/interactives-web.js +5000 -0
- package/dist/interactives-web.mjs +4628 -0
- package/dist/interactives.d.mts +2430 -0
- package/dist/interactives.d.ts +2430 -0
- package/dist/interactives.js +5723 -0
- package/dist/interactives.mjs +4333 -0
- package/dist/juice-CoHxlpKA.d.ts +42 -0
- package/dist/juice-DQztFS43.d.mts +42 -0
- package/dist/launch-T2f4_Di4.d.mts +151 -0
- package/dist/launch-d6oreMzR.d.ts +151 -0
- package/dist/library-DXYaMFhi.d.mts +69 -0
- package/dist/library-DXYaMFhi.d.ts +69 -0
- package/dist/link-BUTqGmyi.d.mts +38 -0
- package/dist/link-BUTqGmyi.d.ts +38 -0
- package/dist/lint.js +104 -204
- package/dist/lint.mjs +103 -203
- package/dist/local-D8_I6UeL.d.mts +6967 -0
- package/dist/local-VZkqsCzR.d.ts +6967 -0
- package/dist/lockstep-BLf6dglI.d.mts +321 -0
- package/dist/lockstep-D50Ia0JW.d.ts +321 -0
- package/dist/ludo-B8ClkDqr.d.ts +205 -0
- package/dist/ludo-BOuohQ-M.d.mts +205 -0
- package/dist/mock/cli.mjs +200 -56
- package/dist/mock/library.js +200 -56
- package/dist/mock/library.mjs +200 -56
- package/dist/mock/msw.js +200 -56
- package/dist/mock/msw.mjs +200 -56
- package/dist/native-BodxSh03.d.mts +16 -0
- package/dist/native-DUHMT8gA.d.ts +16 -0
- package/dist/network-ZXLD7l1b.d.mts +19 -0
- package/dist/network-ZXLD7l1b.d.ts +19 -0
- package/dist/online-XeymeM9s.d.ts +381 -0
- package/dist/online-d7W_Al9a.d.mts +381 -0
- package/dist/params-DxFb5G_U.d.mts +155 -0
- package/dist/params-DxFb5G_U.d.ts +155 -0
- package/dist/play-BRRlfLhX.d.ts +940 -0
- package/dist/play-ClrMd_e8.d.mts +940 -0
- package/dist/policy-CCw8tXLm.d.mts +3078 -0
- package/dist/policy-CMqOSQIu.d.ts +3078 -0
- package/dist/ports-B_0v_P3A.d.mts +13 -0
- package/dist/ports-CGU_3e_0.d.ts +13 -0
- package/dist/prefetch-BHnicOQj.d.ts +117 -0
- package/dist/prefetch-CBXgYacv.d.mts +117 -0
- package/dist/{price-CSztR02F.d.mts → price-BOzexBww.d.mts} +1 -1
- package/dist/{price-C_vasx9A.d.ts → price-C1h9sPxE.d.ts} +1 -1
- package/dist/protocol-C8qbpUbT.d.mts +242 -0
- package/dist/protocol-C8qbpUbT.d.ts +242 -0
- package/dist/rapier-AZHT4YI7.js +7886 -0
- package/dist/rapier-ODEPCQA6.mjs +7792 -0
- package/dist/react.d.mts +157 -15
- package/dist/react.d.ts +157 -15
- package/dist/react.js +5564 -5904
- package/dist/react.mjs +5451 -5808
- package/dist/runner-CQcLL7By.d.ts +189 -0
- package/dist/runner-D46Yj-wE.d.mts +189 -0
- package/dist/runtime-BRWfkf_q.d.mts +51 -0
- package/dist/runtime-DyuBMkKM.d.ts +51 -0
- package/dist/scheduling-D2ajXpMC.d.ts +224 -0
- package/dist/scheduling-DSRbbaZb.d.mts +224 -0
- package/dist/schema-BrWxzKp6.d.mts +63 -0
- package/dist/schema-BrWxzKp6.d.ts +63 -0
- package/dist/server/evict.js +34 -37
- package/dist/server/evict.mjs +34 -37
- package/dist/server/tanstack.d.mts +49 -3
- package/dist/server/tanstack.d.ts +49 -3
- package/dist/server/tanstack.js +169 -117
- package/dist/server/tanstack.mjs +166 -118
- package/dist/{server-Dckg4Vdr.d.ts → server-D29IIuDV.d.ts} +136 -130
- package/dist/{server-B6dW7-Lj.d.mts → server-DQMWPnc8.d.mts} +136 -130
- package/dist/server.d.mts +45 -5
- package/dist/server.d.ts +45 -5
- package/dist/server.js +171 -227
- package/dist/server.mjs +165 -225
- package/dist/session-grant-CJ27DwrT.d.mts +19 -0
- package/dist/session-grant-CJ27DwrT.d.ts +19 -0
- package/dist/shootout-BJZeX6FG.d.ts +140 -0
- package/dist/shootout-tcZd1Rxt.d.mts +140 -0
- package/dist/state-replica-stMtdkVD.d.mts +42 -0
- package/dist/state-replica-stMtdkVD.d.ts +42 -0
- package/dist/studio-CowqWqez.d.mts +14 -0
- package/dist/studio-CowqWqez.d.ts +14 -0
- package/dist/styles.css +1 -1
- package/dist/template-AhCdB1kW.d.mts +190 -0
- package/dist/template-BkEGVTQj.d.ts +190 -0
- package/dist/terrain-BMxEc6Oc.d.ts +429 -0
- package/dist/terrain-C-XC1Oui.d.mts +429 -0
- package/dist/testing/msw.d.mts +28 -4
- package/dist/testing/msw.d.ts +28 -4
- package/dist/testing/msw.js +15 -21
- package/dist/testing/msw.mjs +15 -21
- package/dist/testing/suite.d.mts +6 -5
- package/dist/testing/suite.d.ts +6 -5
- package/dist/testing/suite.js +89 -124
- package/dist/testing/suite.mjs +81 -116
- package/dist/testing.d.mts +27 -1227
- package/dist/testing.d.ts +27 -1227
- package/dist/testing.js +127 -131
- package/dist/testing.mjs +19 -23
- package/dist/tick-transport-C8QEh8Uw.d.mts +50 -0
- package/dist/tick-transport-UjHY3xK1.d.ts +50 -0
- package/dist/timeline-protocol-hp6e8zFB.d.mts +47 -0
- package/dist/timeline-protocol-hp6e8zFB.d.ts +47 -0
- package/dist/tokens-DhanQRQS.d.mts +21 -0
- package/dist/tokens-K8yxwd6G.d.ts +21 -0
- package/dist/tree-C-Io2Hbx.d.mts +35 -0
- package/dist/tree-CP_qSW4H.d.ts +35 -0
- package/dist/tycoon-B5KHk2Xx.d.mts +255 -0
- package/dist/tycoon-hmHo-3HX.d.ts +255 -0
- package/dist/types-BQkxPwZP.d.mts +219 -0
- package/dist/types-D_f6UUxM.d.ts +219 -0
- package/dist/ui-DwHicuFv.d.mts +563 -0
- package/dist/ui-hi7S2YcH.d.ts +563 -0
- package/dist/{sign-in-DQlIdqsi.d.mts → url-52ndUruG.d.mts} +15 -1
- package/dist/{sign-in-DQlIdqsi.d.ts → url-52ndUruG.d.ts} +15 -1
- package/dist/utils.d.mts +3 -3
- package/dist/utils.d.ts +3 -3
- package/dist/utils.js +37 -37
- package/dist/utils.mjs +4 -4
- package/dist/vars-Dc_PrhBK.d.mts +511 -0
- package/dist/vars-Dc_PrhBK.d.ts +511 -0
- package/dist/vm-IUARFFAI.mjs +63 -0
- package/dist/vm-N7L6MGGH.js +65 -0
- package/dist/weave-delivery-CW-Kstut.d.mts +360 -0
- package/dist/weave-delivery-CW-Kstut.d.ts +360 -0
- package/dist/web-Dss74a7v.d.ts +883 -0
- package/dist/web-f9ZQPoyw.d.mts +883 -0
- package/dist/web-transport-C7MkBL0a.d.ts +19 -0
- package/dist/web-transport-aYEqXMd9.d.mts +19 -0
- package/dist/weight-CPGjsgjV.d.ts +92 -0
- package/dist/weight-tF1ODR1p.d.mts +92 -0
- package/dist/word-BcX9Jcmv.d.mts +70 -0
- package/dist/word-C7sVPLHm.d.ts +70 -0
- package/dist/world-PvILHDR1.d.ts +2285 -0
- package/dist/world-qekkXjJv.d.mts +2285 -0
- package/dist/worlds-Br2Pb0Cs.d.ts +109 -0
- package/dist/worlds-D5ydYr7d.d.mts +109 -0
- package/engines/c/cimplify.h +108 -0
- package/engines/c/cimplify.lib.js +11 -0
- package/engines/godot/addons/cimplify/cimplify.gd +97 -0
- package/engines/rust/interactives-ctx/Cargo.toml +9 -0
- package/engines/rust/interactives-ctx/src/lib.rs +189 -0
- package/package.json +189 -3
- package/vendor/rapier3d-compat/LICENSE +201 -0
- package/vendor/rapier3d-compat/PATCHES.md +61 -0
- package/dist/chunk-2P4KXFB6.js +0 -274
- package/dist/chunk-3G6RQLXK.mjs +0 -21
- package/dist/chunk-3V4DVXV3.mjs +0 -254
- package/dist/chunk-EDK3LNM6.js +0 -2436
- package/dist/chunk-F7J3HK27.js +0 -4549
- package/dist/chunk-U4MW6PYU.mjs +0 -23
- package/dist/chunk-XREIZ56K.js +0 -26
|
@@ -0,0 +1,4333 @@
|
|
|
1
|
+
export { UI_CLOCK_SECONDS, currencyCounter, dialogueBox, iconButton, itemCard, panel, progressBar, tabs, toast, uiClock, worldLabel } from './chunk-3ZYSAW2T.mjs';
|
|
2
|
+
import { yawRotation, withinWorld, snappedToGrid, snapHeightToGrid, overlapsFootprint, movedAbout, identityTransform, encodeTransformSelection, encodeSettings, encodeSetTransform, encodeSelect, encodePlace, encodeModerate, encodeJoinCopy, encodeDuplicate, encodeClock, encodeBare, copyTransform, connectWorld, canonical, bounds, WorldRoleCode, WorldMirror, WorldBuilder, Visibility, TRANSFORM_WORDS, Status, Sky, SelectMode, Sanction, SNAP_SURFACE, SNAP_GRID, SCALE, ROTATION, POSITION, Notice, NOT_SENT, MessageKind, LocalWorld, Likeness, Lighting, Ground, CommandWriter, COMMAND_OP_ID_BYTES, BOUNDS_WORDS, BOUNDS_MIN, BOUNDS_MAX, Action } from './chunk-NPSYB6DC.mjs';
|
|
3
|
+
export { LOCKSTEP_AXIS_LIMIT, LOCKSTEP_AXIS_X, LOCKSTEP_AXIS_Z, LOCKSTEP_BATCH_BYTES, LOCKSTEP_BUTTONS, LOCKSTEP_CONFIG_HEADER_BYTES, LOCKSTEP_CONFIG_MAX_WORDS, LOCKSTEP_CONFIG_TAG, LOCKSTEP_INPUT_ACTION, LOCKSTEP_INPUT_STRIDE, LOCKSTEP_MAX_SEATS, LOCKSTEP_PRESENT, LOCKSTEP_REFEREE_BYTES, LOCKSTEP_WINDOW, LockstepLoopback, LockstepPhase, LockstepRecord, LockstepSession, createTickRoomSimulation, decodeLockstepRecord, defineLockstep, defineLockstepRoom, encodeLockstepConfig, lockstepChecksum, lockstepConfigHash, lockstepRefereeState, lockstepRefereeTick, quantiseLockstepAxis, seededWords as tickSeededWords, unwrapTick16 } from './chunk-RQXN5A34.mjs';
|
|
4
|
+
import { woven, weaveParts, weaveNodeValid, weaveNodeLevel, weaveNodeCount, weaveHeadMessage, walkWeave, verifyRoot, verifyChild, validWeaveRoot, unweaveIndex, storeWeaveSource, planWeave, openWeaveSession, openWeaveHead, nodeMatches, leafZone, leafLength, leafFlags, leafDigestAt, leafDigest, leafAt, deliverSchedule, chunkWeaveSource, childDigestAt, buildWeave, WeaveVerifyError, WeaveRefusal, WEAVE_VERSION, WEAVE_NODE_ZONE, WEAVE_NODE_MAGIC, WEAVE_NODE_HEADER_BYTES, WEAVE_MIN_NODE_ENTRIES, WEAVE_MAX_NODE_ENTRIES, WEAVE_MAX_NODE_BYTES, WEAVE_MAX_HEIGHT, WEAVE_LEAF_TWINNED, WEAVE_LEAF_ENTRY_BYTES, WEAVE_LEAF_DECORATED, WEAVE_HEAD_DOMAIN, WEAVE_CHILD_ENTRY_BYTES, WEAVE_BOUNDARY_MASK } from './chunk-ZR5ULMN2.mjs';
|
|
5
|
+
export { AUDIO_RELAY_EXPORT, AUDIO_WORKLET_FILE, AUDIO_WORKLET_GROUP, AUDIO_WORKLET_PATH, ENGINE_AUDIO_UNIT } from './chunk-ZR5ULMN2.mjs';
|
|
6
|
+
export { SurfacePointer } from './chunk-3GXH2NFD.mjs';
|
|
7
|
+
export { DEFAULT_DISK_RESERVE_BYTES, DEFAULT_KEPT_BUDGET_BYTES, DEFAULT_PART_STORE_BUDGET_BYTES, DEFAULT_PART_ZONE, ENGINE_ARENA_BASELINE_BYTES, ENGINE_ARENA_CHUNK_BYTES, ENGINE_ARENA_FEATURE, ENGINE_ARENA_MAX_CEILING_BYTES, ENGINE_COMPATIBILITY_EXPORT_NAMES, ENGINE_CORE_SCRIPTS_UNIT, ENGINE_FEATURES, ENGINE_FEATURE_NAMES, ENGINE_LUAU_UNIT, ENGINE_OPTIONAL_EXPORTS, KEEP_REASONS, LUAU_SCRIPTS_GROUP, LUAU_VM_EXCEPTIONS, LUAU_VM_FILE, LUAU_VM_PATH, LuauVmModules, MemoryPartBackend, PartSession, PartVerifyError, SCRIPTS_CORE_GROUP, SCRIPTS_CORE_PATH, SharedPartStore, engineExportsUsed, engineFeatureExports, engineFeatureMember, exceptionSupport, luauVmModules, luauVmRunsHere, openLuauScripts, unmetEngineExport, unmetEngineFeature } from './chunk-BU6OK542.mjs';
|
|
8
|
+
import './chunk-PRSR4FAV.mjs';
|
|
9
|
+
import './chunk-TM63CYGN.mjs';
|
|
10
|
+
import './chunk-X6CN6KQF.mjs';
|
|
11
|
+
export { LuauScriptError } from './chunk-MN3YETVN.mjs';
|
|
12
|
+
export { UI_CHECKS, UI_EXEMPT_REASONS, UI_INSPECT_HOOK, exemptUi, inspectScene, inspectSceneEntered, inspectSceneSwitch, uiSite } from './chunk-73SGZLAQ.mjs';
|
|
13
|
+
export { Connecting, Connector, GAME_CHANNEL_RELIABLE_BASE, GAME_CHANNEL_SLOTS, InMemoryNetworkMemory, JoinStatus, Locomotion, LocomotionMotion, MAX_STATE_FRAGMENTS, ROOM_STATE_SLOT, RoomClient, RoomPhase, STATE_CHUNK_BYTES, STATE_FRAME_VERSION, STATE_HEADER_BYTES, StorageNetworkMemory, TickStateReplica, Transport, WebSocketDialer, WebTransportDialer, blankReply, currentNetwork, decodeJoinReply, isqrt, locomotionMotion, perAxisUnit, previousSend, resumeRequest, sendsOn, spawn, steer, ticketRequest } from './chunk-M5EXQZYY.mjs';
|
|
14
|
+
export { Lane, Pace } from './chunk-TU5RYTYU.mjs';
|
|
15
|
+
import './chunk-3OY3VYNF.mjs';
|
|
16
|
+
import './chunk-EIB4OWVQ.mjs';
|
|
17
|
+
export { LOCKSTEP_STORAGE_U64_HI, LOCKSTEP_STORAGE_U64_LO, LOCKSTEP_TABLE_ALIGN, LockstepKernel, LockstepTable, COMMAND_AREA_BYTES as TICK_COMMAND_AREA_BYTES, TICK_DEADLINE_MS, GUEST_HEAP_BYTES as TICK_GUEST_HEAP_BYTES, MAX_COMMAND_PAYLOAD_BYTES as TICK_MAX_COMMAND_PAYLOAD_BYTES, MAX_STATE_BYTES as TICK_MAX_STATE_BYTES, TickRoomError, defineTickRoom, defineTickState, lockstepKernel, lockstepKernelHost, lockstepTable, setLockstepKernelHost, tickLayout } from './chunk-PBL6YL5L.mjs';
|
|
18
|
+
import './chunk-GXKI64OT.mjs';
|
|
19
|
+
import './chunk-NHJUGZUR.mjs';
|
|
20
|
+
import './chunk-E65WCTIG.mjs';
|
|
21
|
+
import './chunk-5YFBGGCK.mjs';
|
|
22
|
+
import './chunk-K4UDGE3Z.mjs';
|
|
23
|
+
import './chunk-MOBSBXVE.mjs';
|
|
24
|
+
import './chunk-SMK6JU2F.mjs';
|
|
25
|
+
import { soleSpan, segmentOutput, partKindName, manifestBytes, isManifest, encodePart, encodeManifest, encodeDelta, decodePart, decodeManifest, assembleInto, assemble, applyDelta, SegmentOp, SEGMENT_BYTES, PartKind, PartFormatError, PART_VERSION, PART_MAGIC, PART_HEADER_BYTES, MAX_MANIFEST_PARTS, MAX_ASSET_BYTES, MANIFEST_VERSION, MANIFEST_PART_BYTES, MANIFEST_MAGIC, MANIFEST_HEADER_BYTES, DeltaOp, ProgressiveKind, containerBounds, writePatch, readLayout, progressiveKindName, liftForward, isProgressive, isCoarseKey, headBytes, encodeContainer, decodeProgressive, coarseKeys, checkLayout, UNLIFT_PARAM_BYTES, UNIT_BYTES, TableWriter, SEGMENT_STAGED, SEGMENT_BYTES2, SAMPLE_BYTES, ProgressiveLayout, ProgressiveFormatError, ProgressiveFeed, ProgressiveDecoder, ProgressiveCancelled, PatchOp, PROGRESSIVE_VERSION, PROGRESSIVE_MAGIC, PPM, PATCH_BYTES, MERGE_PARAM_BYTES, MAX_PROGRESSIVE_DECODE_BYTES, MAX_PROGRESSIVE_BYTES, LEVEL_BYTES, Header, HEADER_BYTES, FILL_BYTE_MAX } from './chunk-U6UVWEAK.mjs';
|
|
26
|
+
export { ENGINE_ABI_DIGEST, ENGINE_ABI_VERSION, ENGINE_EXPORT_PROTOTYPES } from './chunk-A33OORT7.mjs';
|
|
27
|
+
import { validateValue, t, select, runContent, rule, dialogueSchema, createGenerate, contentRequest, applyRules, acceptContent, MIN_TIMEOUT_MS, MAX_TIMEOUT_MS, DEFAULT_TIMEOUT_MS, DEFAULT_RETRIES } from './chunk-OKC2B4O3.mjs';
|
|
28
|
+
import { styles, compileStyle, Condition } from './chunk-PPF2BYFL.mjs';
|
|
29
|
+
export { BREAKPOINT_LG, BREAKPOINT_SM, CompiledStyle, Condition, GameUi, GameUiError, SLOT_REFERENCE, STYLE_BLOCK_MAGIC, STYLE_BLOCK_VERSION, KEY_NAMES as STYLE_KEYS, STYLE_PROPERTY_NAMES, STYLE_RECORD_REFERENCED, STYLE_RECORD_SAFE_EDGES, TextMeasurer, UiElement, UiProps, UiStyleCompileError, VariantKind, collectingSink, compileClasses, compileStyle, conditionPriority, encodeStyleRecords, props, readBlock, styles, tailwindStyle, tailwindVocabulary } from './chunk-PPF2BYFL.mjs';
|
|
30
|
+
import { defineVars, tokens, createTheme, mergeThemes, UiSlot } from './chunk-WLMINRC4.mjs';
|
|
31
|
+
export { TOKEN_NAMESPACE, UiSlot, UiTheme, UiVar, createTheme, defineVars, themeTokens, tokens, varId } from './chunk-WLMINRC4.mjs';
|
|
32
|
+
import { DEFAULT_THEME, theme, UiAction } from './chunk-RFVRPYR2.mjs';
|
|
33
|
+
export { DEFAULT_THEME, NO_NODE, PatchWriter, StyleCache, UI_EVENT_BYTES, UI_EVENT_DX_OFFSET, UI_EVENT_DY_OFFSET, UI_EVENT_KIND_OFFSET, UI_EVENT_NODE_OFFSET, UI_EVENT_PHASE_OFFSET, UI_EVENT_POINTER_OFFSET, UI_EVENT_TIME_OFFSET, UI_EVENT_VALUE_OFFSET, UI_EVENT_X_OFFSET, UI_EVENT_Y_OFFSET, UI_EXCLUSION_HEADER_WORDS, UI_HEADER_BYTES, UI_MAGIC, UI_MAX_EXCLUSIONS, UI_RECORD_HEADER_WORDS, UI_SLOT_REFERENCE, UI_STYLE_REFERENCED, UI_STYLE_SAFE_EDGES, UI_TOKENS_REPLACE, UI_VERSION, UiAction, UiAnchor, UiEasing, UiEventKind, UiExclusionShape, UiFlag, UiFocusFlag, UiKind, UiNumberFormat, UiOp, UiProp, UiRole, UiStyleError, UiTextOption, UiTrait, UiTransition, UiUnit, UiVectorData, UiVectorPlay, codePointOffset, eventStride, parseColor, readEvent, textComposition, textEventCapacity, textEventPadding, theme, writeStyle, writeTextEvent } from './chunk-RFVRPYR2.mjs';
|
|
34
|
+
export { BASE_ENGINE_VARIANT, CONTENT_ENGINE_VARIANT, ENGINE_CORE_GL_UNIT, ENGINE_FEATURE_CARGO, ENGINE_VARIANTS, FULL_ENGINE_VARIANT, GATED_ENGINE_FEATURES, GL_CORE_GROUP, GL_CORE_PATH, GL_ENGINE_VARIANTS, PHYSICS_ENGINE_VARIANT, SCRIPTS_ENGINE_VARIANT, SCRIPTS_ENGINE_VARIANTS, SCRIPTS_SHADERS_ENGINE_VARIANT, SCRIPTS_SHADERS_ENGINE_VARIANTS, TEXT_DICTIONARIES_ASSET, TEXT_DICTIONARIES_FILE, THREADED_ENGINE_VARIANT, THREADED_ENGINE_VARIANTS, engineVariantFor, glVariantOf, isGlVariant, isScriptsVariant, isShadersVariant, isThreadedVariant, scriptsShadersVariantOf, scriptsVariantOf, threadedVariantOf, webGpuVariantOf } from './chunk-DS2VU4WW.mjs';
|
|
35
|
+
import './chunk-5YWN6H5Q.mjs';
|
|
36
|
+
export { suggest } from './chunk-F6XRYEM3.mjs';
|
|
37
|
+
export { FrameBufferPool, FrameCode, FrameFault, acknowledges, compareStamps, decodeAck, decodeChannelFrame, decodeCounterAdd, decodeCounterValue, decodeFastRead, decodeFastValue, decodeMoveInput, decodePresenceDelta, decodePresenceTick, decodeRoomInputFrame, dequantiseAxis, dequantiseCellOffset, dequantiseHeight, dequantiseYaw, encodeAck, encodeCounterAdd, encodeCounterValue, encodeMoveInput, finishPresenceTick, frameLength, frameTag, peekFrameCode, quantiseAxis, quantiseCellOffset, quantiseHeight, quantiseYaw, readPresenceDeltaEntry, readPresenceEntry, stampChannelSender, writeChannelHeader, writeFastReadHeader, writeFastValueHeader, writePresenceEntry, writeRoomInputHeader } from './chunk-OQRVEM56.mjs';
|
|
38
|
+
import { FRAME_LIMITS, CTX_LIMITS } from './chunk-SPCRQ6NO.mjs';
|
|
39
|
+
export { CTX_CAPABILITIES, CTX_COMPATIBLE_FINGERPRINTS, CTX_CONTRACT_FINGERPRINT, CTX_CONTRACT_VERSION, CTX_LIMITS, CTX_MIN_SUPPORTED_CONTRACT_VERSION, FRAME_CODES, FRAME_FLAGS, FRAME_LAYOUT, FRAME_LIMITS, FRAME_VERSION, MAX_DATAGRAM_BYTES, QUANTISATION } from './chunk-SPCRQ6NO.mjs';
|
|
40
|
+
import './chunk-V7ZRH3PY.mjs';
|
|
41
|
+
export { BreakDictionaries, breakDictionaries, registerBreakDictionaries } from './chunk-GYLP6UG4.mjs';
|
|
42
|
+
export { FontTable, fontTable, registerFontTable } from './chunk-XJA2NGTI.mjs';
|
|
43
|
+
import './chunk-2IC4H6OV.mjs';
|
|
44
|
+
import './chunk-MOMOZEUM.mjs';
|
|
45
|
+
import './chunk-N4RGGDEL.mjs';
|
|
46
|
+
import './chunk-XJIHN3BY.mjs';
|
|
47
|
+
import { __export } from './chunk-25T4JHEA.mjs';
|
|
48
|
+
|
|
49
|
+
// src/interactives/simulator.ts
|
|
50
|
+
var SimulatorUnsupportedError = class extends Error {
|
|
51
|
+
constructor(member) {
|
|
52
|
+
super(`ctx.${member} is not available in the local simulator yet`), this.name = "SimulatorUnsupportedError", this.member = member;
|
|
53
|
+
}
|
|
54
|
+
}, SIMULATOR_FIXED_STEP_MS = 1e3 / 60, MAX_FRAME_MS = 250, PREPARED_ENGINE = { kind: "prepared" }, UINT32 = 4294967296, DEFAULT_SEED = 2654435769, STATUS_TEXT_FIELD = "text", DEFAULT_PERSONA = {
|
|
55
|
+
age_range: "adult",
|
|
56
|
+
avatar: null,
|
|
57
|
+
display_name: "Local Player",
|
|
58
|
+
handle: "local",
|
|
59
|
+
participant_id: "participant_local"
|
|
60
|
+
}, DEFAULT_LOCALE = {
|
|
61
|
+
currency: "GHS",
|
|
62
|
+
decimal_separator: ".",
|
|
63
|
+
direction: "ltr",
|
|
64
|
+
first_day_of_week: "monday",
|
|
65
|
+
grouping_separator: ",",
|
|
66
|
+
hour_cycle: "h23",
|
|
67
|
+
language: "en-GH",
|
|
68
|
+
measurement: "metric",
|
|
69
|
+
region: "GH",
|
|
70
|
+
time_zone: "Africa/Accra"
|
|
71
|
+
}, Xoshiro128 = class {
|
|
72
|
+
constructor(words) {
|
|
73
|
+
this.a = words[0] >>> 0, this.b = words[1] >>> 0, this.c = words[2] >>> 0, this.d = words[3] >>> 0 || 1;
|
|
74
|
+
}
|
|
75
|
+
next_u32() {
|
|
76
|
+
let result = Math.imul(rotl(Math.imul(this.b, 5), 7), 9) >>> 0, t2 = this.b << 9;
|
|
77
|
+
return this.c ^= this.a, this.d ^= this.b, this.b ^= this.c, this.a ^= this.d, this.c ^= t2, this.d = rotl(this.d, 11), result;
|
|
78
|
+
}
|
|
79
|
+
next_float() {
|
|
80
|
+
return this.next_u32() / (4294967296);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
function rotl(x, k) {
|
|
84
|
+
return (x << k | x >>> 32 - k) >>> 0;
|
|
85
|
+
}
|
|
86
|
+
function splitmix(state) {
|
|
87
|
+
let z = state + 2654435769 | 0;
|
|
88
|
+
return z = Math.imul(z ^ z >>> 16, 2246822507), z = Math.imul(z ^ z >>> 13, 3266489909), (z ^ z >>> 16) >>> 0;
|
|
89
|
+
}
|
|
90
|
+
function copyEntries(entries) {
|
|
91
|
+
let out = /* @__PURE__ */ new Map();
|
|
92
|
+
for (let [k, v] of entries) out.set(k, { value: structuredClone(v.value), revision: v.revision });
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
function createSimulatorCtx(options) {
|
|
96
|
+
let host = options.host, now = options.now ?? (() => Date.now()), persona = options.persona ?? DEFAULT_PERSONA, locale = options.locale ?? DEFAULT_LOCALE, unsupported = /* @__PURE__ */ new Set(), disposers = [], lifecycle = /* @__PURE__ */ new Map(), stores = /* @__PURE__ */ new Map(), uiListeners = /* @__PURE__ */ new Set(), cosmeticState = (options.seed ?? (2654435769)) >>> 0, checkpointCounter = 0, lifecycleState = "visible", status = { text: null, your_turn: false }, completions = [], info = {
|
|
97
|
+
capabilities: [],
|
|
98
|
+
contract_version: 1,
|
|
99
|
+
data_lineage: null,
|
|
100
|
+
features: [],
|
|
101
|
+
instance: "simulator",
|
|
102
|
+
interactive_id: options.interactiveId ?? "itv_simulator",
|
|
103
|
+
kit_version: null,
|
|
104
|
+
launch: { source: "direct", reference: null, selected: null },
|
|
105
|
+
location: "client",
|
|
106
|
+
profile: options.profile,
|
|
107
|
+
revision: "rev_local"
|
|
108
|
+
}, program = {
|
|
109
|
+
ready() {
|
|
110
|
+
},
|
|
111
|
+
...info,
|
|
112
|
+
async set_status(request) {
|
|
113
|
+
if ([...request.text].length > CTX_LIMITS.max_status_line_chars)
|
|
114
|
+
throw { code: "invalid_arguments", field: STATUS_TEXT_FIELD, problem: "too_long" };
|
|
115
|
+
return status = { text: request.text.length === 0 ? null : request.text, your_turn: request.your_turn }, status;
|
|
116
|
+
}
|
|
117
|
+
}, storeById = (id) => {
|
|
118
|
+
let store = stores.get(id);
|
|
119
|
+
if (!store) throw new Error(`unknown store ${id}`);
|
|
120
|
+
return store;
|
|
121
|
+
}, emitStore = (store, event) => {
|
|
122
|
+
for (let l of store.listeners) l(event);
|
|
123
|
+
}, openStore = async (request) => {
|
|
124
|
+
let key = `${request.scope}:${request.name}`, store = stores.get(key);
|
|
125
|
+
store || (store = {
|
|
126
|
+
handle: {
|
|
127
|
+
access: "read_write",
|
|
128
|
+
classification: request.classification,
|
|
129
|
+
migrate_from: null,
|
|
130
|
+
revision: 0,
|
|
131
|
+
schema: request.schema,
|
|
132
|
+
scope: request.scope,
|
|
133
|
+
store_id: key
|
|
134
|
+
},
|
|
135
|
+
entries: /* @__PURE__ */ new Map(),
|
|
136
|
+
checkpoints: /* @__PURE__ */ new Map(),
|
|
137
|
+
listeners: /* @__PURE__ */ new Set()
|
|
138
|
+
}, stores.set(key, store));
|
|
139
|
+
let s9 = store, id = s9.handle.store_id;
|
|
140
|
+
return {
|
|
141
|
+
get handle() {
|
|
142
|
+
return s9.handle;
|
|
143
|
+
},
|
|
144
|
+
async get(req) {
|
|
145
|
+
let hit = storeById(id).entries.get(req.key);
|
|
146
|
+
return { key: req.key, revision: hit ? hit.revision : 0, value: hit ? structuredClone(hit.value) : null };
|
|
147
|
+
},
|
|
148
|
+
async list(req) {
|
|
149
|
+
let prefix = req.prefix ?? "", entries = [];
|
|
150
|
+
for (let [k, v] of s9.entries) k.startsWith(prefix) && entries.push({ key: k, revision: v.revision, value: structuredClone(v.value) });
|
|
151
|
+
entries.sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
|
|
152
|
+
let limit = req.page.limit ?? entries.length;
|
|
153
|
+
return { entries: entries.slice(0, limit), next: null, revision: s9.handle.revision };
|
|
154
|
+
},
|
|
155
|
+
async commit(req) {
|
|
156
|
+
if (req.expected !== void 0 && req.expected !== null && req.expected !== s9.handle.revision)
|
|
157
|
+
throw new Error(`store ${id} is at revision ${s9.handle.revision}, expected ${req.expected}`);
|
|
158
|
+
let revision = s9.handle.revision + 1, keys = [];
|
|
159
|
+
for (let w of req.writes)
|
|
160
|
+
keys.push(w.key), w.op === "put" ? s9.entries.set(w.key, { value: structuredClone(w.value), revision }) : s9.entries.delete(w.key);
|
|
161
|
+
return s9.handle = { ...s9.handle, revision }, emitStore(s9, { kind: "changed", keys, revision, store_id: id }), { revision, store_id: id };
|
|
162
|
+
},
|
|
163
|
+
async checkpoint() {
|
|
164
|
+
checkpointCounter++;
|
|
165
|
+
let checkpoint_id = `checkpoint_${checkpointCounter}`;
|
|
166
|
+
return s9.checkpoints.set(checkpoint_id, { revision: s9.handle.revision, entries: copyEntries(s9.entries) }), { checkpoint_id, created_at: now(), revision: s9.handle.revision, store_id: id };
|
|
167
|
+
},
|
|
168
|
+
async restore(req) {
|
|
169
|
+
let cp = s9.checkpoints.get(req.checkpoint_id);
|
|
170
|
+
if (!cp) throw new Error(`unknown checkpoint ${req.checkpoint_id}`);
|
|
171
|
+
s9.entries = copyEntries(cp.entries);
|
|
172
|
+
let revision = s9.handle.revision + 1;
|
|
173
|
+
return s9.handle = { ...s9.handle, revision }, emitStore(s9, { kind: "restored", checkpoint_id: req.checkpoint_id, revision, store_id: id }), s9.handle;
|
|
174
|
+
},
|
|
175
|
+
async migrate(req) {
|
|
176
|
+
let revision = s9.handle.revision + 1;
|
|
177
|
+
return s9.handle = { ...s9.handle, revision, schema: req.to, migrate_from: s9.handle.schema.version }, emitStore(s9, { kind: "migrated", revision, schema: req.to, store_id: id }), s9.handle;
|
|
178
|
+
},
|
|
179
|
+
on_event(listener) {
|
|
180
|
+
return s9.listeners.add(listener), () => s9.listeners.delete(listener);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
}, loop = createLoop(host, () => record("game.loop")), record = (member) => {
|
|
184
|
+
throw unsupported.add(member), new SimulatorUnsupportedError(member);
|
|
185
|
+
}, fire = (event) => {
|
|
186
|
+
let listeners = lifecycle.get(event);
|
|
187
|
+
if (listeners) for (let l of listeners) l();
|
|
188
|
+
}, base = {
|
|
189
|
+
program,
|
|
190
|
+
session: {
|
|
191
|
+
async complete(request) {
|
|
192
|
+
return completions.push(request), { recorded: false };
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
clock: {
|
|
196
|
+
now,
|
|
197
|
+
async sync() {
|
|
198
|
+
return { display_offset_ms: 0, now: now(), room_tick: null, source: "app_clock" };
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
random: {
|
|
202
|
+
cosmetic() {
|
|
203
|
+
return cosmeticState = splitmix(cosmeticState), cosmeticState / (4294967296);
|
|
204
|
+
},
|
|
205
|
+
async seed(request) {
|
|
206
|
+
let s9 = cosmeticState, words = [0, 0, 0, 0];
|
|
207
|
+
for (let i = 0; i < 4; i++)
|
|
208
|
+
s9 = splitmix(s9 + i), words[i] = s9;
|
|
209
|
+
return { label: request.label, recorded: false, scope: request.scope, words };
|
|
210
|
+
},
|
|
211
|
+
stream(grant) {
|
|
212
|
+
return new Xoshiro128(grant.words);
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
locale: {
|
|
216
|
+
...locale,
|
|
217
|
+
format_number(value, fraction_digits) {
|
|
218
|
+
return new Intl.NumberFormat(locale.language, {
|
|
219
|
+
minimumFractionDigits: fraction_digits,
|
|
220
|
+
maximumFractionDigits: fraction_digits
|
|
221
|
+
}).format(value);
|
|
222
|
+
},
|
|
223
|
+
format_money(amount, currency) {
|
|
224
|
+
return new Intl.NumberFormat(locale.language, { style: "currency", currency: currency ?? locale.currency }).format(Number(amount));
|
|
225
|
+
},
|
|
226
|
+
format_time(unix_ms) {
|
|
227
|
+
return new Intl.DateTimeFormat(locale.language, { timeStyle: "short", timeZone: locale.time_zone }).format(unix_ms);
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
identity: {
|
|
231
|
+
async current() {
|
|
232
|
+
return persona;
|
|
233
|
+
},
|
|
234
|
+
async personas(request) {
|
|
235
|
+
return { personas: request.participants.indexOf(persona.participant_id) >= 0 ? [persona] : [] };
|
|
236
|
+
},
|
|
237
|
+
async profile() {
|
|
238
|
+
return {
|
|
239
|
+
participant_id: persona.participant_id,
|
|
240
|
+
display_name: persona.display_name,
|
|
241
|
+
handle: persona.handle ?? null,
|
|
242
|
+
avatar: persona.avatar ?? null
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
open_store: openStore,
|
|
247
|
+
async share() {
|
|
248
|
+
return host.toast("Share sheet opened"), { decision: "confirmed", link: null };
|
|
249
|
+
},
|
|
250
|
+
ui: {
|
|
251
|
+
render(tree) {
|
|
252
|
+
host.render(tree);
|
|
253
|
+
},
|
|
254
|
+
async present() {
|
|
255
|
+
},
|
|
256
|
+
open_sheet(request) {
|
|
257
|
+
return host.openSheet ? host.openSheet(request) : record("ui.open_sheet");
|
|
258
|
+
},
|
|
259
|
+
async open_handoff() {
|
|
260
|
+
return { status: "cancelled" };
|
|
261
|
+
},
|
|
262
|
+
toast(text) {
|
|
263
|
+
host.toast(text);
|
|
264
|
+
},
|
|
265
|
+
haptic() {
|
|
266
|
+
},
|
|
267
|
+
announce(text) {
|
|
268
|
+
host.toast(text);
|
|
269
|
+
},
|
|
270
|
+
on_event(listener) {
|
|
271
|
+
return uiListeners.add(listener), () => uiListeners.delete(listener);
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
graphics: {
|
|
275
|
+
features: { apis: ["canvas2d"], max_texture_size: 4096, device_tier: "mid" },
|
|
276
|
+
engine() {
|
|
277
|
+
return host.engine ? host.engine() : Promise.resolve(PREPARED_ENGINE);
|
|
278
|
+
},
|
|
279
|
+
acquire_surface(surfaceOptions) {
|
|
280
|
+
return host.acquireSurface ? host.acquireSurface(surfaceOptions) : record("graphics.acquire_surface");
|
|
281
|
+
},
|
|
282
|
+
attach_engine() {
|
|
283
|
+
return record("graphics.attach_engine");
|
|
284
|
+
},
|
|
285
|
+
on_context_lost() {
|
|
286
|
+
return () => {
|
|
287
|
+
};
|
|
288
|
+
},
|
|
289
|
+
on_context_restored() {
|
|
290
|
+
return () => {
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
game: guard("game", { kit_version: "simulator", loop }, unsupported),
|
|
295
|
+
lifecycle: {
|
|
296
|
+
get state() {
|
|
297
|
+
return lifecycleState;
|
|
298
|
+
},
|
|
299
|
+
on(event, listener) {
|
|
300
|
+
let set = lifecycle.get(event);
|
|
301
|
+
return set || (set = /* @__PURE__ */ new Set(), lifecycle.set(event, set)), set.add(listener), () => set.delete(listener);
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
on_dispose(callback) {
|
|
305
|
+
disposers.push(callback);
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
return {
|
|
309
|
+
ctx: guard("", base, unsupported),
|
|
310
|
+
unsupported,
|
|
311
|
+
get status() {
|
|
312
|
+
return status;
|
|
313
|
+
},
|
|
314
|
+
completions,
|
|
315
|
+
emit(event) {
|
|
316
|
+
event === "hidden" ? lifecycleState = "hidden" : event === "visible" || event === "resume" ? lifecycleState = "visible" : event === "suspend" && (lifecycleState = "suspended"), fire(event);
|
|
317
|
+
},
|
|
318
|
+
dispatch(event) {
|
|
319
|
+
if (lifecycleState !== "disposed")
|
|
320
|
+
for (let listener of uiListeners) listener(event);
|
|
321
|
+
},
|
|
322
|
+
dispose() {
|
|
323
|
+
if (lifecycleState !== "disposed") {
|
|
324
|
+
loop.stop(), lifecycleState = "disposed", fire("dispose");
|
|
325
|
+
for (let i = disposers.length - 1; i >= 0; i--) disposers[i]();
|
|
326
|
+
disposers.length = 0, uiListeners.clear();
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
function guard(prefix, target, unsupported) {
|
|
332
|
+
return new Proxy(target, {
|
|
333
|
+
get(obj, prop, receiver) {
|
|
334
|
+
if (typeof prop == "symbol" || prop in obj) return Reflect.get(obj, prop, receiver);
|
|
335
|
+
if (prop === "then") return;
|
|
336
|
+
let member = prefix === "" ? prop : `${prefix}.${prop}`;
|
|
337
|
+
throw unsupported.add(member), new SimulatorUnsupportedError(member);
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
function createLoop(host, missing) {
|
|
342
|
+
let callbacks = null, handle = -1, last = -1, accumulator = 0, tick = 0, paused = false, step = SIMULATOR_FIXED_STEP_MS, frame = (time) => {
|
|
343
|
+
if (callbacks === null || !host.requestFrame) return;
|
|
344
|
+
if (handle = host.requestFrame(frame), paused) {
|
|
345
|
+
last = time;
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
let elapsed = last < 0 ? step : time - last;
|
|
349
|
+
for (last = time, accumulator += elapsed > (250) ? (250) : elapsed; accumulator >= step; )
|
|
350
|
+
callbacks.update(step, tick), tick++, accumulator -= step;
|
|
351
|
+
callbacks.render(accumulator / step);
|
|
352
|
+
};
|
|
353
|
+
return {
|
|
354
|
+
fixed_step_ms: step,
|
|
355
|
+
get tick() {
|
|
356
|
+
return tick;
|
|
357
|
+
},
|
|
358
|
+
start(next) {
|
|
359
|
+
host.requestFrame || missing(), callbacks = next, paused = false, last = -1, handle = host.requestFrame(frame);
|
|
360
|
+
},
|
|
361
|
+
pause() {
|
|
362
|
+
paused = true;
|
|
363
|
+
},
|
|
364
|
+
resume() {
|
|
365
|
+
paused = false;
|
|
366
|
+
},
|
|
367
|
+
stop() {
|
|
368
|
+
callbacks = null, handle >= 0 && host.cancelFrame && host.cancelFrame(handle), handle = -1;
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// src/interactives/game-ui/widgets/theme.ts
|
|
374
|
+
var KIT_NAMESPACE = "kit", UI_FONT_SET = ["sans", "rounded", "condensed", "serif", "mono", "pixel"], UI_DEFAULT_FONT = 0, UI_FONT_ROLES = ["body", "display", "mono"], ROLE_FAMILIES = { body: "kit.body", display: "kit.display", mono: "kit.mono" }, ROLE_INDEX = { body: 0, display: 1, mono: 2 }, KIT_WEIGHTS = [400, 600, 700, 800], DEFAULT_WEIGHT = 400, DEFAULT_METRICS = {
|
|
375
|
+
radius: DEFAULT_THEME.radius,
|
|
376
|
+
radiusSmall: 8,
|
|
377
|
+
padding: DEFAULT_THEME.padding,
|
|
378
|
+
gap: DEFAULT_THEME.gap,
|
|
379
|
+
gapSmall: 4,
|
|
380
|
+
small: DEFAULT_THEME.small,
|
|
381
|
+
body: DEFAULT_THEME.body,
|
|
382
|
+
title: DEFAULT_THEME.title,
|
|
383
|
+
display: 30,
|
|
384
|
+
borderWidth: 1,
|
|
385
|
+
focusWidth: 2,
|
|
386
|
+
pressScale: DEFAULT_THEME.press_scale
|
|
387
|
+
}, DEFAULT_EXTRAS = {
|
|
388
|
+
focus: "#ffffffff",
|
|
389
|
+
scrim: "#05070cb3",
|
|
390
|
+
highlight: "#ffffff1f",
|
|
391
|
+
shadow: "#0000008c",
|
|
392
|
+
onDanger: "#ffffffff",
|
|
393
|
+
silver: "#c7ccd6ff",
|
|
394
|
+
bronze: "#cd7f32ff"
|
|
395
|
+
}, kitVars = defineVars(KIT_NAMESPACE, { ...DEFAULT_METRICS, ...DEFAULT_EXTRAS }), AI_MARK_NAMESPACE = "ai_mark", DEFAULT_AI_MARK = { fill: "#ffffff1f", text: "#a1a1aaff", fontSize: 10, radius: 4, paddingInline: 4 }, aiMarkVars = defineVars(AI_MARK_NAMESPACE, { ...DEFAULT_AI_MARK });
|
|
396
|
+
function aiMarkTheme(overrides) {
|
|
397
|
+
return createTheme(aiMarkVars, overrides);
|
|
398
|
+
}
|
|
399
|
+
function themePack(definition) {
|
|
400
|
+
let metrics = { ...DEFAULT_METRICS, ...definition.metrics }, c = definition.colors, game = theme({
|
|
401
|
+
surface: c.surface,
|
|
402
|
+
raised: c.raised,
|
|
403
|
+
border: c.border,
|
|
404
|
+
accent: c.accent,
|
|
405
|
+
on_accent: c.onAccent,
|
|
406
|
+
text: c.text,
|
|
407
|
+
muted: c.muted,
|
|
408
|
+
track: c.track,
|
|
409
|
+
danger: c.danger,
|
|
410
|
+
success: c.success,
|
|
411
|
+
gold: c.gold,
|
|
412
|
+
radius: metrics.radius,
|
|
413
|
+
padding: metrics.padding,
|
|
414
|
+
gap: metrics.gap,
|
|
415
|
+
small: metrics.small,
|
|
416
|
+
body: metrics.body,
|
|
417
|
+
title: metrics.title,
|
|
418
|
+
press_scale: metrics.pressScale,
|
|
419
|
+
motion: definition.motion ?? DEFAULT_THEME.motion
|
|
420
|
+
}), palette = createTheme(tokens, {
|
|
421
|
+
surface: c.surface,
|
|
422
|
+
raised: c.raised,
|
|
423
|
+
border: c.border,
|
|
424
|
+
accent: c.accent,
|
|
425
|
+
onAccent: c.onAccent,
|
|
426
|
+
text: c.text,
|
|
427
|
+
muted: c.muted,
|
|
428
|
+
track: c.track,
|
|
429
|
+
danger: c.danger,
|
|
430
|
+
success: c.success,
|
|
431
|
+
gold: c.gold
|
|
432
|
+
}), kit = createTheme(kitVars, {
|
|
433
|
+
...metrics,
|
|
434
|
+
focus: c.focus,
|
|
435
|
+
scrim: c.scrim,
|
|
436
|
+
highlight: c.highlight,
|
|
437
|
+
shadow: c.shadow,
|
|
438
|
+
onDanger: c.onDanger,
|
|
439
|
+
silver: c.silver,
|
|
440
|
+
bronze: c.bronze
|
|
441
|
+
}), mark = aiMarkTheme({ fill: c.track, text: c.muted, ...definition.aiMark });
|
|
442
|
+
return { name: definition.name, colors: c, metrics, fonts: definition.fonts, game, theme: mergeThemes([palette, kit, mark]) };
|
|
443
|
+
}
|
|
444
|
+
var NEON_ARCADE = themePack({
|
|
445
|
+
name: "Neon arcade",
|
|
446
|
+
colors: {
|
|
447
|
+
surface: "#0b0420eb",
|
|
448
|
+
raised: "#1d0b3dff",
|
|
449
|
+
border: "#ff2bd666",
|
|
450
|
+
accent: "#ff2bd6ff",
|
|
451
|
+
onAccent: "#12021fff",
|
|
452
|
+
text: "#f4f0ffff",
|
|
453
|
+
muted: "#a493d6ff",
|
|
454
|
+
track: "#ffffff1f",
|
|
455
|
+
danger: "#ff3860ff",
|
|
456
|
+
success: "#22f5a0ff",
|
|
457
|
+
gold: "#fff03aff",
|
|
458
|
+
focus: "#2bf3ffff",
|
|
459
|
+
scrim: "#05010fcc",
|
|
460
|
+
highlight: "#2bf3ff26",
|
|
461
|
+
shadow: "#ff2bd659",
|
|
462
|
+
onDanger: "#ffffffff",
|
|
463
|
+
silver: "#b8c4ffff",
|
|
464
|
+
bronze: "#ff9d5cff"
|
|
465
|
+
},
|
|
466
|
+
metrics: { radius: 4, radiusSmall: 2, borderWidth: 2, focusWidth: 3, pressScale: 0.92, display: 34 },
|
|
467
|
+
fonts: { body: "sans", display: "pixel", mono: "mono" },
|
|
468
|
+
motion: 0.1
|
|
469
|
+
}), COZY_PASTEL = themePack({
|
|
470
|
+
name: "Cozy pastel",
|
|
471
|
+
colors: {
|
|
472
|
+
surface: "#fff7efef",
|
|
473
|
+
raised: "#ffe9dcff",
|
|
474
|
+
border: "#e8cbb866",
|
|
475
|
+
accent: "#f49cb8ff",
|
|
476
|
+
onAccent: "#3b1d2aff",
|
|
477
|
+
text: "#4a3a40ff",
|
|
478
|
+
muted: "#9a8590ff",
|
|
479
|
+
track: "#e9d8d2ff",
|
|
480
|
+
danger: "#ef7f7fff",
|
|
481
|
+
success: "#7fcfa6ff",
|
|
482
|
+
gold: "#f6c560ff",
|
|
483
|
+
focus: "#8fb8ffff",
|
|
484
|
+
scrim: "#5a4a5266",
|
|
485
|
+
highlight: "#8fb8ff2e",
|
|
486
|
+
shadow: "#9a6f8040",
|
|
487
|
+
onDanger: "#ffffffff",
|
|
488
|
+
silver: "#b9bfd0ff",
|
|
489
|
+
bronze: "#d9a07aff"
|
|
490
|
+
},
|
|
491
|
+
metrics: { radius: 20, radiusSmall: 14, padding: 16, gap: 10, pressScale: 0.96 },
|
|
492
|
+
fonts: { body: "rounded", display: "rounded", mono: "mono" },
|
|
493
|
+
motion: 0.22
|
|
494
|
+
}), SPORTS_BROADCAST = themePack({
|
|
495
|
+
name: "Sports broadcast",
|
|
496
|
+
colors: {
|
|
497
|
+
surface: "#0d1b2af2",
|
|
498
|
+
raised: "#16324fff",
|
|
499
|
+
border: "#ffffff33",
|
|
500
|
+
accent: "#e4002bff",
|
|
501
|
+
onAccent: "#ffffffff",
|
|
502
|
+
text: "#ffffffff",
|
|
503
|
+
muted: "#9fb3c8ff",
|
|
504
|
+
track: "#ffffff26",
|
|
505
|
+
danger: "#ff5a36ff",
|
|
506
|
+
success: "#00c389ff",
|
|
507
|
+
gold: "#ffcd00ff",
|
|
508
|
+
focus: "#ffcd00ff",
|
|
509
|
+
scrim: "#020a12cc",
|
|
510
|
+
highlight: "#ffffff1a",
|
|
511
|
+
shadow: "#00000080",
|
|
512
|
+
onDanger: "#ffffffff",
|
|
513
|
+
silver: "#c0c8d2ff",
|
|
514
|
+
bronze: "#c9844aff"
|
|
515
|
+
},
|
|
516
|
+
metrics: { radius: 2, radiusSmall: 2, padding: 10, gap: 6, gapSmall: 3, body: 15, title: 20, display: 32, pressScale: 0.97 },
|
|
517
|
+
fonts: { body: "sans", display: "condensed", mono: "condensed" },
|
|
518
|
+
motion: 0.12
|
|
519
|
+
}), FANTASY_PARCHMENT = themePack({
|
|
520
|
+
name: "Fantasy parchment",
|
|
521
|
+
colors: {
|
|
522
|
+
surface: "#f1e2c2f2",
|
|
523
|
+
raised: "#e5cf9fff",
|
|
524
|
+
border: "#7a5a2e99",
|
|
525
|
+
accent: "#8b2a1fff",
|
|
526
|
+
onAccent: "#fbf1dcff",
|
|
527
|
+
text: "#3a2614ff",
|
|
528
|
+
muted: "#7a6448ff",
|
|
529
|
+
track: "#c9b083ff",
|
|
530
|
+
danger: "#a3241bff",
|
|
531
|
+
success: "#4f7a2aff",
|
|
532
|
+
gold: "#b8860bff",
|
|
533
|
+
focus: "#2f5d8aff",
|
|
534
|
+
scrim: "#1a0f0599",
|
|
535
|
+
highlight: "#2f5d8a26",
|
|
536
|
+
shadow: "#3a261459",
|
|
537
|
+
onDanger: "#fbf1dcff",
|
|
538
|
+
silver: "#8d8f94ff",
|
|
539
|
+
bronze: "#8c5a2bff"
|
|
540
|
+
},
|
|
541
|
+
metrics: { radius: 6, radiusSmall: 4, padding: 14, borderWidth: 2, focusWidth: 2, title: 21, display: 32 },
|
|
542
|
+
fonts: { body: "serif", display: "serif", mono: "mono" },
|
|
543
|
+
motion: 0.2
|
|
544
|
+
}), THEME_PACKS = [NEON_ARCADE, COZY_PASTEL, SPORTS_BROADCAST, FANTASY_PARCHMENT], books = /* @__PURE__ */ new WeakMap();
|
|
545
|
+
function book(ui) {
|
|
546
|
+
let found = books.get(ui);
|
|
547
|
+
return found === void 0 && (found = { fonts: /* @__PURE__ */ new Map(), pack: null, roles: [] }, books.set(ui, found)), found;
|
|
548
|
+
}
|
|
549
|
+
function kitFamily(ui, role) {
|
|
550
|
+
return ui.family(ROLE_FAMILIES[role]);
|
|
551
|
+
}
|
|
552
|
+
function fontStyle(ui, role) {
|
|
553
|
+
let roles = book(ui).roles, index = ROLE_INDEX[role], style = roles[index];
|
|
554
|
+
if (style === void 0) {
|
|
555
|
+
let fonts = book(ui);
|
|
556
|
+
(fonts.pack === null || !fonts.fonts.has(fonts.pack.fonts[role])) && ui.registerFont(ROLE_FAMILIES[role], (0), (400)), style = styles({ font: { fontFamily: kitFamily(ui, role) } }).font, roles[index] = style;
|
|
557
|
+
}
|
|
558
|
+
return style;
|
|
559
|
+
}
|
|
560
|
+
function nearest(entry, weight) {
|
|
561
|
+
let best = -1, distance = 1 / 0;
|
|
562
|
+
for (let i = 0; i < entry.weights.length; i++) {
|
|
563
|
+
let gap = Math.abs(entry.weights[i] - weight);
|
|
564
|
+
gap < distance && (distance = gap, best = entry.fonts[i]);
|
|
565
|
+
}
|
|
566
|
+
return best;
|
|
567
|
+
}
|
|
568
|
+
function bind(ui, fonts, pack) {
|
|
569
|
+
for (let r = 0; r < UI_FONT_ROLES.length; r++) {
|
|
570
|
+
let role = UI_FONT_ROLES[r], entry = fonts.fonts.get(pack.fonts[role]);
|
|
571
|
+
if (entry !== void 0)
|
|
572
|
+
for (let w = 0; w < KIT_WEIGHTS.length; w++) ui.registerFont(ROLE_FAMILIES[role], nearest(entry, KIT_WEIGHTS[w]), KIT_WEIGHTS[w]);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
function registerUiFont(ui, name, font, weight = (400)) {
|
|
576
|
+
let fonts = book(ui), entry = fonts.fonts.get(name);
|
|
577
|
+
entry === void 0 && (entry = { weights: [], fonts: [] }, fonts.fonts.set(name, entry));
|
|
578
|
+
let at = entry.weights.indexOf(weight);
|
|
579
|
+
at >= 0 ? entry.fonts[at] = font : (entry.weights.push(weight), entry.fonts.push(font)), ui.registerFont(name, font, weight), fonts.pack !== null && bind(ui, fonts, fonts.pack);
|
|
580
|
+
}
|
|
581
|
+
function applyThemePack(ui, pack) {
|
|
582
|
+
let fonts = book(ui);
|
|
583
|
+
ui.theme(pack.theme), fonts.pack !== pack && (fonts.pack = pack, bind(ui, fonts, pack));
|
|
584
|
+
}
|
|
585
|
+
function currentThemePack(ui) {
|
|
586
|
+
return books.get(ui)?.pack ?? null;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// src/interactives/game-ui/widgets/sheet.ts
|
|
590
|
+
var TRANSPARENT = "#00000000", TAP_TARGET = 44, PRESS_SECONDS = 0.12, FADE_SECONDS = 0.18, HALF = 0.5, PERCENT = 100, BOLD = 700, HEAVY = 800, sheet = styles({
|
|
591
|
+
text: { fontSize: kitVars.body, textColor: tokens.text, pointerEvents: "none" },
|
|
592
|
+
small: { fontSize: kitVars.small, textColor: tokens.muted, pointerEvents: "none" },
|
|
593
|
+
title: { fontSize: kitVars.title, fontWeight: (700), textColor: tokens.text, pointerEvents: "none" },
|
|
594
|
+
display: { fontSize: kitVars.display, fontWeight: (800), textColor: tokens.text, pointerEvents: "none" },
|
|
595
|
+
strong: { fontWeight: (700) },
|
|
596
|
+
muted: { textColor: tokens.muted },
|
|
597
|
+
center: { textAlign: "center" },
|
|
598
|
+
wrap: { textWrap: true, alignSelf: "stretch" },
|
|
599
|
+
hidden: { hidden: true },
|
|
600
|
+
shown: { hidden: false },
|
|
601
|
+
layer: { width: "100%", height: "100%", pointerEvents: "none" },
|
|
602
|
+
panel: {
|
|
603
|
+
padding: kitVars.padding,
|
|
604
|
+
gap: kitVars.gap,
|
|
605
|
+
fill: tokens.surface,
|
|
606
|
+
radius: kitVars.radius,
|
|
607
|
+
borderWidth: kitVars.borderWidth,
|
|
608
|
+
borderColor: tokens.border
|
|
609
|
+
},
|
|
610
|
+
focusRing: {
|
|
611
|
+
borderWidth: kitVars.focusWidth,
|
|
612
|
+
borderColor: { default: TRANSPARENT, ":focus": kitVars.focus }
|
|
613
|
+
},
|
|
614
|
+
pressable: {
|
|
615
|
+
scale: { default: 1, ":pressed": kitVars.pressScale },
|
|
616
|
+
opacity: { default: 1, ":disabled": 0.5 }
|
|
617
|
+
}
|
|
618
|
+
}), PERCENT_TEXT = Array.from({ length: (100) + 1 }, (_, i) => `${i}%`), INTEGER = { format: "integer", separator: "," }, PLAIN = { format: "integer", separator: "" }, TIMER = { format: "timer" };
|
|
619
|
+
function label(ui, value, role, a, b, c) {
|
|
620
|
+
return ui.text(value, ui.props(fontStyle(ui, role), a, b, c));
|
|
621
|
+
}
|
|
622
|
+
function clamp(value, low, high) {
|
|
623
|
+
return value < low ? low : value > high ? high : value;
|
|
624
|
+
}
|
|
625
|
+
var SLOTS = new Float64Array(4);
|
|
626
|
+
function slotWords(template) {
|
|
627
|
+
return compileStyle(template);
|
|
628
|
+
}
|
|
629
|
+
function slot(index, percent = false) {
|
|
630
|
+
return new UiSlot(index, percent);
|
|
631
|
+
}
|
|
632
|
+
var A11y = class {
|
|
633
|
+
constructor(options) {
|
|
634
|
+
this.first = true;
|
|
635
|
+
this.actions = options.actions, this.options = { ...options, actions: void 0 };
|
|
636
|
+
}
|
|
637
|
+
apply(element) {
|
|
638
|
+
if (this.first) {
|
|
639
|
+
this.first = false, this.options.actions = this.actions, element.accessibility(this.options), this.options.actions = void 0;
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
element.accessibility(this.options);
|
|
643
|
+
}
|
|
644
|
+
}, StableList = class {
|
|
645
|
+
constructor() {
|
|
646
|
+
this.items = [];
|
|
647
|
+
this.count = 0;
|
|
648
|
+
}
|
|
649
|
+
get size() {
|
|
650
|
+
return this.count;
|
|
651
|
+
}
|
|
652
|
+
at(index) {
|
|
653
|
+
return this.items[index];
|
|
654
|
+
}
|
|
655
|
+
push(item) {
|
|
656
|
+
this.count < this.items.length ? this.items[this.count] = item : this.items.push(item), this.count++;
|
|
657
|
+
}
|
|
658
|
+
indexOf(item) {
|
|
659
|
+
for (let i = 0; i < this.count; i++) if (this.items[i] === item) return i;
|
|
660
|
+
return -1;
|
|
661
|
+
}
|
|
662
|
+
removeAt(index) {
|
|
663
|
+
for (let i = index; i + 1 < this.count; i++) this.items[i] = this.items[i + 1];
|
|
664
|
+
this.count--;
|
|
665
|
+
}
|
|
666
|
+
};
|
|
667
|
+
function removeAt(list2, index) {
|
|
668
|
+
for (let i = index; i + 1 < list2.length; i++) list2[i] = list2[i + 1];
|
|
669
|
+
list2.length = list2.length - 1;
|
|
670
|
+
}
|
|
671
|
+
var Rng = class {
|
|
672
|
+
constructor(seed) {
|
|
673
|
+
this.state = new Int32Array(1);
|
|
674
|
+
this.state[0] = (seed | 0) === 0 ? 2654435769 : seed | 0;
|
|
675
|
+
}
|
|
676
|
+
next() {
|
|
677
|
+
let x = this.state[0];
|
|
678
|
+
return x ^= x << 13, x ^= x >>> 17, x ^= x << 5, this.state[0] = x, (x >>> 0) / 4294967296;
|
|
679
|
+
}
|
|
680
|
+
range(low, high) {
|
|
681
|
+
return low + (high - low) * this.next();
|
|
682
|
+
}
|
|
683
|
+
};
|
|
684
|
+
|
|
685
|
+
// src/interactives/game-ui/widgets/ai-mark.ts
|
|
686
|
+
var AI_MARK_SOURCES = ["generated", "cached", "replicated"], AI_MARK_TEXT = "AI", AI_MARK_LABEL = "AI generated";
|
|
687
|
+
function isAiGenerated(source) {
|
|
688
|
+
return source === "generated" || source === "cached" || source === "replicated";
|
|
689
|
+
}
|
|
690
|
+
var s = styles({
|
|
691
|
+
mark: { fill: aiMarkVars.fill, radius: aiMarkVars.radius, paddingInline: aiMarkVars.paddingInline, alignSelf: "center", shrink: 0, pointerEvents: "none" },
|
|
692
|
+
markText: { fontSize: aiMarkVars.fontSize, fontWeight: (800), textColor: aiMarkVars.text, pointerEvents: "none" },
|
|
693
|
+
row: { direction: "row", alignItems: "center", gap: kitVars.gapSmall },
|
|
694
|
+
text: { fontSize: kitVars.body, textColor: tokens.text, shrink: 1, pointerEvents: "none" }
|
|
695
|
+
}), AiMark = class {
|
|
696
|
+
constructor(ui, options = {}) {
|
|
697
|
+
this.ui = ui;
|
|
698
|
+
this.on = false;
|
|
699
|
+
this.states = [ui.props(s.mark, options.style, sheet.hidden), ui.props(s.mark, options.style)], this.root = ui.box(this.states[0]), this.text = label(ui, options.text ?? AI_MARK_TEXT, "body", s.markText, options.textStyle), this.root.append(this.text), this.root.accessibility({ hidden: true });
|
|
700
|
+
}
|
|
701
|
+
get shown() {
|
|
702
|
+
return this.on;
|
|
703
|
+
}
|
|
704
|
+
show(source) {
|
|
705
|
+
let on = isAiGenerated(source);
|
|
706
|
+
return on === this.on || (this.on = on, this.root.style(this.states[on ? 1 : 0])), on;
|
|
707
|
+
}
|
|
708
|
+
};
|
|
709
|
+
function aiMark(ui, options = {}) {
|
|
710
|
+
return new AiMark(ui, options);
|
|
711
|
+
}
|
|
712
|
+
function aiLabel(text, marked) {
|
|
713
|
+
return marked ? `${text}, ${AI_MARK_LABEL}` : text;
|
|
714
|
+
}
|
|
715
|
+
var GeneratedText = class {
|
|
716
|
+
constructor(ui, options = {}) {
|
|
717
|
+
this.ui = ui;
|
|
718
|
+
this.current = "";
|
|
719
|
+
this.source = null;
|
|
720
|
+
this.shown = false;
|
|
721
|
+
this.a11y = new A11y({ role: "text", label: "" });
|
|
722
|
+
this.root = ui.box(ui.props(s.row, options.style)), this.text = label(ui, "", options.role ?? "body", s.text, options.wrap === true && sheet.wrap, options.textStyle), this.mark = new AiMark(ui, options.mark), this.root.append(this.text).append(this.mark.root), this.set(options.text ?? "", options.source ?? null);
|
|
723
|
+
}
|
|
724
|
+
get value() {
|
|
725
|
+
return this.current;
|
|
726
|
+
}
|
|
727
|
+
get marked() {
|
|
728
|
+
return this.mark.shown;
|
|
729
|
+
}
|
|
730
|
+
set(text, source = null) {
|
|
731
|
+
this.shown && text === this.current && isAiGenerated(source) === isAiGenerated(this.source) || (this.shown = true, this.current = text, this.source = source, this.text.text(text), this.a11y.options.label = aiLabel(text, this.mark.show(source)), this.a11y.apply(this.root));
|
|
732
|
+
}
|
|
733
|
+
show(result) {
|
|
734
|
+
this.set(result.value, result.source);
|
|
735
|
+
}
|
|
736
|
+
};
|
|
737
|
+
function generatedText(ui, options = {}) {
|
|
738
|
+
return new GeneratedText(ui, options);
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// src/interactives/game-ui/widgets/collections.ts
|
|
742
|
+
var CELL = 64, CELL_GAP = 8, GRID_PADDING = 8, ICON_RATIO = 0.7, GHOST_SCALE = 1.08, GHOST_Z = 20, EMPTY = -1, ROW_HEIGHT = 44, LIST_HEIGHT = 320, POOL_SLACK = 2, RANK_WIDTH = 44, SCORE_WIDTH = 96, NO_INDEX = -1, TRAVEL_SHIFT = 4, TRAVEL_SCALE = 1 << (4), MEDALS = 3, s2 = styles({
|
|
743
|
+
grid: { padding: (8), gap: (8), fill: tokens.surface, radius: kitVars.radius, position: "relative", borderWidth: kitVars.focusWidth, borderColor: { default: tokens.border, ":focus": kitVars.focus } },
|
|
744
|
+
gridRow: { direction: "row", gap: (8) },
|
|
745
|
+
cell: {
|
|
746
|
+
alignItems: "center",
|
|
747
|
+
justify: "center",
|
|
748
|
+
radius: kitVars.radiusSmall,
|
|
749
|
+
fill: tokens.raised,
|
|
750
|
+
borderWidth: 2,
|
|
751
|
+
borderColor: TRANSPARENT,
|
|
752
|
+
position: "relative",
|
|
753
|
+
scale: { default: 1, ":pressed": kitVars.pressScale }
|
|
754
|
+
},
|
|
755
|
+
cellCursor: { borderColor: kitVars.focus },
|
|
756
|
+
cellHover: { borderColor: tokens.accent, fill: kitVars.highlight },
|
|
757
|
+
cellSource: { opacity: 0.35 },
|
|
758
|
+
icon: { pointerEvents: "none" },
|
|
759
|
+
iconEmpty: { hidden: true },
|
|
760
|
+
count: { position: "absolute", right: 4, bottom: 2, fontSize: kitVars.small, fontWeight: 800, textColor: tokens.text, pointerEvents: "none" },
|
|
761
|
+
ghost: { position: "absolute", alignItems: "center", justify: "center", pointerEvents: "none", zIndex: (20), scale: (1.08), opacity: 0.92, radius: kitVars.radiusSmall, fill: kitVars.highlight, hidden: true },
|
|
762
|
+
ghostShown: { hidden: false },
|
|
763
|
+
ghostAt: { left: 0, top: 0 },
|
|
764
|
+
list: { scrollAxes: "y", clip: true, radius: kitVars.radius, fill: tokens.surface, borderWidth: kitVars.focusWidth, borderColor: { default: tokens.border, ":focus": kitVars.focus } },
|
|
765
|
+
extent: { height: 0 },
|
|
766
|
+
content: { position: "relative", width: "100%" },
|
|
767
|
+
slot: { position: "absolute", left: 0, right: 0, direction: "row", alignItems: "center" },
|
|
768
|
+
slotHidden: { hidden: true },
|
|
769
|
+
slotCursor: { fill: kitVars.highlight },
|
|
770
|
+
slotAt: { top: 0, height: 0 },
|
|
771
|
+
rowMe: { fill: tokens.accent },
|
|
772
|
+
leader: { direction: "row", alignItems: "center", gap: kitVars.gap, padding: [0, kitVars.padding, 0, kitVars.padding], width: "100%", height: "100%" },
|
|
773
|
+
rank: { width: (44), fontSize: kitVars.body, fontWeight: 800, textColor: tokens.muted, textAlign: "center", pointerEvents: "none" },
|
|
774
|
+
name: { grow: 1, shrink: 1, fontSize: kitVars.body, textColor: tokens.text, pointerEvents: "none" },
|
|
775
|
+
score: { width: (96), fontSize: kitVars.body, fontWeight: 700, textColor: tokens.gold, textAlign: "right", pointerEvents: "none" },
|
|
776
|
+
gold: { textColor: tokens.gold },
|
|
777
|
+
silver: { textColor: kitVars.silver },
|
|
778
|
+
bronze: { textColor: kitVars.bronze },
|
|
779
|
+
onAccent: { textColor: tokens.onAccent }
|
|
780
|
+
}, {
|
|
781
|
+
ghostAt: slotWords({ left: slot(0), top: slot(1) }),
|
|
782
|
+
extent: slotWords({ height: slot(0) }),
|
|
783
|
+
slotAt: slotWords({ top: slot(0), height: slot(1) })
|
|
784
|
+
}), InventoryGrid = class {
|
|
785
|
+
constructor(ui, options) {
|
|
786
|
+
this.ui = ui;
|
|
787
|
+
this.cellStates = [];
|
|
788
|
+
this.cellA11y = [];
|
|
789
|
+
this.cursorAt = 0;
|
|
790
|
+
this.focused = false;
|
|
791
|
+
this.source = (-1);
|
|
792
|
+
this.hover = (-1);
|
|
793
|
+
this.travel = new Int32Array(2);
|
|
794
|
+
this.held = false;
|
|
795
|
+
this.columns = options.columns, this.rows = options.rows, this.size = options.cell ?? (64);
|
|
796
|
+
let gap = options.gap ?? (8);
|
|
797
|
+
this.pitch = this.size + gap, this.natural = options.natural ?? [this.size, this.size], this.onMove = options.onMove ?? null, this.onSelect = options.onSelect ?? null;
|
|
798
|
+
let count2 = this.columns * this.rows;
|
|
799
|
+
this.assets = new Int32Array(count2).fill((-1)), this.amounts = new Int32Array(count2), this.cellColumn = new Int32Array(count2), this.cellRow = new Int32Array(count2);
|
|
800
|
+
for (let i = 0; i < count2; i++)
|
|
801
|
+
this.cellColumn[i] = i % this.columns, this.cellRow[i] = Math.floor(i / this.columns);
|
|
802
|
+
this.names = new Array(count2).fill("Empty");
|
|
803
|
+
let sized = { width: this.size, height: this.size }, iconSize = { width: this.size * (0.7), height: this.size * (0.7) };
|
|
804
|
+
for (let state = 0; state < 8; state++) this.cellStates.push(ui.props(s2.cell, sized, (state & 1) !== 0 && s2.cellCursor, (state & 2) !== 0 && s2.cellHover, (state & 4) !== 0 && s2.cellSource));
|
|
805
|
+
this.iconStates = [ui.props(s2.icon, iconSize), ui.props(s2.icon, iconSize, s2.iconEmpty)], this.ghostStates = [ui.props(s2.ghost, sized), ui.props(s2.ghost, sized, s2.ghostShown)];
|
|
806
|
+
let mono = fontStyle(ui, "mono");
|
|
807
|
+
this.countStates = [ui.props(mono, s2.count), ui.props(mono, s2.count, sheet.hidden)], this.root = ui.box(ui.props(s2.grid, { gap }, options.style));
|
|
808
|
+
let cells = [], icons = [], counts = [];
|
|
809
|
+
for (let r = 0; r < this.rows; r++) {
|
|
810
|
+
let row = ui.box(ui.props(s2.gridRow, { gap }));
|
|
811
|
+
for (let c = 0; c < this.columns; c++) {
|
|
812
|
+
let index = r * this.columns + c, cell = ui.box(this.cellStates[0]);
|
|
813
|
+
cell.transition(["scale_x", "scale_y", "opacity"], { duration: (0.12), easing: "back_out" });
|
|
814
|
+
let icon = ui.image(0, this.natural, this.iconStates[1]), amount = ui.text("", this.countStates[1]);
|
|
815
|
+
cell.append(icon).append(amount), cell.on("tap", () => this.select(index)), cell.on("drag_start", () => this.begin(index)), cell.on("drag_move", (event) => this.drag(event)), cell.on("drag_end", () => this.drop());
|
|
816
|
+
let a11y = new A11y({ role: "button", label: "Empty", actions: ["activate"] });
|
|
817
|
+
a11y.apply(cell), this.cellA11y.push(a11y), row.append(cell), cells.push(cell), icons.push(icon), counts.push(amount);
|
|
818
|
+
}
|
|
819
|
+
this.root.append(row);
|
|
820
|
+
}
|
|
821
|
+
this.cells = cells, this.icons = icons, this.counts = counts, this.ghost = ui.box(this.ghostStates[0]), this.ghostIcon = ui.image(0, this.natural, ui.props(s2.icon, iconSize)), this.ghost.append(this.ghostIcon), this.root.append(this.ghost), this.root.accessibility({ role: "group", label: options.label ?? "Inventory" }), options.scope?.add(this);
|
|
822
|
+
}
|
|
823
|
+
get cursor() {
|
|
824
|
+
return this.cursorAt;
|
|
825
|
+
}
|
|
826
|
+
get dragging() {
|
|
827
|
+
return this.source;
|
|
828
|
+
}
|
|
829
|
+
setSlot(index, asset, count2, name) {
|
|
830
|
+
this.assets[index] = asset, this.amounts[index] = asset === (-1) ? 0 : count2, this.names[index] = asset === (-1) ? "Empty" : name, this.render(index);
|
|
831
|
+
}
|
|
832
|
+
clearSlot(index) {
|
|
833
|
+
this.setSlot(index, (-1), 0, "Empty");
|
|
834
|
+
}
|
|
835
|
+
swap(a, b) {
|
|
836
|
+
if (a === b) return;
|
|
837
|
+
let asset = this.assets[a], amount = this.amounts[a], name = this.names[a];
|
|
838
|
+
this.assets[a] = this.assets[b], this.amounts[a] = this.amounts[b], this.names[a] = this.names[b], this.assets[b] = asset, this.amounts[b] = amount, this.names[b] = name, this.render(a), this.render(b);
|
|
839
|
+
}
|
|
840
|
+
select(index) {
|
|
841
|
+
let previous = this.cursorAt;
|
|
842
|
+
this.cursorAt = index, this.paint(previous), this.paint(index), this.onSelect?.(index);
|
|
843
|
+
}
|
|
844
|
+
focusChanged(focused) {
|
|
845
|
+
this.focused = focused, this.paint(this.cursorAt);
|
|
846
|
+
}
|
|
847
|
+
move(move) {
|
|
848
|
+
let c = this.cellColumn[this.cursorAt], r = this.cellRow[this.cursorAt], next = (-1);
|
|
849
|
+
if (move === "left" && c > 0 ? next = this.cursorAt - 1 : move === "right" && c + 1 < this.columns ? next = this.cursorAt + 1 : move === "up" && r > 0 ? next = this.cursorAt - this.columns : move === "down" && r + 1 < this.rows && (next = this.cursorAt + this.columns), next === (-1)) return false;
|
|
850
|
+
let previous = this.cursorAt;
|
|
851
|
+
return this.cursorAt = next, this.held && (this.hover = next, this.placeGhost(next)), this.paint(previous), this.paint(next), true;
|
|
852
|
+
}
|
|
853
|
+
activate() {
|
|
854
|
+
if (!this.held) {
|
|
855
|
+
if (this.assets[this.cursorAt] === (-1)) {
|
|
856
|
+
this.onSelect?.(this.cursorAt);
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
this.begin(this.cursorAt), this.held = true, this.hover = this.cursorAt, this.placeGhost(this.cursorAt);
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
this.held = false, this.drop();
|
|
863
|
+
}
|
|
864
|
+
cancel() {
|
|
865
|
+
return this.source === (-1) ? false : (this.held = false, this.hover = (-1), this.drop(), true);
|
|
866
|
+
}
|
|
867
|
+
begin(index) {
|
|
868
|
+
this.assets[index] !== (-1) && (this.source = index, this.hover = index, this.travel[0] = 0, this.travel[1] = 0, this.ghostIcon.image(this.assets[index], this.natural[0], this.natural[1]), this.placeGhost(index), this.paint(index));
|
|
869
|
+
}
|
|
870
|
+
drag(event) {
|
|
871
|
+
let source = this.source;
|
|
872
|
+
if (source === (-1) || this.held) return;
|
|
873
|
+
let travel = this.travel;
|
|
874
|
+
travel[0] += event.dx * TRAVEL_SCALE | 0, travel[1] += event.dy * TRAVEL_SCALE | 0, this.placeGhost(source);
|
|
875
|
+
let c = this.cellColumn[source] + this.pitchesIn(travel[0]), r = this.cellRow[source] + this.pitchesIn(travel[1]), next = c < 0 || r < 0 || c >= this.columns || r >= this.rows ? (-1) : r * this.columns + c;
|
|
876
|
+
if (next === this.hover) return;
|
|
877
|
+
let previous = this.hover;
|
|
878
|
+
this.hover = next, previous !== (-1) && this.paint(previous), next !== (-1) && this.paint(next);
|
|
879
|
+
}
|
|
880
|
+
drop() {
|
|
881
|
+
let source = this.source;
|
|
882
|
+
if (source === (-1)) return;
|
|
883
|
+
let target = this.hover;
|
|
884
|
+
this.source = (-1), this.hover = (-1), this.ghost.style(this.ghostStates[0]), this.paint(source), target !== (-1) && this.paint(target), !(target === (-1) || target === source) && (this.swap(source, target), this.onMove?.(source, target));
|
|
885
|
+
}
|
|
886
|
+
pitchesIn(travel) {
|
|
887
|
+
let pitch = this.pitch * TRAVEL_SCALE, half = pitch >> 1, rest = travel, count2 = 0;
|
|
888
|
+
for (; rest >= half; )
|
|
889
|
+
rest -= pitch, count2++;
|
|
890
|
+
for (; rest < -half; )
|
|
891
|
+
rest += pitch, count2--;
|
|
892
|
+
return count2;
|
|
893
|
+
}
|
|
894
|
+
placeGhost(index) {
|
|
895
|
+
SLOTS[0] = (8) + this.cellColumn[index] * this.pitch + (this.travel[0] >> (4)), SLOTS[1] = (8) + this.cellRow[index] * this.pitch + (this.travel[1] >> (4)), this.ghost.style(this.ui.props(this.source === (-1) ? this.ghostStates[0] : this.ghostStates[1], s2.ghostAt.setSlotsFrom(SLOTS)));
|
|
896
|
+
}
|
|
897
|
+
render(index) {
|
|
898
|
+
let asset = this.assets[index], icon = this.icons[index];
|
|
899
|
+
asset === (-1) ? icon.style(this.iconStates[1]) : (icon.image(asset, this.natural[0], this.natural[1]), icon.style(this.iconStates[0]));
|
|
900
|
+
let amount = this.amounts[index], text = this.counts[index];
|
|
901
|
+
amount > 1 ? (text.number(amount, PLAIN), text.style(this.countStates[0])) : text.style(this.countStates[1]);
|
|
902
|
+
let a11y = this.cellA11y[index];
|
|
903
|
+
a11y.options.label = this.names[index], a11y.apply(this.cells[index]);
|
|
904
|
+
}
|
|
905
|
+
paint(index) {
|
|
906
|
+
if (index < 0) return;
|
|
907
|
+
let cursor = this.focused && index === this.cursorAt ? 1 : 0, hover = index === this.hover && index !== this.source ? 2 : 0, source = index === this.source ? 4 : 0;
|
|
908
|
+
this.cells[index].style(this.cellStates[cursor | hover | source]);
|
|
909
|
+
}
|
|
910
|
+
};
|
|
911
|
+
function inventoryGrid(ui, options) {
|
|
912
|
+
return new InventoryGrid(ui, options);
|
|
913
|
+
}
|
|
914
|
+
var VirtualList = class {
|
|
915
|
+
constructor(ui, options) {
|
|
916
|
+
this.ui = ui;
|
|
917
|
+
this.options = options;
|
|
918
|
+
this.offsetY = 0;
|
|
919
|
+
this.cursorAt = 0;
|
|
920
|
+
this.focused = false;
|
|
921
|
+
this.total = Math.max(0, options.count), this.rowHeight = options.rowHeight ?? (44), this.height = options.height ?? (320), this.onSelect = options.onSelect ?? null, this.heightOf = options.heightOf ?? null, this.offsets = new Float64Array(this.heightOf === null ? 1 : this.total + 1), this.measureRows(0);
|
|
922
|
+
let pool = Math.ceil(this.height / this.rowHeight) + (2);
|
|
923
|
+
this.bound = new Int32Array(pool).fill((-1)), this.flags = new Uint8Array(pool).fill(255), this.states = [ui.props(s2.slot), ui.props(s2.slot, s2.slotCursor), ui.props(s2.slot, s2.slotHidden)], this.root = ui.scroll(ui.props(s2.list, { height: this.height, width: options.width ?? "100%" }, options.style)), this.content = ui.box();
|
|
924
|
+
let slots = [], rows = [];
|
|
925
|
+
for (let p = 0; p < pool; p++) {
|
|
926
|
+
let element = ui.box(this.states[2]), row = options.create(ui);
|
|
927
|
+
element.append(row.root), element.on("tap", () => {
|
|
928
|
+
let index = this.bound[p];
|
|
929
|
+
index !== (-1) && this.choose(index);
|
|
930
|
+
}), this.content.append(element), slots.push(element), rows.push(row);
|
|
931
|
+
}
|
|
932
|
+
this.slots = slots, this.rows = rows, this.root.append(this.content), this.root.on("scroll", (event) => this.scrolled(event.dy)), this.root.accessibility({ role: "scroll_view", label: options.label ?? "List", actions: ["scroll"] }), this.extend(), this.refresh(true), options.scope?.add(this);
|
|
933
|
+
}
|
|
934
|
+
get count() {
|
|
935
|
+
return this.total;
|
|
936
|
+
}
|
|
937
|
+
get offset() {
|
|
938
|
+
return this.offsetY;
|
|
939
|
+
}
|
|
940
|
+
get cursor() {
|
|
941
|
+
return this.cursorAt;
|
|
942
|
+
}
|
|
943
|
+
get pool() {
|
|
944
|
+
return this.slots.length;
|
|
945
|
+
}
|
|
946
|
+
get variable() {
|
|
947
|
+
return this.heightOf !== null;
|
|
948
|
+
}
|
|
949
|
+
rowTop(index) {
|
|
950
|
+
return this.heightOf === null ? index * this.rowHeight : this.offsets[index];
|
|
951
|
+
}
|
|
952
|
+
rowSize(index) {
|
|
953
|
+
return this.heightOf === null ? this.rowHeight : this.offsets[index + 1] - this.offsets[index];
|
|
954
|
+
}
|
|
955
|
+
get contentHeight() {
|
|
956
|
+
return this.heightOf === null ? this.total * this.rowHeight : this.offsets[this.total];
|
|
957
|
+
}
|
|
958
|
+
invalidateHeights(from = 0) {
|
|
959
|
+
this.heightOf !== null && (this.measureRows(clamp(from, 0, this.total)), this.extend(), this.offsetY = clamp(this.offsetY, 0, this.maxOffset()) | 0, this.refresh(true));
|
|
960
|
+
}
|
|
961
|
+
measureRows(from) {
|
|
962
|
+
let heightOf = this.heightOf;
|
|
963
|
+
if (heightOf === null) return;
|
|
964
|
+
if (this.offsets.length < this.total + 1) {
|
|
965
|
+
let grown = new Float64Array(Math.max(this.total + 1, this.offsets.length * 2));
|
|
966
|
+
grown.set(this.offsets.subarray(0, from + 1)), this.offsets = grown;
|
|
967
|
+
}
|
|
968
|
+
let offsets = this.offsets;
|
|
969
|
+
offsets[0] = 0;
|
|
970
|
+
for (let i = from; i < this.total; i++) offsets[i + 1] = offsets[i] + Math.max(0, heightOf(i));
|
|
971
|
+
}
|
|
972
|
+
firstVisible(offset) {
|
|
973
|
+
if (this.heightOf === null) return (offset - offset % this.rowHeight) / this.rowHeight;
|
|
974
|
+
let offsets = this.offsets, low = 0, high = this.total;
|
|
975
|
+
for (; low < high; ) {
|
|
976
|
+
let middle = low + high >>> 1;
|
|
977
|
+
offsets[middle + 1] <= offset ? low = middle + 1 : high = middle;
|
|
978
|
+
}
|
|
979
|
+
return low;
|
|
980
|
+
}
|
|
981
|
+
setCount(count2) {
|
|
982
|
+
let previous = this.total;
|
|
983
|
+
this.total = Math.max(0, count2), this.measureRows(Math.min(previous, this.total)), this.cursorAt = clamp(this.cursorAt, 0, Math.max(0, this.total - 1)), this.extend(), this.offsetY = clamp(this.offsetY, 0, this.maxOffset()) | 0, this.refresh(true);
|
|
984
|
+
}
|
|
985
|
+
rebind() {
|
|
986
|
+
this.refresh(true);
|
|
987
|
+
}
|
|
988
|
+
scrollTo(offset) {
|
|
989
|
+
let next = clamp(offset, 0, this.maxOffset());
|
|
990
|
+
this.root.scrollTo(0, next), this.scrolled(next);
|
|
991
|
+
}
|
|
992
|
+
scrollToIndex(index) {
|
|
993
|
+
let top = this.rowTop(index), size = this.rowSize(index);
|
|
994
|
+
top < this.offsetY ? this.scrollTo(top) : top + size > this.offsetY + this.height && this.scrollTo(top + size - this.height);
|
|
995
|
+
}
|
|
996
|
+
focusChanged(focused) {
|
|
997
|
+
this.focused = focused, this.refresh(false);
|
|
998
|
+
}
|
|
999
|
+
move(move) {
|
|
1000
|
+
if (this.total === 0) return false;
|
|
1001
|
+
let next = this.cursorAt;
|
|
1002
|
+
if (move === "up") next--;
|
|
1003
|
+
else if (move === "down") next++;
|
|
1004
|
+
else return false;
|
|
1005
|
+
return next < 0 || next >= this.total ? false : (this.cursorAt = next, this.scrollToIndex(next), this.refresh(false), true);
|
|
1006
|
+
}
|
|
1007
|
+
activate() {
|
|
1008
|
+
this.total > 0 && this.choose(this.cursorAt);
|
|
1009
|
+
}
|
|
1010
|
+
choose(index) {
|
|
1011
|
+
this.cursorAt = index, this.refresh(false), this.onSelect?.(index);
|
|
1012
|
+
}
|
|
1013
|
+
scrolled(offset) {
|
|
1014
|
+
this.offsetY = offset | 0, this.refresh(false);
|
|
1015
|
+
}
|
|
1016
|
+
maxOffset() {
|
|
1017
|
+
return Math.max(0, this.contentHeight - this.height);
|
|
1018
|
+
}
|
|
1019
|
+
extend() {
|
|
1020
|
+
SLOTS[0] = this.contentHeight, this.content.style(this.ui.props(s2.content, s2.extent.setSlotsFrom(SLOTS)));
|
|
1021
|
+
}
|
|
1022
|
+
refresh(force) {
|
|
1023
|
+
let pool = this.slots.length, offset = this.offsetY < 0 ? 0 : this.offsetY, first = this.firstVisible(offset);
|
|
1024
|
+
for (let k = 0; k < pool; k++) {
|
|
1025
|
+
let index = first + k, p = index % pool, slotElement = this.slots[p], visible = index < this.total, flag = visible ? this.focused && index === this.cursorAt ? 1 : 0 : 2, moved = this.bound[p] !== index;
|
|
1026
|
+
if (visible && (moved || force) && this.options.bind(this.rows[p], index), !moved && this.flags[p] === flag && !force) continue;
|
|
1027
|
+
this.bound[p] = visible ? index : (-1), this.flags[p] = flag;
|
|
1028
|
+
let fixed = this.heightOf === null;
|
|
1029
|
+
SLOTS[0] = fixed || visible ? this.rowTop(index) : this.contentHeight, SLOTS[1] = fixed || !visible ? this.rowHeight : this.rowSize(index), slotElement.style(this.ui.props(this.states[flag], s2.slotAt.setSlotsFrom(SLOTS)));
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
};
|
|
1033
|
+
function virtualList(ui, options) {
|
|
1034
|
+
return new VirtualList(ui, options);
|
|
1035
|
+
}
|
|
1036
|
+
var Leaderboard = class {
|
|
1037
|
+
constructor(ui, options = {}) {
|
|
1038
|
+
this.ui = ui;
|
|
1039
|
+
this.names = [];
|
|
1040
|
+
this.scores = [];
|
|
1041
|
+
this.me = (-1);
|
|
1042
|
+
this.rowStates = [ui.props(s2.leader), ui.props(s2.leader, s2.rowMe)];
|
|
1043
|
+
let mono = fontStyle(ui, "mono"), body = fontStyle(ui, "body");
|
|
1044
|
+
this.rankStates = [ui.props(mono, s2.rank), ui.props(mono, s2.rank, s2.gold), ui.props(mono, s2.rank, s2.silver), ui.props(mono, s2.rank, s2.bronze), ui.props(mono, s2.rank, s2.onAccent)], this.nameStates = [ui.props(body, s2.name), ui.props(body, s2.name, s2.onAccent)], this.scoreStyle = ui.props(mono, s2.score), this.list = new VirtualList(ui, {
|
|
1045
|
+
count: 0,
|
|
1046
|
+
rowHeight: options.rowHeight,
|
|
1047
|
+
height: options.height,
|
|
1048
|
+
width: options.width,
|
|
1049
|
+
label: options.label ?? "Leaderboard",
|
|
1050
|
+
style: options.style,
|
|
1051
|
+
scope: options.scope,
|
|
1052
|
+
onSelect: options.onSelect,
|
|
1053
|
+
create: (owner) => {
|
|
1054
|
+
let root = owner.box(this.rowStates[0]), rank = owner.text("", this.rankStates[0]), name = owner.text("", this.nameStates[0]), score = owner.text("", this.scoreStyle);
|
|
1055
|
+
return root.append(rank).append(name).append(score), { root, rank, name, score };
|
|
1056
|
+
},
|
|
1057
|
+
bind: (row, index) => this.bind(row, index)
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
get root() {
|
|
1061
|
+
return this.list.root;
|
|
1062
|
+
}
|
|
1063
|
+
setEntries(names, scores, me = (-1)) {
|
|
1064
|
+
this.names = names, this.scores = scores, this.me = me, this.list.setCount(Math.min(names.length, scores.length));
|
|
1065
|
+
}
|
|
1066
|
+
showMe() {
|
|
1067
|
+
this.me !== (-1) && this.list.scrollToIndex(this.me);
|
|
1068
|
+
}
|
|
1069
|
+
bind(row, index) {
|
|
1070
|
+
let mine = index === this.me;
|
|
1071
|
+
row.root.style(this.rowStates[mine ? 1 : 0]), row.rank.style(this.rankStates[mine ? 4 : index < (3) ? index + 1 : 0]), row.rank.number(index + 1, PLAIN), row.name.text(this.names[index]), row.name.style(this.nameStates[mine ? 1 : 0]), row.score.number(this.scores[index], INTEGER);
|
|
1072
|
+
}
|
|
1073
|
+
};
|
|
1074
|
+
function leaderboard(ui, options = {}) {
|
|
1075
|
+
return new Leaderboard(ui, options);
|
|
1076
|
+
}
|
|
1077
|
+
var CHAT_LOG_WIDTH = 300, CHAT_LOG_HEIGHT = 240, CHAT_LOG_FONT = 14, CHAT_LOG_PADDING = 6, CHAT_LOG_CAPACITY = 2e3, CHAT_LOG_MIN_ROW = 18, SCROLL_END = Number.MAX_SAFE_INTEGER, chatLogStyles = styles({
|
|
1078
|
+
row: { width: "100%", height: "100%", padding: [0, (6), 0, (6)], justify: "center" },
|
|
1079
|
+
line: { textWrap: true, textColor: tokens.text, pointerEvents: "none" }
|
|
1080
|
+
}), ChatLog = class {
|
|
1081
|
+
constructor(ui, options = {}) {
|
|
1082
|
+
this.ui = ui;
|
|
1083
|
+
this.lines = [];
|
|
1084
|
+
this.head = 0;
|
|
1085
|
+
this.measured = { lines: 0, width: 0, height: 0 };
|
|
1086
|
+
let width = options.width ?? (300), fontSize = options.fontSize ?? (14);
|
|
1087
|
+
this.capacity = options.capacity ?? (2e3), this.lineWidth = width - (6) * 2, this.measureStyle = { fontFamily: kitFamily(ui, "body"), fontSize };
|
|
1088
|
+
let lineStyle = ui.props(fontStyle(ui, "body"), chatLogStyles.line, { fontSize }), rowStyle = ui.props(chatLogStyles.row);
|
|
1089
|
+
this.list = new VirtualList(ui, {
|
|
1090
|
+
count: 0,
|
|
1091
|
+
rowHeight: Math.min((18), fontSize),
|
|
1092
|
+
height: options.height ?? (240),
|
|
1093
|
+
width,
|
|
1094
|
+
label: options.label ?? "Chat",
|
|
1095
|
+
style: options.style,
|
|
1096
|
+
scope: options.scope,
|
|
1097
|
+
heightOf: (index) => this.heightOf(index),
|
|
1098
|
+
create: (owner) => {
|
|
1099
|
+
let root = owner.box(rowStyle), line = owner.text("", lineStyle);
|
|
1100
|
+
return root.append(line), { root, line };
|
|
1101
|
+
},
|
|
1102
|
+
bind: (row, index) => {
|
|
1103
|
+
row.line.text(this.line(index));
|
|
1104
|
+
}
|
|
1105
|
+
});
|
|
1106
|
+
}
|
|
1107
|
+
get root() {
|
|
1108
|
+
return this.list.root;
|
|
1109
|
+
}
|
|
1110
|
+
get count() {
|
|
1111
|
+
return this.lines.length;
|
|
1112
|
+
}
|
|
1113
|
+
line(index) {
|
|
1114
|
+
return this.lines[(this.head + index) % this.lines.length];
|
|
1115
|
+
}
|
|
1116
|
+
push(sender, message) {
|
|
1117
|
+
let text = sender.length > 0 ? `${sender}: ${message}` : message;
|
|
1118
|
+
this.lines.length < this.capacity ? (this.lines.push(text), this.list.setCount(this.lines.length)) : (this.lines[this.head] = text, this.head = (this.head + 1) % this.capacity, this.list.invalidateHeights(0)), this.list.scrollTo(SCROLL_END);
|
|
1119
|
+
}
|
|
1120
|
+
heightOf(index) {
|
|
1121
|
+
return this.ui.measureText(this.line(index), this.measureStyle, this.lineWidth, this.measured).height;
|
|
1122
|
+
}
|
|
1123
|
+
};
|
|
1124
|
+
function chatLog(ui, options = {}) {
|
|
1125
|
+
return new ChatLog(ui, options);
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
// src/interactives/game-ui/widgets/focus.ts
|
|
1129
|
+
var UiFocusScope = class {
|
|
1130
|
+
constructor(columns = 1, onBack = null) {
|
|
1131
|
+
this.columns = columns;
|
|
1132
|
+
this.onBack = onBack;
|
|
1133
|
+
this.targets = [];
|
|
1134
|
+
this.current = -1;
|
|
1135
|
+
}
|
|
1136
|
+
add(target) {
|
|
1137
|
+
return this.targets.indexOf(target) < 0 && this.targets.push(target), this;
|
|
1138
|
+
}
|
|
1139
|
+
remove(target) {
|
|
1140
|
+
let at = this.targets.indexOf(target);
|
|
1141
|
+
return at < 0 ? this : (removeAt(this.targets, at), this.current === at ? this.current = -1 : this.current > at && this.current--, this);
|
|
1142
|
+
}
|
|
1143
|
+
clear() {
|
|
1144
|
+
this.targets.length = 0, this.current = -1;
|
|
1145
|
+
}
|
|
1146
|
+
};
|
|
1147
|
+
function focusNodeOf(target) {
|
|
1148
|
+
return target.focusNode ?? target.root;
|
|
1149
|
+
}
|
|
1150
|
+
function usable(target) {
|
|
1151
|
+
let root = focusNodeOf(target);
|
|
1152
|
+
return !root.destroyed && (root.active() & Condition.disabled) === 0;
|
|
1153
|
+
}
|
|
1154
|
+
function stepOf(move, columns) {
|
|
1155
|
+
switch (move) {
|
|
1156
|
+
case "next":
|
|
1157
|
+
case "right":
|
|
1158
|
+
return 1;
|
|
1159
|
+
case "previous":
|
|
1160
|
+
case "left":
|
|
1161
|
+
return -1;
|
|
1162
|
+
case "down":
|
|
1163
|
+
return columns;
|
|
1164
|
+
default:
|
|
1165
|
+
return -columns;
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
var UiNavigator = class {
|
|
1169
|
+
constructor(base = new UiFocusScope()) {
|
|
1170
|
+
this.scopes = new StableList();
|
|
1171
|
+
this.listeners = [];
|
|
1172
|
+
this.shown = null;
|
|
1173
|
+
this.base = base, this.scopes.push(base);
|
|
1174
|
+
}
|
|
1175
|
+
get scope() {
|
|
1176
|
+
return this.scopes.at(this.scopes.size - 1);
|
|
1177
|
+
}
|
|
1178
|
+
get depth() {
|
|
1179
|
+
return this.scopes.size;
|
|
1180
|
+
}
|
|
1181
|
+
get focused() {
|
|
1182
|
+
return this.shown;
|
|
1183
|
+
}
|
|
1184
|
+
onChange(listener) {
|
|
1185
|
+
return this.listeners.push(listener), () => {
|
|
1186
|
+
let at = this.listeners.indexOf(listener);
|
|
1187
|
+
at >= 0 && removeAt(this.listeners, at);
|
|
1188
|
+
};
|
|
1189
|
+
}
|
|
1190
|
+
has(scope) {
|
|
1191
|
+
return this.scopes.indexOf(scope) >= 0;
|
|
1192
|
+
}
|
|
1193
|
+
push(scope) {
|
|
1194
|
+
this.has(scope) || (this.scopes.push(scope), this.restore(scope));
|
|
1195
|
+
}
|
|
1196
|
+
pop(scope = null) {
|
|
1197
|
+
let target = scope ?? this.scope;
|
|
1198
|
+
if (target === this.base) return;
|
|
1199
|
+
let at = this.scopes.indexOf(target);
|
|
1200
|
+
if (at < 0) return;
|
|
1201
|
+
let wasTop = at === this.scopes.size - 1;
|
|
1202
|
+
this.scopes.removeAt(at), wasTop && this.restore(this.scope);
|
|
1203
|
+
}
|
|
1204
|
+
focus(target) {
|
|
1205
|
+
let scope = this.scope, at = scope.targets.indexOf(target);
|
|
1206
|
+
return at < 0 || !usable(target) ? false : (this.show(scope, at), true);
|
|
1207
|
+
}
|
|
1208
|
+
move(move) {
|
|
1209
|
+
let scope = this.scope, count2 = scope.targets.length;
|
|
1210
|
+
if (count2 === 0) return false;
|
|
1211
|
+
let at = scope.current;
|
|
1212
|
+
if (at >= 0 && at < count2 && this.shown === scope.targets[at]) {
|
|
1213
|
+
let current = scope.targets[at];
|
|
1214
|
+
if (current.move !== void 0 && current.move(move)) return true;
|
|
1215
|
+
} else
|
|
1216
|
+
return this.first(scope);
|
|
1217
|
+
let step = stepOf(move, scope.columns);
|
|
1218
|
+
for (let i = 1; i <= count2; i++) {
|
|
1219
|
+
let next = ((at + step * i) % count2 + count2) % count2;
|
|
1220
|
+
if (next === at) break;
|
|
1221
|
+
if (usable(scope.targets[next]))
|
|
1222
|
+
return this.show(scope, next), true;
|
|
1223
|
+
}
|
|
1224
|
+
return false;
|
|
1225
|
+
}
|
|
1226
|
+
activate() {
|
|
1227
|
+
let target = this.shown;
|
|
1228
|
+
return target === null || target.activate === void 0 || !usable(target) ? false : (target.activate(), true);
|
|
1229
|
+
}
|
|
1230
|
+
back() {
|
|
1231
|
+
let onBack = this.scope.onBack;
|
|
1232
|
+
return onBack !== null && onBack();
|
|
1233
|
+
}
|
|
1234
|
+
blur() {
|
|
1235
|
+
this.set(null);
|
|
1236
|
+
}
|
|
1237
|
+
first(scope) {
|
|
1238
|
+
for (let i = 0; i < scope.targets.length; i++)
|
|
1239
|
+
if (usable(scope.targets[i]))
|
|
1240
|
+
return this.show(scope, i), true;
|
|
1241
|
+
return this.set(null), false;
|
|
1242
|
+
}
|
|
1243
|
+
restore(scope) {
|
|
1244
|
+
let at = scope.current;
|
|
1245
|
+
at >= 0 && at < scope.targets.length && usable(scope.targets[at]) ? this.show(scope, at) : scope.targets.length > 0 ? this.first(scope) : this.set(null);
|
|
1246
|
+
}
|
|
1247
|
+
show(scope, at) {
|
|
1248
|
+
scope.current = at, this.set(scope.targets[at]);
|
|
1249
|
+
}
|
|
1250
|
+
set(target) {
|
|
1251
|
+
let previous = this.shown;
|
|
1252
|
+
if (previous !== target) {
|
|
1253
|
+
if (this.shown = target, previous !== null && !focusNodeOf(previous).destroyed) {
|
|
1254
|
+
let node = focusNodeOf(previous);
|
|
1255
|
+
node.setState("focus", false), previous.focusChanged?.(false), target === null && node.blur();
|
|
1256
|
+
}
|
|
1257
|
+
if (target !== null) {
|
|
1258
|
+
let node = focusNodeOf(target);
|
|
1259
|
+
node.setState("focus", true), node.focus(), target.focusChanged?.(true);
|
|
1260
|
+
}
|
|
1261
|
+
for (let i = 0; i < this.listeners.length; i++) this.listeners[i](target);
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
};
|
|
1265
|
+
|
|
1266
|
+
// src/interactives/game-ui/widgets/controls.ts
|
|
1267
|
+
var TRACK_WIDTH = 52, TRACK_HEIGHT = 30, KNOB = 24, KNOB_INSET = 3, RAIL = 6, THUMB = 24, SLIDER_HEIGHT = 32, SLIDER_WIDTH = 220, DROPDOWN_WIDTH = 200, OPTION_HEIGHT = 40, CHEVRON = 8, CHEVRON_TURN = Math.PI / 4, POPUP_Z = 50, MAX_LABELLED_STEPS = 1001, s3 = styles({
|
|
1268
|
+
button: {
|
|
1269
|
+
direction: "row",
|
|
1270
|
+
alignItems: "center",
|
|
1271
|
+
justify: "center",
|
|
1272
|
+
gap: kitVars.gapSmall,
|
|
1273
|
+
minHeight: (44),
|
|
1274
|
+
padding: [kitVars.gap, kitVars.padding, kitVars.gap, kitVars.padding],
|
|
1275
|
+
radius: kitVars.radius,
|
|
1276
|
+
fill: { default: tokens.raised, ":disabled": tokens.track },
|
|
1277
|
+
borderWidth: kitVars.focusWidth,
|
|
1278
|
+
borderColor: { default: TRANSPARENT, ":focus": kitVars.focus },
|
|
1279
|
+
scale: { default: 1, ":pressed": kitVars.pressScale },
|
|
1280
|
+
opacity: { default: 1, ":disabled": 0.55 }
|
|
1281
|
+
},
|
|
1282
|
+
primary: { fill: { default: tokens.accent, ":disabled": tokens.track } },
|
|
1283
|
+
danger: { fill: { default: tokens.danger, ":disabled": tokens.track } },
|
|
1284
|
+
ghost: { fill: { default: TRANSPARENT, ":focus": kitVars.highlight, ":pressed": kitVars.highlight, ":disabled": TRANSPARENT } },
|
|
1285
|
+
label: { fontSize: kitVars.body, fontWeight: 700, textColor: { default: tokens.text, ":disabled": tokens.muted }, pointerEvents: "none" },
|
|
1286
|
+
onPrimary: { textColor: { default: tokens.onAccent, ":disabled": tokens.muted } },
|
|
1287
|
+
onDanger: { textColor: { default: kitVars.onDanger, ":disabled": tokens.muted } },
|
|
1288
|
+
icon: { width: 20, height: 20, pointerEvents: "none" },
|
|
1289
|
+
row: {
|
|
1290
|
+
direction: "row",
|
|
1291
|
+
alignItems: "center",
|
|
1292
|
+
justify: "space-between",
|
|
1293
|
+
gap: kitVars.gap,
|
|
1294
|
+
minHeight: (44),
|
|
1295
|
+
padding: [kitVars.gapSmall, kitVars.gap, kitVars.gapSmall, kitVars.gap],
|
|
1296
|
+
radius: kitVars.radius,
|
|
1297
|
+
borderWidth: kitVars.focusWidth,
|
|
1298
|
+
borderColor: { default: TRANSPARENT, ":focus": kitVars.focus },
|
|
1299
|
+
fill: { default: TRANSPARENT, ":pressed": kitVars.highlight },
|
|
1300
|
+
opacity: { default: 1, ":disabled": 0.5 }
|
|
1301
|
+
},
|
|
1302
|
+
track: { width: (52), height: (30), radius: (30) / 2, fill: tokens.track, padding: (3), justify: "center", pointerEvents: "none" },
|
|
1303
|
+
trackOn: { fill: tokens.accent },
|
|
1304
|
+
knob: {
|
|
1305
|
+
width: (24),
|
|
1306
|
+
height: (24),
|
|
1307
|
+
radius: (24) / 2,
|
|
1308
|
+
fill: tokens.text,
|
|
1309
|
+
translateX: 0,
|
|
1310
|
+
scale: { default: 1, ":pressed": 0.88 },
|
|
1311
|
+
shadow: { color: kitVars.shadow, y: 1, blur: 3 }
|
|
1312
|
+
},
|
|
1313
|
+
knobOn: { translateX: (52) - (24) - (3) * 2, fill: tokens.onAccent },
|
|
1314
|
+
slider: { gap: kitVars.gapSmall, padding: [kitVars.gapSmall, kitVars.gap, kitVars.gapSmall, kitVars.gap], radius: kitVars.radius, borderWidth: kitVars.focusWidth, borderColor: { default: TRANSPARENT, ":focus": kitVars.focus }, opacity: { default: 1, ":disabled": 0.5 } },
|
|
1315
|
+
header: { direction: "row", justify: "space-between", alignItems: "center", pointerEvents: "none" },
|
|
1316
|
+
rail: { height: (32), position: "relative" },
|
|
1317
|
+
railLine: { position: "absolute", left: 0, right: 0, top: ((32) - (6)) / 2, height: (6), radius: (6) / 2, fill: tokens.track, pointerEvents: "none" },
|
|
1318
|
+
railFill: { position: "absolute", left: 0, top: ((32) - (6)) / 2, height: (6), radius: (6) / 2, fill: tokens.accent, pointerEvents: "none" },
|
|
1319
|
+
thumb: {
|
|
1320
|
+
position: "absolute",
|
|
1321
|
+
top: ((32) - (24)) / 2,
|
|
1322
|
+
width: (24),
|
|
1323
|
+
height: (24),
|
|
1324
|
+
marginLeft: -(24) / 2,
|
|
1325
|
+
radius: (24) / 2,
|
|
1326
|
+
fill: tokens.text,
|
|
1327
|
+
borderWidth: kitVars.focusWidth,
|
|
1328
|
+
borderColor: { default: TRANSPARENT, ":focus": kitVars.focus },
|
|
1329
|
+
scale: { default: 1, ":pressed": 1.15 },
|
|
1330
|
+
shadow: { color: kitVars.shadow, y: 1, blur: 4 },
|
|
1331
|
+
pointerEvents: "none"
|
|
1332
|
+
},
|
|
1333
|
+
fillTo: { width: "0%" },
|
|
1334
|
+
thumbAt: { left: "0%" },
|
|
1335
|
+
dropdown: { position: "relative", gap: kitVars.gapSmall },
|
|
1336
|
+
field: { justify: "space-between" },
|
|
1337
|
+
chevron: { width: (8), height: (8), borderColor: tokens.muted, borderWidth: [0, 2, 2, 0], rotate: CHEVRON_TURN, marginTop: -(8) / 2, pointerEvents: "none" },
|
|
1338
|
+
chevronOpen: { rotate: -CHEVRON_TURN * 3, marginTop: (8) / 2 },
|
|
1339
|
+
popup: {
|
|
1340
|
+
position: "absolute",
|
|
1341
|
+
top: "100%",
|
|
1342
|
+
left: 0,
|
|
1343
|
+
right: 0,
|
|
1344
|
+
marginTop: kitVars.gapSmall,
|
|
1345
|
+
padding: kitVars.gapSmall,
|
|
1346
|
+
gap: 2,
|
|
1347
|
+
fill: tokens.surface,
|
|
1348
|
+
radius: kitVars.radius,
|
|
1349
|
+
borderWidth: kitVars.borderWidth,
|
|
1350
|
+
borderColor: tokens.border,
|
|
1351
|
+
shadow: { color: kitVars.shadow, y: 8, blur: 24 },
|
|
1352
|
+
zIndex: (50),
|
|
1353
|
+
hidden: true
|
|
1354
|
+
},
|
|
1355
|
+
option: {
|
|
1356
|
+
minHeight: (40),
|
|
1357
|
+
justify: "center",
|
|
1358
|
+
padding: [kitVars.gapSmall, kitVars.gap, kitVars.gapSmall, kitVars.gap],
|
|
1359
|
+
radius: kitVars.radiusSmall,
|
|
1360
|
+
fill: { default: TRANSPARENT, ":focus": kitVars.highlight, ":pressed": kitVars.highlight },
|
|
1361
|
+
borderWidth: kitVars.focusWidth,
|
|
1362
|
+
borderColor: { default: TRANSPARENT, ":focus": kitVars.focus }
|
|
1363
|
+
},
|
|
1364
|
+
optionOn: { fill: { default: tokens.accent, ":focus": tokens.accent } }
|
|
1365
|
+
}, {
|
|
1366
|
+
fillTo: slotWords({ width: slot(0, true) }),
|
|
1367
|
+
thumbAt: slotWords({ left: slot(0, true) })
|
|
1368
|
+
}), TextButton = class {
|
|
1369
|
+
constructor(ui, options) {
|
|
1370
|
+
this.ui = ui;
|
|
1371
|
+
let variant = options.variant ?? "secondary";
|
|
1372
|
+
this.onPress = options.onPress ?? null, this.root = ui.box(ui.props(s3.button, variant === "primary" && s3.primary, variant === "danger" && s3.danger, variant === "ghost" && s3.ghost, options.style)), this.root.transition(["scale_x", "scale_y", "fill"], { duration: (0.12), easing: "back_out" }), options.icon !== void 0 && this.root.append(ui.image(options.icon, options.natural ?? [32, 32], s3.icon)), this.text = label(ui, options.label, "body", s3.label, variant === "primary" ? s3.onPrimary : variant === "danger" ? s3.onDanger : null, options.labelStyle), this.root.append(this.text), this.root.on("tap", () => this.activate()), this.a11y = new A11y({ role: "button", label: options.label, disabled: options.disabled === true, actions: ["activate"] }), this.a11y.apply(this.root), options.scope?.add(this);
|
|
1373
|
+
}
|
|
1374
|
+
get disabled() {
|
|
1375
|
+
return this.a11y.options.disabled === true;
|
|
1376
|
+
}
|
|
1377
|
+
setLabel(value) {
|
|
1378
|
+
this.text.text(value), this.a11y.options.label = value, this.a11y.apply(this.root);
|
|
1379
|
+
}
|
|
1380
|
+
setDisabled(disabled) {
|
|
1381
|
+
disabled !== this.disabled && (this.a11y.options.disabled = disabled, this.a11y.apply(this.root));
|
|
1382
|
+
}
|
|
1383
|
+
activate() {
|
|
1384
|
+
this.disabled || this.onPress?.();
|
|
1385
|
+
}
|
|
1386
|
+
};
|
|
1387
|
+
function textButton(ui, options) {
|
|
1388
|
+
return new TextButton(ui, options);
|
|
1389
|
+
}
|
|
1390
|
+
var Toggle = class {
|
|
1391
|
+
constructor(ui, options) {
|
|
1392
|
+
this.on = options.value ?? false, this.onChange = options.onChange ?? null, this.root = ui.box(ui.props(s3.row, options.style)), this.root.append(label(ui, options.label, "body", sheet.text)), this.tracks = [ui.props(s3.track), ui.props(s3.track, s3.trackOn)], this.knobs = [ui.props(s3.knob), ui.props(s3.knob, s3.knobOn)], this.track = ui.box(this.tracks[this.on ? 1 : 0]), this.knob = ui.box(this.knobs[this.on ? 1 : 0]), this.track.transition(["fill"], { duration: (0.18) }), this.knob.transition(["translate_x", "scale_x", "scale_y"], { duration: (0.18), easing: "back_out" }), this.track.append(this.knob), this.root.append(this.track), this.root.on("tap", () => this.activate()), this.a11y = new A11y({ role: "button", label: options.label, value: this.on ? "On" : "Off", selected: this.on, disabled: options.disabled === true, actions: ["activate"] }), this.a11y.apply(this.root), options.scope?.add(this);
|
|
1393
|
+
}
|
|
1394
|
+
get value() {
|
|
1395
|
+
return this.on;
|
|
1396
|
+
}
|
|
1397
|
+
set(value, notify = false) {
|
|
1398
|
+
if (value === this.on) return;
|
|
1399
|
+
this.on = value;
|
|
1400
|
+
let index = value ? 1 : 0;
|
|
1401
|
+
this.track.style(this.tracks[index]), this.knob.style(this.knobs[index]), this.a11y.options.value = value ? "On" : "Off", this.a11y.options.selected = value, this.a11y.apply(this.root), notify && this.onChange?.(value);
|
|
1402
|
+
}
|
|
1403
|
+
setDisabled(disabled) {
|
|
1404
|
+
this.a11y.options.disabled !== disabled && (this.a11y.options.disabled = disabled, this.a11y.apply(this.root));
|
|
1405
|
+
}
|
|
1406
|
+
activate() {
|
|
1407
|
+
this.a11y.options.disabled !== true && this.set(!this.on, true);
|
|
1408
|
+
}
|
|
1409
|
+
};
|
|
1410
|
+
function toggle(ui, options) {
|
|
1411
|
+
return new Toggle(ui, options);
|
|
1412
|
+
}
|
|
1413
|
+
var Slider = class {
|
|
1414
|
+
constructor(ui, options) {
|
|
1415
|
+
this.ui = ui;
|
|
1416
|
+
this.index = -1;
|
|
1417
|
+
this.dragFrom = 0;
|
|
1418
|
+
this.travel = new Float64Array(1);
|
|
1419
|
+
this.min = options.min ?? 0, this.max = options.max ?? 1, this.step = options.step ?? (this.max - this.min) / (100), this.width = options.width ?? (220), this.onChange = options.onChange ?? null, this.steps = Math.max(1, Math.round((this.max - this.min) / this.step));
|
|
1420
|
+
let format = options.format ?? ((value) => percentLabel(value, this.min, this.max));
|
|
1421
|
+
this.texts = this.steps < (1001) ? Array.from({ length: this.steps + 1 }, (_, i) => format(this.min + i * this.step)) : null, this.root = ui.box(ui.props(s3.slider, { width: this.width }, options.style));
|
|
1422
|
+
let header = ui.box(s3.header);
|
|
1423
|
+
header.append(label(ui, options.label, "body", sheet.text)), this.readout = label(ui, "", "mono", sheet.small, sheet.strong), header.append(this.readout), this.rail = ui.box(s3.rail), this.rail.append(ui.box(s3.railLine)), this.fill = ui.box(), this.thumb = ui.box(), this.rail.append(this.fill).append(this.thumb), this.root.append(header).append(this.rail), this.rail.on("drag_start", () => {
|
|
1424
|
+
this.dragFrom = this.index, this.travel[0] = 0;
|
|
1425
|
+
}), this.rail.on("drag_move", (event) => {
|
|
1426
|
+
let travel = this.travel;
|
|
1427
|
+
travel[0] += event.dx, this.select(this.dragFrom + Math.round(travel[0] / this.width * this.steps), true);
|
|
1428
|
+
}), this.root.on("action", (event) => {
|
|
1429
|
+
event.value === UiAction.increment ? this.nudge(1) : event.value === UiAction.decrement && this.nudge(-1);
|
|
1430
|
+
}), this.a11y = new A11y({ role: "adjustable", label: options.label, disabled: options.disabled === true, actions: ["increment", "decrement"] }), this.set(options.value ?? this.min), options.scope?.add(this);
|
|
1431
|
+
}
|
|
1432
|
+
get value() {
|
|
1433
|
+
return clamp(this.min + this.index * this.step, this.min, this.max);
|
|
1434
|
+
}
|
|
1435
|
+
set(value, notify = false) {
|
|
1436
|
+
this.select(Math.round((clamp(value, this.min, this.max) - this.min) / this.step), notify);
|
|
1437
|
+
}
|
|
1438
|
+
select(step, notify = false) {
|
|
1439
|
+
let next = step < 0 ? 0 : step > this.steps ? this.steps : step;
|
|
1440
|
+
if (next === this.index) return;
|
|
1441
|
+
this.index = next;
|
|
1442
|
+
let ui = this.ui;
|
|
1443
|
+
SLOTS[0] = next * (100) / this.steps, this.fill.style(ui.props(s3.railFill, s3.fillTo.setSlotsFrom(SLOTS))), this.thumb.style(ui.props(s3.thumb, s3.thumbAt.setSlotsFrom(SLOTS)));
|
|
1444
|
+
let text = this.texts === null ? PERCENT_TEXT[Math.round(next * (100) / this.steps)] : this.texts[next];
|
|
1445
|
+
this.readout.text(text), this.a11y.options.value = text, this.a11y.apply(this.root), notify && this.onChange?.(this.value);
|
|
1446
|
+
}
|
|
1447
|
+
nudge(direction) {
|
|
1448
|
+
this.a11y.options.disabled !== true && this.select(this.index + direction, true);
|
|
1449
|
+
}
|
|
1450
|
+
setDisabled(disabled) {
|
|
1451
|
+
this.a11y.options.disabled !== disabled && (this.a11y.options.disabled = disabled, this.a11y.apply(this.root));
|
|
1452
|
+
}
|
|
1453
|
+
move(move) {
|
|
1454
|
+
if (move === "left") this.nudge(-1);
|
|
1455
|
+
else if (move === "right") this.nudge(1);
|
|
1456
|
+
else return false;
|
|
1457
|
+
return true;
|
|
1458
|
+
}
|
|
1459
|
+
};
|
|
1460
|
+
function percentLabel(value, min, max) {
|
|
1461
|
+
let percent = max > min ? Math.round((value - min) / (max - min) * (100)) : 0;
|
|
1462
|
+
return PERCENT_TEXT[clamp(percent, 0, (100))];
|
|
1463
|
+
}
|
|
1464
|
+
function slider(ui, options) {
|
|
1465
|
+
return new Slider(ui, options);
|
|
1466
|
+
}
|
|
1467
|
+
var DropdownOption = class {
|
|
1468
|
+
constructor(ui, owner, index, value) {
|
|
1469
|
+
this.owner = owner;
|
|
1470
|
+
this.index = index;
|
|
1471
|
+
this.root = ui.box(owner.optionProps[0]), this.text = label(ui, value, "body", sheet.text), this.root.append(this.text), this.root.on("tap", () => this.activate()), this.a11y = new A11y({ role: "button", label: value, selected: false, actions: ["activate"] }), this.a11y.apply(this.root);
|
|
1472
|
+
}
|
|
1473
|
+
mark(selected) {
|
|
1474
|
+
this.root.style(this.owner.optionProps[selected ? 1 : 0]), this.text.style(this.owner.optionText[selected ? 1 : 0]), this.a11y.options.selected = selected, this.a11y.apply(this.root);
|
|
1475
|
+
}
|
|
1476
|
+
activate() {
|
|
1477
|
+
this.owner.choose(this.index, true);
|
|
1478
|
+
}
|
|
1479
|
+
}, Dropdown = class {
|
|
1480
|
+
constructor(ui, options) {
|
|
1481
|
+
this.options = options;
|
|
1482
|
+
this.chosen = -1;
|
|
1483
|
+
this.shown = false;
|
|
1484
|
+
this.onChange = options.onChange ?? null, this.navigator = options.navigator ?? null, this.optionProps = [ui.props(s3.option), ui.props(s3.option, s3.optionOn)];
|
|
1485
|
+
let body = fontStyle(ui, "body");
|
|
1486
|
+
this.optionText = [ui.props(body, sheet.text), ui.props(body, sheet.text, s3.onPrimary)], this.popups = [ui.props(s3.popup), ui.props(s3.popup, sheet.shown)], this.chevrons = [ui.props(s3.chevron), ui.props(s3.chevron, s3.chevronOpen)], this.root = ui.box(ui.props(s3.dropdown, { width: options.width ?? (200) }, options.style)), this.root.append(label(ui, options.label, "body", sheet.small)), this.field = ui.box(ui.props(s3.button, s3.field)), this.field.transition(["scale_x", "scale_y"], { duration: (0.12), easing: "back_out" }), this.current = label(ui, "", "body", s3.label), this.chevron = ui.box(this.chevrons[0]), this.chevron.transition(["rotate"], { duration: (0.18) }), this.field.append(this.current).append(this.chevron), this.popup = ui.box(this.popups[0]), this.scope = new UiFocusScope(1, () => (this.close(), true));
|
|
1487
|
+
let items = [];
|
|
1488
|
+
for (let i = 0; i < options.options.length; i++) {
|
|
1489
|
+
let item = new DropdownOption(ui, this, i, options.options[i]);
|
|
1490
|
+
this.popup.append(item.root), this.scope.add(item), items.push(item);
|
|
1491
|
+
}
|
|
1492
|
+
this.items = items, this.root.append(this.field).append(this.popup), this.field.on("tap", () => this.activate()), this.a11y = new A11y({ role: "button", label: options.label, value: "", disabled: options.disabled === true, actions: ["activate"] }), this.choose(options.selected ?? 0, false), this.popupA11y = new A11y({ role: "group", label: options.label, hidden: true, modal: false }), this.popupA11y.apply(this.popup), options.scope?.add(this);
|
|
1493
|
+
}
|
|
1494
|
+
get focusNode() {
|
|
1495
|
+
return this.field;
|
|
1496
|
+
}
|
|
1497
|
+
get selected() {
|
|
1498
|
+
return this.chosen;
|
|
1499
|
+
}
|
|
1500
|
+
get open() {
|
|
1501
|
+
return this.shown;
|
|
1502
|
+
}
|
|
1503
|
+
choose(index, notify) {
|
|
1504
|
+
let next = clamp(index, 0, this.items.length - 1);
|
|
1505
|
+
if (next !== this.chosen) {
|
|
1506
|
+
this.chosen >= 0 && this.items[this.chosen].mark(false), this.chosen = next, this.items[next].mark(true);
|
|
1507
|
+
let value = this.options.options[next];
|
|
1508
|
+
this.current.text(value), this.a11y.options.value = value, this.a11y.apply(this.field), notify && this.onChange?.(next);
|
|
1509
|
+
}
|
|
1510
|
+
notify && this.close();
|
|
1511
|
+
}
|
|
1512
|
+
activate() {
|
|
1513
|
+
this.a11y.options.disabled !== true && (this.shown ? this.close() : this.show());
|
|
1514
|
+
}
|
|
1515
|
+
show() {
|
|
1516
|
+
this.shown || (this.shown = true, this.popup.style(this.popups[1]), this.chevron.style(this.chevrons[1]), this.popupA11y.options.hidden = false, this.popupA11y.options.modal = true, this.popupA11y.apply(this.popup), this.scope.current = this.chosen, this.navigator?.push(this.scope));
|
|
1517
|
+
}
|
|
1518
|
+
close() {
|
|
1519
|
+
this.shown && (this.shown = false, this.popup.style(this.popups[0]), this.chevron.style(this.chevrons[0]), this.popupA11y.options.hidden = true, this.popupA11y.options.modal = false, this.popupA11y.apply(this.popup), this.navigator?.pop(this.scope));
|
|
1520
|
+
}
|
|
1521
|
+
setDisabled(disabled) {
|
|
1522
|
+
this.a11y.options.disabled !== disabled && (disabled && this.close(), this.a11y.options.disabled = disabled, this.a11y.apply(this.field));
|
|
1523
|
+
}
|
|
1524
|
+
move(move) {
|
|
1525
|
+
return this.shown || move !== "left" && move !== "right" ? false : (this.choose(this.chosen + (move === "left" ? -1 : 1), true), true);
|
|
1526
|
+
}
|
|
1527
|
+
};
|
|
1528
|
+
function dropdown(ui, options) {
|
|
1529
|
+
return new Dropdown(ui, options);
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
// src/interactives/game-ui/widgets/hud.ts
|
|
1533
|
+
var PULSE_SECONDS = 0.16, REMAIN = 0, PULSE = 1, TAU = Math.PI * 2, MINIMAP = 160, MARKER = 8, MARKER_KINDS = 4, NEEDLE_WIDTH = 4, NEEDLE_HEIGHT = 14, PLAYER = 10, RADIAL_RADIUS = 96, RADIAL_ITEM = 56, RADIAL_CENTER = 76, RADIAL_DEAD_ZONE = 18, RADIAL_ICON = 28, DIRECTION_SCALE = 1024, TRAVEL_SHIFT2 = 4, TRAVEL_SCALE2 = 1 << (4), DAMAGE_WIDTH = 120, HALF_DAMAGE_WIDTH = (120) / 2, DAMAGE_SECONDS = 0.9, DAMAGE_RISE = 56, DAMAGE_POP = 1.35, DAMAGE_Z = 700, DAMAGE_KINDS = 4, POP_SPEED = 4, CONFIG_SECONDS = 0, CONFIG_RISE = 1, BADGE = 20, BADGE_DOT = 10, BADGE_MAX = 99, BADGE_OFFSET = -6, s4 = styles({
|
|
1534
|
+
timer: {
|
|
1535
|
+
direction: "row",
|
|
1536
|
+
alignItems: "center",
|
|
1537
|
+
gap: kitVars.gapSmall,
|
|
1538
|
+
padding: [kitVars.gapSmall, kitVars.gap, kitVars.gapSmall, kitVars.gap],
|
|
1539
|
+
radius: kitVars.radius,
|
|
1540
|
+
fill: tokens.surface,
|
|
1541
|
+
borderWidth: kitVars.borderWidth,
|
|
1542
|
+
borderColor: tokens.border,
|
|
1543
|
+
scale: 1
|
|
1544
|
+
},
|
|
1545
|
+
timerWarn: { fill: tokens.danger, borderColor: tokens.danger },
|
|
1546
|
+
timerPulse: { scale: 1.12 },
|
|
1547
|
+
timerText: { fontSize: kitVars.title, fontWeight: 800, textColor: tokens.text, pointerEvents: "none" },
|
|
1548
|
+
timerTextWarn: { textColor: kitVars.onDanger },
|
|
1549
|
+
map: { position: "relative", clip: true, fill: tokens.surface, borderWidth: 3, borderColor: tokens.border, shadow: { color: kitVars.shadow, y: 4, blur: 12 } },
|
|
1550
|
+
mapImage: { position: "absolute", left: 0, top: 0, pointerEvents: "none" },
|
|
1551
|
+
pan: { translate: [0, 0] },
|
|
1552
|
+
marker: { position: "absolute", left: "50%", top: "50%", width: (8), height: (8), marginLeft: -(8) / 2, marginTop: -(8) / 2, radius: (8) / 2, borderWidth: 1, borderColor: tokens.surface, pointerEvents: "none", hidden: true },
|
|
1553
|
+
markerShown: { hidden: false },
|
|
1554
|
+
markerAt: { translate: [0, 0] },
|
|
1555
|
+
markerAccent: { fill: tokens.accent },
|
|
1556
|
+
markerDanger: { fill: tokens.danger },
|
|
1557
|
+
markerSuccess: { fill: tokens.success },
|
|
1558
|
+
markerGold: { fill: tokens.gold },
|
|
1559
|
+
player: { position: "absolute", left: "50%", top: "50%", width: (10), height: (10), marginLeft: -(10) / 2, marginTop: -(10) / 2, radius: (10) / 2, fill: tokens.text, borderWidth: 2, borderColor: tokens.accent, pointerEvents: "none" },
|
|
1560
|
+
needle: { position: "absolute", left: "50%", top: "50%", width: (4), height: (14), marginLeft: -(4) / 2, marginTop: -(14), radius: (4) / 2, fill: tokens.accent, origin: [0.5, 1], pointerEvents: "none" },
|
|
1561
|
+
heading: { rotate: 0 },
|
|
1562
|
+
compass: { position: "absolute", top: 4, left: 0, right: 0, textAlign: "center", fontSize: kitVars.small, fontWeight: 800, textColor: tokens.text, pointerEvents: "none" },
|
|
1563
|
+
radial: { position: "relative", alignItems: "center", justify: "center", scale: 0.6, opacity: 0, hidden: true },
|
|
1564
|
+
radialOpen: { scale: 1, opacity: 1, hidden: false },
|
|
1565
|
+
radialItem: {
|
|
1566
|
+
position: "absolute",
|
|
1567
|
+
left: "50%",
|
|
1568
|
+
top: "50%",
|
|
1569
|
+
width: (56),
|
|
1570
|
+
height: (56),
|
|
1571
|
+
marginLeft: -(56) / 2,
|
|
1572
|
+
marginTop: -(56) / 2,
|
|
1573
|
+
radius: (56) / 2,
|
|
1574
|
+
alignItems: "center",
|
|
1575
|
+
justify: "center",
|
|
1576
|
+
fill: tokens.raised,
|
|
1577
|
+
borderWidth: kitVars.focusWidth,
|
|
1578
|
+
borderColor: tokens.border,
|
|
1579
|
+
scale: 1
|
|
1580
|
+
},
|
|
1581
|
+
radialItemOn: { fill: tokens.accent, borderColor: kitVars.focus, scale: 1.15 },
|
|
1582
|
+
radialIcon: { width: (28), height: (28), pointerEvents: "none" },
|
|
1583
|
+
radialCenter: { width: (76), height: (76), radius: (76) / 2, alignItems: "center", justify: "center", padding: kitVars.gapSmall, fill: tokens.surface, borderWidth: kitVars.borderWidth, borderColor: tokens.border, pointerEvents: "none" },
|
|
1584
|
+
damage: { position: "absolute", left: 0, top: 0, width: (120), textAlign: "center", fontSize: kitVars.title, fontWeight: 800, textColor: tokens.text, pointerEvents: "none", hidden: true },
|
|
1585
|
+
damageShown: { hidden: false },
|
|
1586
|
+
damageCrit: { textColor: tokens.gold, fontSize: kitVars.display },
|
|
1587
|
+
damageHeal: { textColor: tokens.success },
|
|
1588
|
+
damageMiss: { textColor: tokens.muted },
|
|
1589
|
+
float: { translate: [0, 0], opacity: 1, scale: 1 },
|
|
1590
|
+
badge: {
|
|
1591
|
+
position: "absolute",
|
|
1592
|
+
top: (-6),
|
|
1593
|
+
right: (-6),
|
|
1594
|
+
minWidth: (20),
|
|
1595
|
+
height: (20),
|
|
1596
|
+
padding: [0, 5, 0, 5],
|
|
1597
|
+
radius: (20) / 2,
|
|
1598
|
+
alignItems: "center",
|
|
1599
|
+
justify: "center",
|
|
1600
|
+
fill: tokens.danger,
|
|
1601
|
+
borderWidth: 2,
|
|
1602
|
+
borderColor: tokens.surface,
|
|
1603
|
+
pointerEvents: "none",
|
|
1604
|
+
scale: 1
|
|
1605
|
+
},
|
|
1606
|
+
badgeDot: { minWidth: (10), width: (10), height: (10), padding: 0, top: -2, right: -2 },
|
|
1607
|
+
badgeBump: { scale: 1.3 },
|
|
1608
|
+
badgeText: { fontSize: 11, fontWeight: 800, textColor: kitVars.onDanger, pointerEvents: "none" }
|
|
1609
|
+
}, {
|
|
1610
|
+
pan: slotWords({ translate: [slot(0), slot(1)] }),
|
|
1611
|
+
markerAt: slotWords({ translate: [slot(0), slot(1)] }),
|
|
1612
|
+
heading: slotWords({ rotate: slot(0) }),
|
|
1613
|
+
float: slotWords({ translate: [slot(0), slot(1)], opacity: slot(2), scale: slot(3) })
|
|
1614
|
+
}), Countdown = class {
|
|
1615
|
+
constructor(ui, options) {
|
|
1616
|
+
this.ui = ui;
|
|
1617
|
+
this.clock = new Float64Array(2);
|
|
1618
|
+
this.shown = -1;
|
|
1619
|
+
this.warned = false;
|
|
1620
|
+
this.mode = options.mode ?? "down", this.warnAt = options.warnAt ?? 0, this.onExpire = options.onExpire ?? null, this.clock[(0)] = this.mode === "down" ? options.seconds : 0, this.active = options.autostart ?? true, this.roots = [ui.props(s4.timer, options.style), ui.props(s4.timer, options.style, s4.timerWarn), ui.props(s4.timer, options.style, s4.timerWarn, s4.timerPulse)];
|
|
1621
|
+
let mono = fontStyle(ui, "mono");
|
|
1622
|
+
this.texts = [ui.props(mono, s4.timerText), ui.props(mono, s4.timerText, s4.timerTextWarn)], this.root = ui.box(this.roots[0]), this.root.transition(["scale_x", "scale_y", "fill"], { duration: (0.16), easing: "back_out" }), this.text = ui.text("", this.texts[0]), this.root.append(this.text), this.root.accessibility({ role: "text", label: options.label ?? "Timer" }), this.render();
|
|
1623
|
+
}
|
|
1624
|
+
get remaining() {
|
|
1625
|
+
return this.clock[(0)];
|
|
1626
|
+
}
|
|
1627
|
+
get running() {
|
|
1628
|
+
return this.active;
|
|
1629
|
+
}
|
|
1630
|
+
get warning() {
|
|
1631
|
+
return this.warned;
|
|
1632
|
+
}
|
|
1633
|
+
start(seconds) {
|
|
1634
|
+
this.clock[(0)] = this.mode === "down" ? seconds : 0, this.active = true, this.render();
|
|
1635
|
+
}
|
|
1636
|
+
pause() {
|
|
1637
|
+
this.active = false;
|
|
1638
|
+
}
|
|
1639
|
+
resume() {
|
|
1640
|
+
this.active = true;
|
|
1641
|
+
}
|
|
1642
|
+
add(seconds) {
|
|
1643
|
+
let c = this.clock;
|
|
1644
|
+
c[(0)] = Math.max(0, c[(0)] + seconds), this.render();
|
|
1645
|
+
}
|
|
1646
|
+
update(frame) {
|
|
1647
|
+
let dt = frame[1], c = this.clock;
|
|
1648
|
+
if (c[(1)] > 0 && (c[(1)] -= dt, c[(1)] <= 0 && this.root.style(this.roots[this.warned ? 1 : 0])), !!this.active) {
|
|
1649
|
+
if (this.mode === "up") c[(0)] += dt;
|
|
1650
|
+
else if (c[(0)] -= dt, c[(0)] <= 0) {
|
|
1651
|
+
c[(0)] = 0, this.active = false, this.render(), this.onExpire?.();
|
|
1652
|
+
return;
|
|
1653
|
+
}
|
|
1654
|
+
this.render();
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
render() {
|
|
1658
|
+
let c = this.clock, truncated = c[(0)] | 0, whole = this.mode === "down" && truncated < c[(0)] ? truncated + 1 : truncated;
|
|
1659
|
+
if (whole === this.shown) return;
|
|
1660
|
+
this.shown = whole, this.text.number(whole, TIMER);
|
|
1661
|
+
let warn = this.mode === "down" && this.warnAt > 0 && c[(0)] <= this.warnAt && c[(0)] > 0;
|
|
1662
|
+
warn !== this.warned && (this.warned = warn, this.text.style(this.texts[warn ? 1 : 0])), warn ? (this.root.style(this.roots[2]), c[(1)] = (0.16)) : this.root.style(this.roots[0]);
|
|
1663
|
+
}
|
|
1664
|
+
};
|
|
1665
|
+
function countdown(ui, options) {
|
|
1666
|
+
return new Countdown(ui, options);
|
|
1667
|
+
}
|
|
1668
|
+
var MAP_PAN_X = 0, MAP_PAN_Y = 1, MAP_HEADING = 2, MARKER_INDEX = { accent: 0, danger: 1, success: 2, gold: 3 }, Minimap = class {
|
|
1669
|
+
constructor(ui, options) {
|
|
1670
|
+
this.ui = ui;
|
|
1671
|
+
this.view = new Float64Array(3);
|
|
1672
|
+
this.size = options.size ?? (160);
|
|
1673
|
+
let map = options.mapSize ?? [this.size, this.size], radius = (options.shape ?? "circle") === "circle" ? this.size / 2 : 12;
|
|
1674
|
+
this.root = ui.box(ui.props(s4.map, { width: this.size, height: this.size, radius }, options.style)), this.imageBase = ui.props(s4.mapImage, { width: map[0], height: map[1] }), SLOTS[0] = 0, SLOTS[1] = 0, this.image = ui.image(options.asset, options.natural, ui.props(this.imageBase, s4.pan.setSlotsFrom(SLOTS))), this.root.append(this.image);
|
|
1675
|
+
let kindStates = [s4.markerAccent, s4.markerDanger, s4.markerSuccess, s4.markerGold], states = [];
|
|
1676
|
+
for (let i = 0; i < (4); i++) states.push(ui.props(s4.marker, kindStates[i], s4.markerShown));
|
|
1677
|
+
this.markerStates = states, this.hiddenMarker = ui.props(s4.marker);
|
|
1678
|
+
let count2 = options.markers ?? 8;
|
|
1679
|
+
this.kinds = new Int8Array(count2).fill(-1), this.shown = new Uint8Array(count2), this.points = new Float64Array(count2 * 2);
|
|
1680
|
+
let markers = [];
|
|
1681
|
+
for (let i = 0; i < count2; i++) {
|
|
1682
|
+
let marker = ui.box(this.hiddenMarker);
|
|
1683
|
+
this.root.append(marker), markers.push(marker);
|
|
1684
|
+
}
|
|
1685
|
+
this.markers = markers, this.needle = ui.box(ui.props(s4.needle, s4.heading.setSlotsFrom(SLOTS))), this.root.append(this.needle).append(ui.box(s4.player)), (options.compass ?? true) && this.root.append(label(ui, "N", "display", s4.compass)), this.root.accessibility({ role: "image", label: options.label ?? "Minimap" });
|
|
1686
|
+
}
|
|
1687
|
+
setImage(asset, width, height) {
|
|
1688
|
+
this.image.image(asset, width, height);
|
|
1689
|
+
}
|
|
1690
|
+
pan(x, y) {
|
|
1691
|
+
this.view[(0)] = x, this.view[(1)] = y, this.writePan();
|
|
1692
|
+
}
|
|
1693
|
+
heading(radians) {
|
|
1694
|
+
this.view[(2)] = radians, this.writeHeading();
|
|
1695
|
+
}
|
|
1696
|
+
marker(index, x, y, kind = "accent") {
|
|
1697
|
+
this.points[index * 2] = x, this.points[index * 2 + 1] = y, this.kinds[index] = MARKER_INDEX[kind], this.place(index);
|
|
1698
|
+
}
|
|
1699
|
+
setMarkerKind(index, kind) {
|
|
1700
|
+
this.kinds[index] = MARKER_INDEX[kind];
|
|
1701
|
+
}
|
|
1702
|
+
hideMarker(index) {
|
|
1703
|
+
this.kinds[index] = -1, this.place(index);
|
|
1704
|
+
}
|
|
1705
|
+
apply() {
|
|
1706
|
+
this.writePan(), this.writeHeading();
|
|
1707
|
+
for (let i = 0; i < this.markers.length; i++) this.place(i);
|
|
1708
|
+
}
|
|
1709
|
+
writePan() {
|
|
1710
|
+
SLOTS[0] = this.view[(0)], SLOTS[1] = this.view[(1)], this.image.style(this.ui.props(this.imageBase, s4.pan.setSlotsFrom(SLOTS)));
|
|
1711
|
+
}
|
|
1712
|
+
writeHeading() {
|
|
1713
|
+
SLOTS[0] = this.view[(2)], this.needle.style(this.ui.props(s4.needle, s4.heading.setSlotsFrom(SLOTS)));
|
|
1714
|
+
}
|
|
1715
|
+
place(index) {
|
|
1716
|
+
let half = this.size * (0.5), x = this.points[index * 2], y = this.points[index * 2 + 1], k = this.kinds[index];
|
|
1717
|
+
if (k < 0 || x < -half || x > half || y < -half || y > half) {
|
|
1718
|
+
if (this.shown[index] === 0) return;
|
|
1719
|
+
this.shown[index] = 0, this.markers[index].style(this.hiddenMarker);
|
|
1720
|
+
return;
|
|
1721
|
+
}
|
|
1722
|
+
this.shown[index] = 1, SLOTS[0] = x, SLOTS[1] = y, this.markers[index].style(this.ui.props(this.markerStates[k], s4.markerAt.setSlotsFrom(SLOTS)));
|
|
1723
|
+
}
|
|
1724
|
+
};
|
|
1725
|
+
function minimap(ui, options) {
|
|
1726
|
+
return new Minimap(ui, options);
|
|
1727
|
+
}
|
|
1728
|
+
var RadialMenu = class {
|
|
1729
|
+
constructor(ui, options) {
|
|
1730
|
+
this.ui = ui;
|
|
1731
|
+
this.chosen = -1;
|
|
1732
|
+
this.shown = false;
|
|
1733
|
+
this.travel = new Int32Array(2);
|
|
1734
|
+
this.onSelect = options.onSelect ?? null, this.deadZone = options.deadZone ?? (18), this.directions = new Int32Array(options.items.length * 2);
|
|
1735
|
+
let radius = options.radius ?? (96), span = radius * 2 + (56), sized = { width: span, height: span };
|
|
1736
|
+
this.states = [ui.props(s4.radial, sized), ui.props(s4.radial, sized, s4.radialOpen)], this.root = ui.box(this.states[0]), this.root.transition(["scale_x", "scale_y", "opacity"], { duration: (0.18), easing: "back_out" });
|
|
1737
|
+
let count2 = options.items.length, items = [], itemStates = [], labels = [];
|
|
1738
|
+
for (let i = 0; i < count2; i++) {
|
|
1739
|
+
let angle = -Math.PI / 2 + i / count2 * TAU;
|
|
1740
|
+
this.directions[i * 2] = Math.round(Math.cos(angle) * (1024)), this.directions[i * 2 + 1] = Math.round(Math.sin(angle) * (1024));
|
|
1741
|
+
let at = { translate: [Math.cos(angle) * radius, Math.sin(angle) * radius] }, pair = [ui.props(s4.radialItem, at), ui.props(s4.radialItem, at, s4.radialItemOn)], item = ui.box(pair[0]);
|
|
1742
|
+
item.transition(["scale_x", "scale_y", "fill"], { duration: (0.12), easing: "back_out" });
|
|
1743
|
+
let entry = options.items[i];
|
|
1744
|
+
entry.icon !== void 0 ? item.append(ui.image(entry.icon, entry.natural ?? [(28), (28)], s4.radialIcon)) : item.append(label(ui, entry.label.slice(0, 2), "display", sheet.text, sheet.strong)), item.on("tap", () => {
|
|
1745
|
+
this.select(i), this.confirm();
|
|
1746
|
+
}), item.accessibility({ role: "button", label: entry.label, actions: ["activate"] }), this.root.append(item), items.push(item), itemStates.push(pair), labels.push(entry.label);
|
|
1747
|
+
}
|
|
1748
|
+
this.items = items, this.itemStates = itemStates, this.labels = labels;
|
|
1749
|
+
let hub = ui.box(s4.radialCenter);
|
|
1750
|
+
this.center = label(ui, "", "body", sheet.small, sheet.center, sheet.wrap), hub.append(this.center), this.root.append(hub), this.root.on("drag_start", () => {
|
|
1751
|
+
this.travel[0] = 0, this.travel[1] = 0;
|
|
1752
|
+
}), this.root.on("drag_move", (event) => {
|
|
1753
|
+
this.travel[0] += event.dx * TRAVEL_SCALE2 | 0, this.travel[1] += event.dy * TRAVEL_SCALE2 | 0, this.aim();
|
|
1754
|
+
}), this.root.on("drag_end", () => this.confirm()), this.a11y = new A11y({ role: "group", label: options.label ?? "Radial menu", hidden: true }), this.a11y.apply(this.root), options.scope?.add(this);
|
|
1755
|
+
}
|
|
1756
|
+
get open() {
|
|
1757
|
+
return this.shown;
|
|
1758
|
+
}
|
|
1759
|
+
get selected() {
|
|
1760
|
+
return this.chosen;
|
|
1761
|
+
}
|
|
1762
|
+
show() {
|
|
1763
|
+
this.shown || (this.shown = true, this.root.style(this.states[1]), this.a11y.options.hidden = false, this.a11y.apply(this.root));
|
|
1764
|
+
}
|
|
1765
|
+
hide() {
|
|
1766
|
+
this.shown && (this.shown = false, this.select(-1), this.root.style(this.states[0]), this.a11y.options.hidden = true, this.a11y.apply(this.root));
|
|
1767
|
+
}
|
|
1768
|
+
point(dx, dy) {
|
|
1769
|
+
this.travel[0] = dx * TRAVEL_SCALE2 | 0, this.travel[1] = dy * TRAVEL_SCALE2 | 0, this.aim();
|
|
1770
|
+
}
|
|
1771
|
+
aim() {
|
|
1772
|
+
let x = this.travel[0] >> (4), y = this.travel[1] >> (4);
|
|
1773
|
+
if (x * x + y * y < this.deadZone * this.deadZone) {
|
|
1774
|
+
this.select(-1);
|
|
1775
|
+
return;
|
|
1776
|
+
}
|
|
1777
|
+
let directions = this.directions, best = 0, score = x * directions[0] + y * directions[1];
|
|
1778
|
+
for (let i = 1; i < this.items.length; i++) {
|
|
1779
|
+
let next = x * directions[i * 2] + y * directions[i * 2 + 1];
|
|
1780
|
+
next > score && (score = next, best = i);
|
|
1781
|
+
}
|
|
1782
|
+
this.select(best);
|
|
1783
|
+
}
|
|
1784
|
+
select(index) {
|
|
1785
|
+
index !== this.chosen && (this.chosen >= 0 && this.items[this.chosen].style(this.itemStates[this.chosen][0]), this.chosen = index, index >= 0 ? (this.items[index].style(this.itemStates[index][1]), this.center.text(this.labels[index])) : this.center.text(""));
|
|
1786
|
+
}
|
|
1787
|
+
confirm() {
|
|
1788
|
+
let index = this.chosen;
|
|
1789
|
+
return this.hide(), index >= 0 && this.onSelect?.(index), index;
|
|
1790
|
+
}
|
|
1791
|
+
activate() {
|
|
1792
|
+
this.shown ? this.confirm() : this.show();
|
|
1793
|
+
}
|
|
1794
|
+
move(move) {
|
|
1795
|
+
if (!this.shown) return false;
|
|
1796
|
+
let count2 = this.items.length;
|
|
1797
|
+
if (move === "left" || move === "previous") this.select(((this.chosen < 0 ? 0 : this.chosen) - 1 + count2) % count2);
|
|
1798
|
+
else if (move === "right" || move === "next") this.select(((this.chosen < 0 ? -1 : this.chosen) + 1) % count2);
|
|
1799
|
+
else return false;
|
|
1800
|
+
return true;
|
|
1801
|
+
}
|
|
1802
|
+
};
|
|
1803
|
+
function radialMenu(ui, options) {
|
|
1804
|
+
return new RadialMenu(ui, options);
|
|
1805
|
+
}
|
|
1806
|
+
var DAMAGE_INDEX = { hit: 0, crit: 1, heal: 2, miss: 3 }, DamageNumbers = class {
|
|
1807
|
+
constructor(ui, options = {}) {
|
|
1808
|
+
this.ui = ui;
|
|
1809
|
+
this.config = new Float64Array(2);
|
|
1810
|
+
this.cursor = 0;
|
|
1811
|
+
this.live = 0;
|
|
1812
|
+
let capacity = options.capacity ?? 24;
|
|
1813
|
+
this.config[(0)] = options.seconds ?? (0.9), this.config[(1)] = options.rise ?? (56), this.x = new Float32Array(capacity), this.y = new Float32Array(capacity), this.age = new Float32Array(capacity), this.kind = new Int8Array(capacity).fill(-1);
|
|
1814
|
+
let display = fontStyle(ui, "display"), kinds = [null, s4.damageCrit, s4.damageHeal, s4.damageMiss], states = [];
|
|
1815
|
+
for (let i = 0; i < (4); i++) states.push(ui.props(display, s4.damage, kinds[i], s4.damageShown));
|
|
1816
|
+
this.states = states, this.hidden = ui.props(display, s4.damage), this.root = ui.box(sheet.layer);
|
|
1817
|
+
let entries = [];
|
|
1818
|
+
for (let i = 0; i < capacity; i++) {
|
|
1819
|
+
let entry = ui.text("", this.hidden);
|
|
1820
|
+
this.root.append(entry), entries.push(entry);
|
|
1821
|
+
}
|
|
1822
|
+
this.entries = entries;
|
|
1823
|
+
let rooting = { anchor: "fill", safe_area: false, z: options.z ?? (700) };
|
|
1824
|
+
ui.root(this.root, rooting), this.root.accessibility({ role: "none", hidden: true });
|
|
1825
|
+
}
|
|
1826
|
+
get active() {
|
|
1827
|
+
return this.live;
|
|
1828
|
+
}
|
|
1829
|
+
spawn(value, x, y, kind = "hit") {
|
|
1830
|
+
let i = this.cursor;
|
|
1831
|
+
this.cursor = (i + 1) % this.entries.length, this.kind[i] < 0 && this.live++;
|
|
1832
|
+
let k = DAMAGE_INDEX[kind];
|
|
1833
|
+
this.kind[i] = k, this.x[i] = x - HALF_DAMAGE_WIDTH, this.y[i] = y, this.age[i] = 0;
|
|
1834
|
+
let entry = this.entries[i];
|
|
1835
|
+
entry.number(value, PLAIN), SLOTS[0] = x - HALF_DAMAGE_WIDTH, SLOTS[1] = y, SLOTS[2] = 1, SLOTS[3] = k === 1 ? (1.35) : 1, entry.style(this.ui.props(this.states[k], s4.float.setSlotsFrom(SLOTS)));
|
|
1836
|
+
}
|
|
1837
|
+
update(frame) {
|
|
1838
|
+
if (this.live === 0) return;
|
|
1839
|
+
let dt = frame[1], ui = this.ui, config = this.config;
|
|
1840
|
+
for (let i = 0; i < this.entries.length; i++) {
|
|
1841
|
+
let k = this.kind[i];
|
|
1842
|
+
if (k < 0) continue;
|
|
1843
|
+
let age = this.age[i] + dt;
|
|
1844
|
+
if (age >= config[(0)]) {
|
|
1845
|
+
this.kind[i] = -1, this.live--, this.entries[i].style(this.hidden);
|
|
1846
|
+
continue;
|
|
1847
|
+
}
|
|
1848
|
+
this.age[i] = age;
|
|
1849
|
+
let p = age / config[(0)], rest = 1 - p, pop = 1 - p * (4);
|
|
1850
|
+
SLOTS[0] = this.x[i], SLOTS[1] = this.y[i] - config[(1)] * (1 - rest * rest), SLOTS[2] = 1 - p * p * p, SLOTS[3] = k === 1 && pop > 0 ? 1 + ((1.35) - 1) * pop : 1, this.entries[i].style(ui.props(this.states[k], s4.float.setSlotsFrom(SLOTS)));
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
clear() {
|
|
1854
|
+
for (let i = 0; i < this.entries.length; i++)
|
|
1855
|
+
this.kind[i] < 0 || (this.kind[i] = -1, this.entries[i].style(this.hidden));
|
|
1856
|
+
this.live = 0;
|
|
1857
|
+
}
|
|
1858
|
+
};
|
|
1859
|
+
function damageNumbers(ui, options = {}) {
|
|
1860
|
+
return new DamageNumbers(ui, options);
|
|
1861
|
+
}
|
|
1862
|
+
var Badge = class {
|
|
1863
|
+
constructor(ui, options) {
|
|
1864
|
+
this.ui = ui;
|
|
1865
|
+
this.current = -1;
|
|
1866
|
+
this.clock = new Float64Array(1);
|
|
1867
|
+
this.a11y = new A11y({ role: "text", label: "", hidden: true });
|
|
1868
|
+
this.max = options.max ?? (99), this.dot = options.dot ?? false, this.overflow = `${this.max}+`;
|
|
1869
|
+
let noun = options.label ?? "new";
|
|
1870
|
+
this.labels = Array.from({ length: this.max + 2 }, (_, i) => i > this.max ? `${this.max}+ ${noun}` : `${i} ${noun}`);
|
|
1871
|
+
let shape = this.dot ? s4.badgeDot : null;
|
|
1872
|
+
this.states = [ui.props(s4.badge, shape, sheet.hidden), ui.props(s4.badge, shape), ui.props(s4.badge, shape, s4.badgeBump)], this.root = ui.box(this.states[0]), this.root.transition(["scale_x", "scale_y"], { duration: (0.16), easing: "back_out" }), this.text = label(ui, "", "mono", s4.badgeText, this.dot ? sheet.hidden : null), this.root.append(this.text), options.host.append(this.root), this.set(options.count ?? 0);
|
|
1873
|
+
}
|
|
1874
|
+
get count() {
|
|
1875
|
+
return this.current;
|
|
1876
|
+
}
|
|
1877
|
+
set(count2) {
|
|
1878
|
+
let next = Math.max(0, Math.floor(count2));
|
|
1879
|
+
if (next === this.current) return;
|
|
1880
|
+
let grew = next > this.current && this.current >= 0;
|
|
1881
|
+
this.current = next, this.dot || (next > this.max ? this.text.text(this.overflow) : this.text.number(next, PLAIN)), this.a11y.options.label = this.labels[Math.min(next, this.max + 1)], this.a11y.options.hidden = next === 0, this.a11y.apply(this.root), next === 0 ? (this.clock[0] = 0, this.root.style(this.states[0])) : grew ? (this.clock[0] = (0.16), this.root.style(this.states[2])) : this.root.style(this.states[1]);
|
|
1882
|
+
}
|
|
1883
|
+
update(frame) {
|
|
1884
|
+
let clock = this.clock;
|
|
1885
|
+
clock[0] <= 0 || (clock[0] -= frame[1], clock[0] <= 0 && this.current > 0 && this.root.style(this.states[1]));
|
|
1886
|
+
}
|
|
1887
|
+
};
|
|
1888
|
+
function badge(ui, options) {
|
|
1889
|
+
return new Badge(ui, options);
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1892
|
+
// src/interactives/game-ui/widgets/overlay.ts
|
|
1893
|
+
var MODAL_Z = 800, MODAL_WIDTH = 340, ENTER_SCALE = 0.94, TOOLTIP_SECONDS = 2.5, TOOLTIP_Z = 60, ARROW = 10, TOOLTIP_MAX = 240, s5 = styles({
|
|
1894
|
+
layer: { width: "100%", height: "100%", alignItems: "center", justify: "center", fill: kitVars.scrim, opacity: 0, hidden: true },
|
|
1895
|
+
layerShown: { opacity: 1, hidden: false },
|
|
1896
|
+
card: {
|
|
1897
|
+
width: (340),
|
|
1898
|
+
maxWidth: "92%",
|
|
1899
|
+
padding: kitVars.padding,
|
|
1900
|
+
gap: kitVars.gap,
|
|
1901
|
+
fill: tokens.surface,
|
|
1902
|
+
radius: kitVars.radius,
|
|
1903
|
+
borderWidth: kitVars.borderWidth,
|
|
1904
|
+
borderColor: tokens.border,
|
|
1905
|
+
shadow: { color: kitVars.shadow, y: 12, blur: 32 },
|
|
1906
|
+
scale: (0.94)
|
|
1907
|
+
},
|
|
1908
|
+
cardShown: { scale: 1 },
|
|
1909
|
+
content: { gap: kitVars.gap, alignItems: "stretch" },
|
|
1910
|
+
tipAnchor: { position: "absolute", left: 0, right: 0, alignItems: "center", pointerEvents: "none", zIndex: (60), opacity: 0, hidden: true },
|
|
1911
|
+
above: { bottom: "100%", marginBottom: kitVars.gapSmall },
|
|
1912
|
+
below: { top: "100%", marginTop: kitVars.gapSmall },
|
|
1913
|
+
tipShown: { opacity: 1, hidden: false },
|
|
1914
|
+
bubble: { maxWidth: (240), padding: [kitVars.gapSmall, kitVars.gap, kitVars.gapSmall, kitVars.gap], fill: tokens.raised, radius: kitVars.radiusSmall, borderWidth: kitVars.borderWidth, borderColor: tokens.border, shadow: { color: kitVars.shadow, y: 4, blur: 12 } },
|
|
1915
|
+
arrow: { width: (10), height: (10), fill: tokens.raised, rotate: Math.PI / 4, marginTop: -(10) / 2, marginBottom: -(10) / 2 }
|
|
1916
|
+
}), Modal = class {
|
|
1917
|
+
constructor(ui, options = {}) {
|
|
1918
|
+
this.ui = ui;
|
|
1919
|
+
this.onClose = null;
|
|
1920
|
+
this.stack = null;
|
|
1921
|
+
this.dismissible = options.dismissible ?? true, this.layers = [ui.props(s5.layer), ui.props(s5.layer, s5.layerShown)], this.cards = [ui.props(s5.card, options.style), ui.props(s5.card, options.style, s5.cardShown)], this.layer = ui.box(this.layers[0]), this.layer.transition(["opacity"], { duration: (0.18), easing: "ease_out" }), this.root = ui.box(this.cards[0]), this.root.transition(["scale_x", "scale_y"], { duration: (0.18), easing: "back_out" }), this.title = options.title === void 0 ? null : label(ui, options.title, "display", sheet.title, sheet.center), this.title !== null && this.root.append(this.title), this.content = ui.box(s5.content), this.root.append(this.content), this.layer.append(this.root), this.scope = new UiFocusScope(options.columns ?? 1, () => this.stack?.back() ?? false), this.a11y = new A11y({ role: "group", label: options.title ?? "", hidden: true, modal: false }), this.a11y.apply(this.root);
|
|
1922
|
+
}
|
|
1923
|
+
add(target) {
|
|
1924
|
+
return this.scope.add(target), this;
|
|
1925
|
+
}
|
|
1926
|
+
append(element) {
|
|
1927
|
+
return this.content.append(element), this;
|
|
1928
|
+
}
|
|
1929
|
+
get open() {
|
|
1930
|
+
return this.stack !== null;
|
|
1931
|
+
}
|
|
1932
|
+
shown(on, top) {
|
|
1933
|
+
this.layer.style(this.layers[on ? 1 : 0]), this.root.style(this.cards[on ? 1 : 0]), this.a11y.options.hidden = !on || !top, this.a11y.options.modal = on && top, this.a11y.options.disabled = on && !top, this.a11y.apply(this.root);
|
|
1934
|
+
}
|
|
1935
|
+
};
|
|
1936
|
+
function modal(ui, options = {}) {
|
|
1937
|
+
return new Modal(ui, options);
|
|
1938
|
+
}
|
|
1939
|
+
var ModalStack = class {
|
|
1940
|
+
constructor(ui, options = {}) {
|
|
1941
|
+
this.ui = ui;
|
|
1942
|
+
this.modals = new StableList();
|
|
1943
|
+
this.rooting = { anchor: "fill", safe_area: false, z: 0 };
|
|
1944
|
+
this.navigator = options.navigator ?? null, this.inert = options.inert ?? [], this.z = options.z ?? (800);
|
|
1945
|
+
}
|
|
1946
|
+
get depth() {
|
|
1947
|
+
return this.modals.size;
|
|
1948
|
+
}
|
|
1949
|
+
get top() {
|
|
1950
|
+
return this.modals.size === 0 ? null : this.modals.at(this.modals.size - 1);
|
|
1951
|
+
}
|
|
1952
|
+
contains(modal2) {
|
|
1953
|
+
return this.modals.indexOf(modal2) >= 0;
|
|
1954
|
+
}
|
|
1955
|
+
push(modal2) {
|
|
1956
|
+
if (modal2.stack !== null) return;
|
|
1957
|
+
let below = this.top;
|
|
1958
|
+
if (below !== null) below.shown(true, false);
|
|
1959
|
+
else for (let i = 0; i < this.inert.length; i++) this.inert[i].setState("disabled", true);
|
|
1960
|
+
this.modals.push(modal2), modal2.stack = this, this.rooting.z = this.z + this.modals.size, this.ui.root(modal2.layer, this.rooting), modal2.shown(true, true), modal2.scope.current = -1, this.navigator?.push(modal2.scope);
|
|
1961
|
+
}
|
|
1962
|
+
pop() {
|
|
1963
|
+
let top = this.top;
|
|
1964
|
+
return top === null ? null : (this.remove(top), top);
|
|
1965
|
+
}
|
|
1966
|
+
remove(modal2) {
|
|
1967
|
+
let at = this.modals.indexOf(modal2);
|
|
1968
|
+
if (at < 0) return;
|
|
1969
|
+
this.modals.removeAt(at), modal2.stack = null, modal2.shown(false, false), this.ui.unroot(modal2.layer);
|
|
1970
|
+
let top = this.top;
|
|
1971
|
+
if (top !== null) top.shown(true, true);
|
|
1972
|
+
else for (let i = 0; i < this.inert.length; i++) this.inert[i].setState("disabled", false);
|
|
1973
|
+
this.navigator?.pop(modal2.scope), modal2.onClose?.();
|
|
1974
|
+
}
|
|
1975
|
+
clear() {
|
|
1976
|
+
for (; this.modals.size > 0; ) this.pop();
|
|
1977
|
+
}
|
|
1978
|
+
back() {
|
|
1979
|
+
let top = this.top;
|
|
1980
|
+
return top === null || !top.dismissible ? false : (this.remove(top), true);
|
|
1981
|
+
}
|
|
1982
|
+
};
|
|
1983
|
+
function modalStack(ui, options = {}) {
|
|
1984
|
+
return new ModalStack(ui, options);
|
|
1985
|
+
}
|
|
1986
|
+
var Tooltip = class {
|
|
1987
|
+
constructor(ui, options) {
|
|
1988
|
+
this.ui = ui;
|
|
1989
|
+
this.options = options;
|
|
1990
|
+
this.remaining = new Float64Array(2);
|
|
1991
|
+
this.pinned = false;
|
|
1992
|
+
this.visible = false;
|
|
1993
|
+
let above = (options.placement ?? "above") === "above", side = above ? s5.above : s5.below;
|
|
1994
|
+
this.states = [ui.props(s5.tipAnchor, side), ui.props(s5.tipAnchor, side, s5.tipShown)], this.remaining[1] = options.seconds ?? (2.5), this.root = ui.box(this.states[0]), this.root.transition(["opacity"], { duration: (0.18) }), this.bubble = ui.box(s5.bubble), this.text = label(ui, options.text, "body", sheet.small, sheet.wrap), this.bubble.append(this.text);
|
|
1995
|
+
let arrow = ui.box(s5.arrow);
|
|
1996
|
+
above ? this.root.append(this.bubble).append(arrow) : this.root.append(arrow).append(this.bubble), options.target.append(this.root), this.root.accessibility({ role: "text", label: options.text, hidden: true }), options.target.on("long_press", () => this.show()), options.navigator?.onChange((focused) => {
|
|
1997
|
+
focused !== null && focusNodeOf(focused) === options.target ? this.pin() : this.visible && this.pinned && this.hide();
|
|
1998
|
+
});
|
|
1999
|
+
}
|
|
2000
|
+
get shown() {
|
|
2001
|
+
return this.visible;
|
|
2002
|
+
}
|
|
2003
|
+
setText(value) {
|
|
2004
|
+
this.text.text(value);
|
|
2005
|
+
}
|
|
2006
|
+
show() {
|
|
2007
|
+
this.reveal(false);
|
|
2008
|
+
}
|
|
2009
|
+
pin() {
|
|
2010
|
+
this.reveal(true);
|
|
2011
|
+
}
|
|
2012
|
+
hide() {
|
|
2013
|
+
this.pinned = false, this.remaining[0] = 0, this.visible && (this.visible = false, this.root.style(this.states[0]));
|
|
2014
|
+
}
|
|
2015
|
+
update(frame) {
|
|
2016
|
+
if (!this.visible || this.pinned) return;
|
|
2017
|
+
let remaining = this.remaining;
|
|
2018
|
+
remaining[0] -= frame[1], remaining[0] <= 0 && this.hide();
|
|
2019
|
+
}
|
|
2020
|
+
reveal(pinned) {
|
|
2021
|
+
this.pinned = pinned, this.remaining.copyWithin(0, 1, 2), !this.visible && (this.visible = true, this.root.style(this.states[1]));
|
|
2022
|
+
}
|
|
2023
|
+
};
|
|
2024
|
+
function tooltip(ui, options) {
|
|
2025
|
+
return new Tooltip(ui, options);
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
// src/interactives/game-ui/widgets/particles.ts
|
|
2029
|
+
var CAPACITY = 64, PARTICLE_Z = 950, CONFETTI_W = 7, CONFETTI_H = 11, SPARKLE = 10, GRAVITY = 900, DRAG = 1.6, CONFETTI_SPEED = 520, SPARKLE_SPEED = 180, CONFETTI_LIFE = 1.6, SPARKLE_LIFE = 0.8, SPIN = 12, TWINKLE = 18, PALETTE = 6, KINDS = 2, CONFETTI = 0, SPARKLE_KIND = 1, DEAD = -1, SPREAD = Math.PI * 0.7, UP = -Math.PI / 2, TAU2 = Math.PI * 2, FADE_FROM = 0.7, SEED = 20973, TABLE_ROWS = 97, F_VX = 0, F_VY = 1, F_ANGLE = 2, F_SPIN = 3, F_LIFE = 4, F_X = 5, F_Y = 6, F_AGE = 7, STRIDE = 8, s6 = styles({
|
|
2030
|
+
confetti: { position: "absolute", left: 0, top: 0, width: (7), height: (11), marginLeft: -(7) / 2, marginTop: -(11) / 2, radius: 1, pointerEvents: "none", hidden: false },
|
|
2031
|
+
sparkle: { position: "absolute", left: 0, top: 0, width: (10), height: (10), marginLeft: -(10) / 2, marginTop: -(10) / 2, radius: (10) / 2, pointerEvents: "none", hidden: false, shadow: { color: tokens.gold, blur: 6 } },
|
|
2032
|
+
dead: { position: "absolute", hidden: true, pointerEvents: "none" },
|
|
2033
|
+
c0: { fill: tokens.accent },
|
|
2034
|
+
c1: { fill: tokens.gold },
|
|
2035
|
+
c2: { fill: tokens.success },
|
|
2036
|
+
c3: { fill: tokens.danger },
|
|
2037
|
+
c4: { fill: kitVars.focus },
|
|
2038
|
+
c5: { fill: tokens.text },
|
|
2039
|
+
piece: { translate: [0, 0], rotate: 0, opacity: 1 },
|
|
2040
|
+
glint: { translate: [0, 0], scale: 1, opacity: 1 }
|
|
2041
|
+
}, {
|
|
2042
|
+
piece: slotWords({ translate: [slot(0), slot(1)], rotate: slot(2), opacity: slot(3) }),
|
|
2043
|
+
glint: slotWords({ translate: [slot(0), slot(1)], scale: slot(2), opacity: slot(3) })
|
|
2044
|
+
});
|
|
2045
|
+
function fillLaunchTable(rng, data, colors) {
|
|
2046
|
+
for (let kind = 0; kind < (2); kind++) {
|
|
2047
|
+
let confetti = kind === (0);
|
|
2048
|
+
for (let r = 0; r < (97); r++) {
|
|
2049
|
+
let row = kind * (97) + r, o = row * (8), heading = confetti ? UP + rng.range(-SPREAD, SPREAD) : rng.range(0, TAU2), speed = (confetti ? (520) : (180)) * rng.range(0.45, 1);
|
|
2050
|
+
data[o + (0)] = Math.cos(heading) * speed, data[o + (1)] = Math.sin(heading) * speed, data[o + (2)] = rng.range(0, TAU2), data[o + (3)] = rng.range(-(12), (12)), data[o + (4)] = (confetti ? (1.6) : (0.8)) * rng.range(0.7, 1), colors[row] = rng.next() * (6) | 0;
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
var UiParticles = class {
|
|
2055
|
+
constructor(ui, options = {}) {
|
|
2056
|
+
this.ui = ui;
|
|
2057
|
+
this.launchColors = new Uint8Array((97) * (2));
|
|
2058
|
+
this.cursor = 0;
|
|
2059
|
+
this.row = 0;
|
|
2060
|
+
this.live = 0;
|
|
2061
|
+
let capacity = options.capacity ?? (64);
|
|
2062
|
+
this.data = new Float32Array(((97) * (2) + capacity) * (8)), this.kind = new Int8Array(capacity).fill((-1)), this.color = new Uint8Array(capacity), fillLaunchTable(new Rng(options.seed ?? (20973)), this.data, this.launchColors);
|
|
2063
|
+
let palette = [s6.c0, s6.c1, s6.c2, s6.c3, s6.c4, s6.c5], states = [];
|
|
2064
|
+
for (let kind = 0; kind < (2); kind++) for (let c = 0; c < (6); c++) states.push(ui.props(kind === (0) ? s6.confetti : s6.sparkle, palette[kind === (0) ? c : 1 + (c & 1) * 4]));
|
|
2065
|
+
this.states = states, this.dead = ui.props(s6.dead), this.root = ui.box(sheet.layer);
|
|
2066
|
+
let pieces = [];
|
|
2067
|
+
for (let i = 0; i < capacity; i++) {
|
|
2068
|
+
let piece = ui.box(this.dead);
|
|
2069
|
+
this.root.append(piece), pieces.push(piece);
|
|
2070
|
+
}
|
|
2071
|
+
this.pieces = pieces;
|
|
2072
|
+
let rooting = { anchor: "fill", safe_area: false, z: options.z ?? (950) };
|
|
2073
|
+
ui.root(this.root, rooting), this.root.accessibility({ role: "none", hidden: true });
|
|
2074
|
+
}
|
|
2075
|
+
get active() {
|
|
2076
|
+
return this.live;
|
|
2077
|
+
}
|
|
2078
|
+
burst(kind, x, y, count2) {
|
|
2079
|
+
let confetti = kind === "confetti", data = this.data, base = confetti ? 0 : (97);
|
|
2080
|
+
for (let n = 0; n < count2; n++) {
|
|
2081
|
+
let i = this.cursor;
|
|
2082
|
+
this.cursor = (i + 1) % this.pieces.length, this.kind[i] === (-1) && this.live++, this.kind[i] = confetti ? (0) : (1);
|
|
2083
|
+
let row = base + this.row;
|
|
2084
|
+
this.row = (this.row + 1) % (97);
|
|
2085
|
+
let o = ((97) * (2) + i) * (8);
|
|
2086
|
+
data.copyWithin(o, row * (8), row * (8) + (8)), data[o + (5)] = x, data[o + (6)] = y, data[o + (7)] = 0, this.color[i] = this.launchColors[row], this.draw(i);
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
update(frame) {
|
|
2090
|
+
if (this.live === 0) return;
|
|
2091
|
+
let dt = frame[1], damping = (1.6) * dt < 1 ? 1 - (1.6) * dt : 0, data = this.data;
|
|
2092
|
+
for (let i = 0; i < this.pieces.length; i++) {
|
|
2093
|
+
let kind = this.kind[i];
|
|
2094
|
+
if (kind === (-1)) continue;
|
|
2095
|
+
let o = ((97) * (2) + i) * (8), age = data[o + (7)] + dt;
|
|
2096
|
+
if (age >= data[o + (4)]) {
|
|
2097
|
+
this.kind[i] = (-1), this.live--, this.pieces[i].style(this.dead);
|
|
2098
|
+
continue;
|
|
2099
|
+
}
|
|
2100
|
+
data[o + (7)] = age, kind === (0) && (data[o + (1)] += (900) * dt), data[o + (0)] *= damping, data[o + (1)] *= damping, data[o + (5)] += data[o + (0)] * dt, data[o + (6)] += data[o + (1)] * dt, data[o + (2)] += data[o + (3)] * dt, this.draw(i);
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
clear() {
|
|
2104
|
+
for (let i = 0; i < this.pieces.length; i++)
|
|
2105
|
+
this.kind[i] !== (-1) && (this.kind[i] = (-1), this.pieces[i].style(this.dead));
|
|
2106
|
+
this.live = 0;
|
|
2107
|
+
}
|
|
2108
|
+
draw(i) {
|
|
2109
|
+
let kind = this.kind[i], data = this.data, o = ((97) * (2) + i) * (8), p = data[o + (7)] / data[o + (4)], state = this.states[kind * (6) + this.color[i]];
|
|
2110
|
+
if (SLOTS[0] = data[o + (5)], SLOTS[1] = data[o + (6)], SLOTS[3] = p < (0.7) ? 1 : 1 - (p - (0.7)) / (1 - (0.7)), kind === (0))
|
|
2111
|
+
SLOTS[2] = data[o + (2)], this.pieces[i].style(this.ui.props(state, s6.piece.setSlotsFrom(SLOTS)));
|
|
2112
|
+
else {
|
|
2113
|
+
let phase = data[o + (7)] * (18) + i, wave = phase - (phase | 0);
|
|
2114
|
+
SLOTS[2] = (0.6 + 0.8 * (wave < 0.5 ? wave : 1 - wave)) * (1 - p * 0.5), this.pieces[i].style(this.ui.props(state, s6.glint.setSlotsFrom(SLOTS)));
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
};
|
|
2118
|
+
function uiParticles(ui, options = {}) {
|
|
2119
|
+
return new UiParticles(ui, options);
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
// src/interactives/game-ui/widgets/screens.ts
|
|
2123
|
+
var STAR = 30, STARS = 3, STAR_SECONDS = 0.35, SCORE_SECONDS = 1.1, REWARD_ICON = 28, REWARDS = 3, SPINNER = 44, SPINNER_SPEED = Math.PI * 2, LOADING_BAR = 260, BAR_HEIGHT = 8, TIP_SECONDS = 4, LOADING_Z = 1200, HINT_Z = 900, HINT_WIDTH = 260, HINT_DOTS = 8, DOT = 7, ARROW2 = 16, BOB = 6, BOB_SPEED = 1, SPARKLES = 10, TURN = Math.PI * 2, SPIN2 = 0, TIP = 1, TIP_SECONDS_AT = 2, HINT_X = 0, HINT_Y = 1, HINT_CLOCK = 2, CONFETTI2 = 36, s7 = styles({
|
|
2124
|
+
actions: { direction: "row", gap: kitVars.gap, justify: "center" },
|
|
2125
|
+
grow: { grow: 1, basis: 0 },
|
|
2126
|
+
section: { fontSize: kitVars.small, fontWeight: 800, textColor: tokens.muted, letterSpacing: 1, pointerEvents: "none" },
|
|
2127
|
+
score: { textAlign: "center", fontSize: kitVars.display, fontWeight: 800, textColor: tokens.gold, pointerEvents: "none" },
|
|
2128
|
+
stars: { direction: "row", gap: kitVars.gap, justify: "center", padding: kitVars.gapSmall },
|
|
2129
|
+
star: { width: (30), height: (30), radius: 4, rotate: Math.PI / 4, fill: tokens.track, scale: 0.8 },
|
|
2130
|
+
starOn: { fill: tokens.gold, scale: 1, shadow: { color: tokens.gold, blur: 10 } },
|
|
2131
|
+
rewards: { direction: "row", gap: kitVars.gap, justify: "center", wrap: true },
|
|
2132
|
+
reward: { direction: "row", alignItems: "center", gap: kitVars.gapSmall, padding: [kitVars.gapSmall, kitVars.gap, kitVars.gapSmall, kitVars.gapSmall], radius: kitVars.radius, fill: tokens.raised, hidden: true },
|
|
2133
|
+
rewardShown: { hidden: false },
|
|
2134
|
+
rewardIcon: { width: (28), height: (28), pointerEvents: "none" },
|
|
2135
|
+
loading: { width: "100%", height: "100%", alignItems: "center", justify: "center", gap: kitVars.padding, padding: kitVars.padding, fill: tokens.surface, hidden: true, opacity: 0 },
|
|
2136
|
+
loadingShown: { hidden: false, opacity: 1 },
|
|
2137
|
+
spinner: { width: (44), height: (44), radius: (44) / 2, borderWidth: 4, borderColor: [tokens.accent, tokens.track, tokens.track, tokens.track] },
|
|
2138
|
+
spin: { rotate: 0 },
|
|
2139
|
+
bar: { width: (260), height: (8), radius: (8) / 2, fill: tokens.track, clip: true },
|
|
2140
|
+
barFill: { height: "100%", radius: (8) / 2, fill: tokens.accent },
|
|
2141
|
+
barTo: { width: "0%" },
|
|
2142
|
+
tip: { maxWidth: (260) + 80, textAlign: "center" },
|
|
2143
|
+
hint: { width: "100%", height: "100%", hidden: true },
|
|
2144
|
+
hintShown: { hidden: false },
|
|
2145
|
+
bubble: { position: "absolute", width: (260), gap: kitVars.gap, padding: kitVars.padding, fill: tokens.raised, radius: kitVars.radius, borderWidth: kitVars.borderWidth, borderColor: tokens.accent, shadow: { color: kitVars.shadow, y: 6, blur: 18 } },
|
|
2146
|
+
bubbleAt: { left: 0, top: 0 },
|
|
2147
|
+
dots: { direction: "row", gap: 4, alignItems: "center" },
|
|
2148
|
+
dot: { width: (7), height: (7), radius: (7) / 2, fill: tokens.track },
|
|
2149
|
+
dotOn: { fill: tokens.accent },
|
|
2150
|
+
dotHidden: { hidden: true },
|
|
2151
|
+
footer: { direction: "row", justify: "space-between", alignItems: "center" },
|
|
2152
|
+
arrow: { position: "absolute", width: (16), height: (16), rotate: Math.PI / 4, fill: tokens.accent, pointerEvents: "none" },
|
|
2153
|
+
arrowAt: { left: 0, top: 0 }
|
|
2154
|
+
}, {
|
|
2155
|
+
spin: slotWords({ rotate: slot(0) }),
|
|
2156
|
+
barTo: slotWords({ width: slot(0, true) }),
|
|
2157
|
+
bubbleAt: slotWords({ left: slot(0), top: slot(1) }),
|
|
2158
|
+
arrowAt: slotWords({ left: slot(0), top: slot(1) })
|
|
2159
|
+
}), PauseScreen = class {
|
|
2160
|
+
constructor(ui, options) {
|
|
2161
|
+
this.options = options;
|
|
2162
|
+
this.modal = new Modal(ui, { title: options.title ?? "Paused" }), this.resume = new TextButton(ui, { label: "Resume", variant: "primary", scope: this.modal.scope, onPress: () => this.close() }), this.settings = new TextButton(ui, { label: "Settings", scope: this.modal.scope, onPress: () => options.onSettings?.() }), this.quit = new TextButton(ui, { label: "Quit", variant: "ghost", scope: this.modal.scope, onPress: () => options.onQuit?.() }), this.modal.append(this.resume.root).append(this.settings.root).append(this.quit.root), this.modal.onClose = () => options.onResume?.();
|
|
2163
|
+
}
|
|
2164
|
+
get open() {
|
|
2165
|
+
return this.modal.open;
|
|
2166
|
+
}
|
|
2167
|
+
show() {
|
|
2168
|
+
this.options.stack.push(this.modal);
|
|
2169
|
+
}
|
|
2170
|
+
close() {
|
|
2171
|
+
this.options.stack.remove(this.modal);
|
|
2172
|
+
}
|
|
2173
|
+
};
|
|
2174
|
+
function pauseScreen(ui, options) {
|
|
2175
|
+
return new PauseScreen(ui, options);
|
|
2176
|
+
}
|
|
2177
|
+
var DEFAULT_QUALITIES = ["Low", "Medium", "High"], DEFAULT_LANGUAGES = ["English", "Fran\xE7ais", "Espa\xF1ol", "Kiswahili", "Yor\xF9b\xE1", "Portugu\xEAs"], SettingsScreen = class {
|
|
2178
|
+
constructor(ui, options) {
|
|
2179
|
+
this.options = options;
|
|
2180
|
+
this.values = { music: 0.8, effects: 1, haptics: true, quality: 1, language: 0, ...options.values };
|
|
2181
|
+
let values = this.values, changed = (key) => options.onChange?.(values, key);
|
|
2182
|
+
this.modal = new Modal(ui, { title: "Settings" });
|
|
2183
|
+
let scope = this.modal.scope, nav = options.navigator;
|
|
2184
|
+
this.music = new Slider(ui, { label: "Music", value: values.music, step: 0.05, scope, onChange: (v) => {
|
|
2185
|
+
values.music = v, changed("music");
|
|
2186
|
+
} }), this.effects = new Slider(ui, { label: "Effects", value: values.effects, step: 0.05, scope, onChange: (v) => {
|
|
2187
|
+
values.effects = v, changed("effects");
|
|
2188
|
+
} }), this.haptics = new Toggle(ui, { label: "Haptics", value: values.haptics, scope, onChange: (v) => {
|
|
2189
|
+
values.haptics = v, changed("haptics");
|
|
2190
|
+
} }), this.quality = new Dropdown(ui, { label: "Quality", options: options.qualities ?? DEFAULT_QUALITIES, selected: values.quality, width: 280, navigator: nav, scope, onChange: (i) => {
|
|
2191
|
+
values.quality = i, changed("quality");
|
|
2192
|
+
} }), this.language = new Dropdown(ui, { label: "Language", options: options.languages ?? DEFAULT_LANGUAGES, selected: values.language, width: 280, navigator: nav, scope, onChange: (i) => {
|
|
2193
|
+
values.language = i, changed("language");
|
|
2194
|
+
} }), this.done = new TextButton(ui, { label: "Done", variant: "primary", scope, onPress: () => this.close() }), this.modal.append(label(ui, "AUDIO", "body", s7.section)).append(this.music.root).append(this.effects.root), this.modal.append(label(ui, "GAME", "body", s7.section)).append(this.haptics.root).append(this.quality.root).append(this.language.root), this.modal.append(this.done.root), this.modal.onClose = () => {
|
|
2195
|
+
this.quality.close(), this.language.close(), options.onDone?.(values);
|
|
2196
|
+
};
|
|
2197
|
+
}
|
|
2198
|
+
get open() {
|
|
2199
|
+
return this.modal.open;
|
|
2200
|
+
}
|
|
2201
|
+
show() {
|
|
2202
|
+
this.options.stack.push(this.modal);
|
|
2203
|
+
}
|
|
2204
|
+
close() {
|
|
2205
|
+
this.options.stack.remove(this.modal);
|
|
2206
|
+
}
|
|
2207
|
+
};
|
|
2208
|
+
function settingsScreen(ui, options) {
|
|
2209
|
+
return new SettingsScreen(ui, options);
|
|
2210
|
+
}
|
|
2211
|
+
var ResultsScreen = class {
|
|
2212
|
+
constructor(ui, options) {
|
|
2213
|
+
this.ui = ui;
|
|
2214
|
+
this.options = options;
|
|
2215
|
+
this.target = 0;
|
|
2216
|
+
this.shownScore = -1;
|
|
2217
|
+
this.earned = 0;
|
|
2218
|
+
this.revealed = 0;
|
|
2219
|
+
this.clock = new Float64Array(2);
|
|
2220
|
+
this.natural = options.natural ?? [(28), (28)], this.modal = new Modal(ui, { columns: 2, dismissible: false }), this.title = label(ui, "", "display", sheet.display, sheet.center), this.score = label(ui, "", "mono", s7.score), this.starStates = [ui.props(s7.star), ui.props(s7.star, s7.starOn)], this.rewardStates = [ui.props(s7.reward), ui.props(s7.reward, s7.rewardShown)];
|
|
2221
|
+
let stars = ui.box(s7.stars), starList = [];
|
|
2222
|
+
for (let i = 0; i < (3); i++) {
|
|
2223
|
+
let star = ui.box(this.starStates[0]);
|
|
2224
|
+
star.transition(["scale_x", "scale_y", "fill"], { duration: (0.18), easing: "back_out" }), stars.append(star), starList.push(star);
|
|
2225
|
+
}
|
|
2226
|
+
this.stars = starList;
|
|
2227
|
+
let rewards = ui.box(s7.rewards), rewardList = [], icons = [], amounts = [];
|
|
2228
|
+
for (let i = 0; i < (options.rewards ?? (3)); i++) {
|
|
2229
|
+
let chip = ui.box(this.rewardStates[0]), icon = ui.image(0, this.natural, s7.rewardIcon), amount = label(ui, "", "mono", sheet.text, sheet.strong);
|
|
2230
|
+
chip.append(icon).append(amount), rewards.append(chip), rewardList.push(chip), icons.push(icon), amounts.push(amount);
|
|
2231
|
+
}
|
|
2232
|
+
this.rewards = rewardList, this.rewardIcons = icons, this.rewardAmounts = amounts;
|
|
2233
|
+
let actions = ui.box(s7.actions);
|
|
2234
|
+
this.retry = new TextButton(ui, { label: "Retry", variant: "primary", style: s7.grow, scope: this.modal.scope, onPress: () => options.onRetry?.() }), this.share = new TextButton(ui, { label: "Share", style: s7.grow, scope: this.modal.scope, onPress: () => options.onShare?.() }), actions.append(this.retry.root).append(this.share.root), this.modal.append(this.title).append(stars).append(this.score).append(rewards).append(actions), this.a11y = new A11y({ role: "text", label: "", live: true });
|
|
2235
|
+
}
|
|
2236
|
+
get open() {
|
|
2237
|
+
return this.modal.open;
|
|
2238
|
+
}
|
|
2239
|
+
get starsShown() {
|
|
2240
|
+
return this.revealed;
|
|
2241
|
+
}
|
|
2242
|
+
get scoreShown() {
|
|
2243
|
+
return this.shownScore;
|
|
2244
|
+
}
|
|
2245
|
+
show(result) {
|
|
2246
|
+
this.title.text(result.victory ? "Victory!" : "Defeat"), this.a11y.options.label = result.victory ? "Victory" : "Defeat", this.a11y.apply(this.title), this.target = result.score, this.earned = clamp(Math.round(result.stars), 0, (3)), this.revealed = 0, this.clock[0] = 0, this.shownScore = -1, this.score.number(0, INTEGER);
|
|
2247
|
+
for (let i = 0; i < (3); i++) this.stars[i].style(this.starStates[0]);
|
|
2248
|
+
this.modal.open || this.options.stack.push(this.modal), result.victory && this.options.particles?.burst("confetti", this.at(0), this.at(1), (36));
|
|
2249
|
+
}
|
|
2250
|
+
setReward(index, icon, amount) {
|
|
2251
|
+
this.rewardIcons[index].image(icon, this.natural[0], this.natural[1]), this.rewardAmounts[index].number(amount, PLAIN), this.rewards[index].style(this.rewardStates[1]);
|
|
2252
|
+
}
|
|
2253
|
+
hideReward(index) {
|
|
2254
|
+
this.rewards[index].style(this.rewardStates[0]);
|
|
2255
|
+
}
|
|
2256
|
+
close() {
|
|
2257
|
+
this.options.stack.remove(this.modal);
|
|
2258
|
+
}
|
|
2259
|
+
update(frame) {
|
|
2260
|
+
if (!this.modal.open) return;
|
|
2261
|
+
let clock = this.clock;
|
|
2262
|
+
clock[0] += frame[1], clock[1] = clock[0] < (1.1) ? 1 - clock[0] / (1.1) : 0;
|
|
2263
|
+
let value = this.target * (1 - clock[1] * clock[1] * clock[1]) + 0.5 | 0;
|
|
2264
|
+
value !== this.shownScore && (this.shownScore = value, this.score.number(value, INTEGER));
|
|
2265
|
+
let stars = clock[0] / (0.35) | 0, due = stars < this.earned ? stars : this.earned;
|
|
2266
|
+
for (; this.revealed < due; )
|
|
2267
|
+
this.stars[this.revealed].style(this.starStates[1]), this.revealed++, this.options.particles?.burst("sparkle", this.at(0), this.at(1), (10));
|
|
2268
|
+
}
|
|
2269
|
+
at(axis) {
|
|
2270
|
+
return this.options.celebrateAt?.[axis] ?? 0;
|
|
2271
|
+
}
|
|
2272
|
+
};
|
|
2273
|
+
function resultsScreen(ui, options) {
|
|
2274
|
+
return new ResultsScreen(ui, options);
|
|
2275
|
+
}
|
|
2276
|
+
var LoadingScreen = class {
|
|
2277
|
+
constructor(ui, options = {}) {
|
|
2278
|
+
this.ui = ui;
|
|
2279
|
+
this.clock = new Float64Array(3);
|
|
2280
|
+
this.tipIndex = 0;
|
|
2281
|
+
this.shownPercent = -1;
|
|
2282
|
+
this.visible = false;
|
|
2283
|
+
this.tips = options.tips ?? [], this.clock[(2)] = options.tipSeconds ?? (4), this.states = [ui.props(s7.loading), ui.props(s7.loading, s7.loadingShown)], this.root = ui.box(this.states[0]), this.root.transition(["opacity"], { duration: (0.18) }), SLOTS[0] = 0, this.spinner = ui.box(ui.props(s7.spinner, s7.spin.setSlotsFrom(SLOTS)));
|
|
2284
|
+
let bar = ui.box(s7.bar);
|
|
2285
|
+
this.fill = ui.box(ui.props(s7.barFill, s7.barTo.setSlotsFrom(SLOTS))), bar.append(this.fill), this.percent = label(ui, "", "mono", sheet.small, sheet.strong), this.tip = label(ui, this.tips.length > 0 ? this.tips[0] : "", "body", sheet.text, sheet.muted, s7.tip), this.root.append(label(ui, options.title ?? "Loading", "display", sheet.title)), this.root.append(this.spinner).append(bar).append(this.percent).append(this.tip);
|
|
2286
|
+
let rooting = { anchor: "fill", safe_area: false, z: options.z ?? (1200) };
|
|
2287
|
+
ui.root(this.root, rooting), this.a11y = new A11y({ role: "progress", label: options.title ?? "Loading", value: "0%", hidden: true }), this.a11y.apply(this.root), this.setProgress(0);
|
|
2288
|
+
}
|
|
2289
|
+
get shown() {
|
|
2290
|
+
return this.visible;
|
|
2291
|
+
}
|
|
2292
|
+
show() {
|
|
2293
|
+
this.visible || (this.visible = true, this.root.style(this.states[1]), this.a11y.options.hidden = false, this.a11y.apply(this.root));
|
|
2294
|
+
}
|
|
2295
|
+
hide() {
|
|
2296
|
+
this.visible && (this.visible = false, this.root.style(this.states[0]), this.a11y.options.hidden = true, this.a11y.apply(this.root));
|
|
2297
|
+
}
|
|
2298
|
+
setProgress(ratio) {
|
|
2299
|
+
this.setPercent(Math.round(clamp(ratio, 0, 1) * (100)));
|
|
2300
|
+
}
|
|
2301
|
+
setPercent(value) {
|
|
2302
|
+
let percent = value < 0 ? 0 : value > (100) ? (100) : value | 0;
|
|
2303
|
+
percent !== this.shownPercent && (this.shownPercent = percent, SLOTS[0] = percent, this.fill.style(this.ui.props(s7.barFill, s7.barTo.setSlotsFrom(SLOTS))), this.percent.text(PERCENT_TEXT[percent]), this.a11y.options.value = PERCENT_TEXT[percent], this.a11y.apply(this.root));
|
|
2304
|
+
}
|
|
2305
|
+
update(frame) {
|
|
2306
|
+
if (!this.visible) return;
|
|
2307
|
+
let dt = frame[1], clock = this.clock;
|
|
2308
|
+
clock[(0)] += SPINNER_SPEED * dt, clock[(0)] >= TURN && (clock[(0)] -= TURN), SLOTS[0] = clock[(0)], this.spinner.style(this.ui.props(s7.spinner, s7.spin.setSlotsFrom(SLOTS))), !(this.tips.length < 2) && (clock[(1)] += dt, !(clock[(1)] < clock[(2)]) && (clock[(1)] = 0, this.tipIndex = (this.tipIndex + 1) % this.tips.length, this.tip.text(this.tips[this.tipIndex])));
|
|
2309
|
+
}
|
|
2310
|
+
};
|
|
2311
|
+
function loadingScreen(ui, options = {}) {
|
|
2312
|
+
return new LoadingScreen(ui, options);
|
|
2313
|
+
}
|
|
2314
|
+
var TutorialHint = class {
|
|
2315
|
+
constructor(ui, options = {}) {
|
|
2316
|
+
this.ui = ui;
|
|
2317
|
+
this.steps = [];
|
|
2318
|
+
this.step = 0;
|
|
2319
|
+
this.at = new Float64Array(3);
|
|
2320
|
+
this.visible = false;
|
|
2321
|
+
this.navigator = options.navigator ?? null, this.onDone = options.onDone ?? null, this.states = [ui.props(s7.hint), ui.props(s7.hint, s7.hintShown)], this.dotStates = [ui.props(s7.dot), ui.props(s7.dot, s7.dotOn), ui.props(s7.dot, s7.dotHidden)], this.root = ui.box(this.states[0]), SLOTS[0] = 0, SLOTS[1] = 0, this.bubble = ui.box(ui.props(s7.bubble, s7.bubbleAt.setSlotsFrom(SLOTS))), this.text = label(ui, "", "body", sheet.text, sheet.wrap);
|
|
2322
|
+
let footer = ui.box(s7.footer), dots = ui.box(s7.dots), dotList = [];
|
|
2323
|
+
for (let i = 0; i < (8); i++) {
|
|
2324
|
+
let dot = ui.box(this.dotStates[2]);
|
|
2325
|
+
dots.append(dot), dotList.push(dot);
|
|
2326
|
+
}
|
|
2327
|
+
this.dots = dotList, this.scope = new UiFocusScope(1, () => (this.hide(), true)), this.next = new TextButton(ui, { label: "Next", variant: "primary", scope: this.scope, onPress: () => this.advance() }), this.skip = new TextButton(ui, { label: "Skip", variant: "ghost", scope: this.scope, onPress: () => this.finish() });
|
|
2328
|
+
let buttons = ui.box(s7.actions);
|
|
2329
|
+
buttons.append(this.skip.root).append(this.next.root), footer.append(dots).append(buttons), this.bubble.append(this.text).append(footer), this.arrow = ui.box(ui.props(s7.arrow, s7.arrowAt.setSlotsFrom(SLOTS))), this.root.append(this.arrow).append(this.bubble);
|
|
2330
|
+
let rooting = { anchor: "fill", safe_area: true, z: options.z ?? (900) };
|
|
2331
|
+
ui.root(this.root, rooting), this.a11y = new A11y({ role: "alert", label: "", live: true, hidden: true }), this.a11y.apply(this.bubble);
|
|
2332
|
+
}
|
|
2333
|
+
get shown() {
|
|
2334
|
+
return this.visible;
|
|
2335
|
+
}
|
|
2336
|
+
get index() {
|
|
2337
|
+
return this.step;
|
|
2338
|
+
}
|
|
2339
|
+
show(steps, x, y) {
|
|
2340
|
+
this.steps = steps, this.at[(0)] = x, this.at[(1)] = y, this.visible = true, this.root.style(this.states[1]), SLOTS[0] = x, SLOTS[1] = y + (16), this.bubble.style(this.ui.props(s7.bubble, s7.bubbleAt.setSlotsFrom(SLOTS))), this.go(0), this.scope.current = -1, this.navigator?.push(this.scope);
|
|
2341
|
+
}
|
|
2342
|
+
advance() {
|
|
2343
|
+
this.step + 1 >= this.steps.length ? this.finish() : this.go(this.step + 1);
|
|
2344
|
+
}
|
|
2345
|
+
hide() {
|
|
2346
|
+
this.visible && (this.visible = false, this.root.style(this.states[0]), this.a11y.options.hidden = true, this.a11y.apply(this.bubble), this.navigator?.pop(this.scope));
|
|
2347
|
+
}
|
|
2348
|
+
update(frame) {
|
|
2349
|
+
if (!this.visible) return;
|
|
2350
|
+
let at = this.at;
|
|
2351
|
+
at[(2)] += frame[1], SLOTS[0] = at[(0)] + (16);
|
|
2352
|
+
let phase = at[(2)] * (1), wave = phase - (phase | 0);
|
|
2353
|
+
SLOTS[1] = at[(1)] + (wave < 0.5 ? wave * 4 - 1 : 3 - wave * 4) * (6), this.arrow.style(this.ui.props(s7.arrow, s7.arrowAt.setSlotsFrom(SLOTS)));
|
|
2354
|
+
}
|
|
2355
|
+
finish() {
|
|
2356
|
+
this.hide(), this.onDone?.();
|
|
2357
|
+
}
|
|
2358
|
+
go(step) {
|
|
2359
|
+
this.step = step, this.text.text(this.steps[step]);
|
|
2360
|
+
let last = step + 1 >= this.steps.length;
|
|
2361
|
+
this.next.setLabel(last ? "Got it" : "Next");
|
|
2362
|
+
for (let i = 0; i < (8); i++) this.dots[i].style(this.dotStates[i >= this.steps.length || this.steps.length < 2 ? 2 : i === step ? 1 : 0]);
|
|
2363
|
+
this.a11y.options.label = this.steps[step], this.a11y.options.hidden = false, this.a11y.apply(this.bubble);
|
|
2364
|
+
}
|
|
2365
|
+
};
|
|
2366
|
+
function tutorialHint(ui, options = {}) {
|
|
2367
|
+
return new TutorialHint(ui, options);
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
// src/interactives/game-ui/widgets/text.ts
|
|
2371
|
+
var CHAT_WIDTH = 300, CHAT_LINES = 6, SENDER_COLORS = 6, FADED_LINES = 2, RICH_SPANS = 24, ICON_SIZE = 18, PARSE_CACHE = 64, s8 = styles({
|
|
2372
|
+
chat: { gap: 2, padding: [kitVars.gapSmall, kitVars.gap, kitVars.gapSmall, kitVars.gap], fill: tokens.surface, radius: kitVars.radius, pointerEvents: "none" },
|
|
2373
|
+
line: { direction: "row", wrap: true, gap: kitVars.gapSmall, alignItems: "start", hidden: false, opacity: 1 },
|
|
2374
|
+
lineFaded: { opacity: 0.55 },
|
|
2375
|
+
lineHidden: { hidden: true },
|
|
2376
|
+
name: { fontSize: kitVars.small, fontWeight: 800, pointerEvents: "none" },
|
|
2377
|
+
body: { fontSize: kitVars.small, textColor: tokens.text, textWrap: true, shrink: 1, grow: 1, basis: 0, pointerEvents: "none" },
|
|
2378
|
+
system: { textColor: tokens.muted },
|
|
2379
|
+
sender0: { textColor: tokens.accent },
|
|
2380
|
+
sender1: { textColor: tokens.success },
|
|
2381
|
+
sender2: { textColor: tokens.gold },
|
|
2382
|
+
sender3: { textColor: tokens.danger },
|
|
2383
|
+
sender4: { textColor: kitVars.silver },
|
|
2384
|
+
sender5: { textColor: kitVars.bronze },
|
|
2385
|
+
rich: { direction: "row", wrap: true, alignItems: "center" },
|
|
2386
|
+
span: { fontSize: kitVars.body, textColor: tokens.text, pointerEvents: "none" },
|
|
2387
|
+
spanBold: { fontWeight: 800 },
|
|
2388
|
+
spanIcon: { width: (18), height: (18), marginInline: 2, pointerEvents: "none" },
|
|
2389
|
+
cText: { textColor: tokens.text },
|
|
2390
|
+
cMuted: { textColor: tokens.muted },
|
|
2391
|
+
cAccent: { textColor: tokens.accent },
|
|
2392
|
+
cGold: { textColor: tokens.gold },
|
|
2393
|
+
cDanger: { textColor: tokens.danger },
|
|
2394
|
+
cSuccess: { textColor: tokens.success }
|
|
2395
|
+
}), ChatPanel = class {
|
|
2396
|
+
constructor(ui, options = {}) {
|
|
2397
|
+
this.ui = ui;
|
|
2398
|
+
this.head = 0;
|
|
2399
|
+
this.size = 0;
|
|
2400
|
+
let lines = options.lines ?? (6);
|
|
2401
|
+
this.senders = new Array(lines).fill(""), this.messages = new Array(lines).fill(""), this.colors = new Int8Array(lines);
|
|
2402
|
+
let body = fontStyle(ui, "body"), colors = [s8.sender0, s8.sender1, s8.sender2, s8.sender3, s8.sender4, s8.sender5];
|
|
2403
|
+
this.lineStates = [ui.props(s8.line), ui.props(s8.line, s8.lineFaded), ui.props(s8.line, s8.lineHidden)];
|
|
2404
|
+
let nameStates = [];
|
|
2405
|
+
for (let i = 0; i < (6); i++) nameStates.push(ui.props(body, s8.name, colors[i]));
|
|
2406
|
+
nameStates.push(ui.props(body, s8.name, sheet.hidden)), this.nameStates = nameStates, this.bodyStates = [ui.props(body, s8.body), ui.props(body, s8.body, s8.system)], this.root = ui.box(ui.props(s8.chat, { width: options.width ?? (300) }, options.style));
|
|
2407
|
+
let rows = [], names = [], bodies = [];
|
|
2408
|
+
for (let i = 0; i < lines; i++) {
|
|
2409
|
+
let row = ui.box(this.lineStates[2]), name = ui.text("", this.nameStates[0]), text = ui.text("", this.bodyStates[0]);
|
|
2410
|
+
row.append(name).append(text), this.root.append(row), rows.push(row), names.push(name), bodies.push(text);
|
|
2411
|
+
}
|
|
2412
|
+
this.rows = rows, this.names = names, this.bodies = bodies, this.root.accessibility({ role: "group", label: options.label ?? "Chat", live: true });
|
|
2413
|
+
}
|
|
2414
|
+
get count() {
|
|
2415
|
+
return this.size;
|
|
2416
|
+
}
|
|
2417
|
+
push(sender, message, color = 0) {
|
|
2418
|
+
let capacity = this.rows.length;
|
|
2419
|
+
this.senders[this.head] = sender, this.messages[this.head] = message, this.colors[this.head] = color, this.head = (this.head + 1) % capacity, this.size < capacity && this.size++, this.render();
|
|
2420
|
+
}
|
|
2421
|
+
system(message) {
|
|
2422
|
+
this.push("", message, -1);
|
|
2423
|
+
}
|
|
2424
|
+
clear() {
|
|
2425
|
+
this.size = 0, this.render();
|
|
2426
|
+
}
|
|
2427
|
+
render() {
|
|
2428
|
+
let capacity = this.rows.length, empty = capacity - this.size;
|
|
2429
|
+
for (let line = 0; line < capacity; line++) {
|
|
2430
|
+
let row = this.rows[line];
|
|
2431
|
+
if (line < empty) {
|
|
2432
|
+
row.style(this.lineStates[2]);
|
|
2433
|
+
continue;
|
|
2434
|
+
}
|
|
2435
|
+
let at = (this.head - (capacity - line) + capacity * 2) % capacity, color = this.colors[at];
|
|
2436
|
+
row.style(this.lineStates[line - empty < (2) && this.size > (2) ? 1 : 0]), this.names[line].style(this.nameStates[color < 0 ? (6) : color % (6)]), color >= 0 && this.names[line].text(this.senders[at]), this.bodies[line].style(this.bodyStates[color < 0 ? 1 : 0]), this.bodies[line].text(this.messages[at]);
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
};
|
|
2440
|
+
function chatPanel(ui, options = {}) {
|
|
2441
|
+
return new ChatPanel(ui, options);
|
|
2442
|
+
}
|
|
2443
|
+
var RICH_COLORS = ["text", "muted", "accent", "gold", "danger", "success"], SPAN_TEXT = 0, SPAN_ICON = 1, BOLD_BIT = 8, RichTextError = class extends Error {
|
|
2444
|
+
constructor(message) {
|
|
2445
|
+
super(message), this.name = "RichTextError";
|
|
2446
|
+
}
|
|
2447
|
+
};
|
|
2448
|
+
function parseRich(markup, icons, limit) {
|
|
2449
|
+
let texts = [], kinds = [], styles2 = [], assets = [], bold = false, colors = [0], word = "", flush = () => {
|
|
2450
|
+
if (word.length === 0) return;
|
|
2451
|
+
let last = texts.length - 1;
|
|
2452
|
+
if (word.trim().length === 0 && last >= 0 && kinds[last] === (0)) {
|
|
2453
|
+
texts[last] += word, word = "";
|
|
2454
|
+
return;
|
|
2455
|
+
}
|
|
2456
|
+
texts.push(word), kinds.push((0)), styles2.push(colors[colors.length - 1] | (bold ? (8) : 0)), assets.push(-1), word = "";
|
|
2457
|
+
};
|
|
2458
|
+
for (let i = 0; i < markup.length; i++) {
|
|
2459
|
+
let c = markup[i];
|
|
2460
|
+
if (c === "*" && markup[i + 1] === "*") {
|
|
2461
|
+
flush(), bold = !bold, i++;
|
|
2462
|
+
continue;
|
|
2463
|
+
}
|
|
2464
|
+
if (c === "[") {
|
|
2465
|
+
let end = markup.indexOf("]", i);
|
|
2466
|
+
if (end < 0) throw new RichTextError(`rich text: unclosed "[" at ${i}`);
|
|
2467
|
+
let name = markup.slice(i + 1, end);
|
|
2468
|
+
if (flush(), name === "/")
|
|
2469
|
+
colors.length > 1 && colors.pop();
|
|
2470
|
+
else {
|
|
2471
|
+
let color = RICH_COLORS.indexOf(name);
|
|
2472
|
+
if (color < 0) throw new RichTextError(`rich text: unknown colour "${name}"; use one of ${RICH_COLORS.join(", ")}`);
|
|
2473
|
+
colors.push(color);
|
|
2474
|
+
}
|
|
2475
|
+
i = end;
|
|
2476
|
+
continue;
|
|
2477
|
+
}
|
|
2478
|
+
if (c === "{") {
|
|
2479
|
+
let end = markup.indexOf("}", i);
|
|
2480
|
+
if (end < 0) throw new RichTextError(`rich text: unclosed "{" at ${i}`);
|
|
2481
|
+
let name = markup.slice(i + 1, end), asset = icons[name];
|
|
2482
|
+
if (asset === void 0) throw new RichTextError(`rich text: unknown icon "${name}"`);
|
|
2483
|
+
flush(), texts.push(""), kinds.push((1)), styles2.push(0), assets.push(asset), i = end;
|
|
2484
|
+
continue;
|
|
2485
|
+
}
|
|
2486
|
+
word += c, c === " " && word.trim().length > 0 && flush();
|
|
2487
|
+
}
|
|
2488
|
+
if (flush(), texts.length > limit) throw new RichTextError(`rich text: ${texts.length} spans exceed the widget's ${limit}; raise spans`);
|
|
2489
|
+
return { texts, kinds: Uint8Array.from(kinds), styles: Uint8Array.from(styles2), icons: Int32Array.from(assets), count: texts.length, plain: texts.join("").replace(/\s+/g, " ").trim() };
|
|
2490
|
+
}
|
|
2491
|
+
var RichText = class {
|
|
2492
|
+
constructor(ui, options = {}) {
|
|
2493
|
+
this.ui = ui;
|
|
2494
|
+
this.source = null;
|
|
2495
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
2496
|
+
this.shown = null;
|
|
2497
|
+
this.current = "";
|
|
2498
|
+
this.a11y = new A11y({ role: "text", label: "" });
|
|
2499
|
+
let spans = options.spans ?? (24);
|
|
2500
|
+
this.icons = options.icons ?? {}, this.natural = options.natural ?? [(18), (18)];
|
|
2501
|
+
let body = fontStyle(ui, "body"), colorStyles = [s8.cText, s8.cMuted, s8.cAccent, s8.cGold, s8.cDanger, s8.cSuccess], textStates = [];
|
|
2502
|
+
for (let bold = 0; bold < 2; bold++) for (let c = 0; c < (8); c++) textStates.push(ui.props(body, s8.span, colorStyles[c % colorStyles.length], bold === 1 && s8.spanBold));
|
|
2503
|
+
this.textStates = textStates, this.hiddenText = ui.props(body, s8.span, sheet.hidden), this.iconStates = [ui.props(s8.spanIcon), ui.props(s8.spanIcon, sheet.hidden)], this.root = ui.box(ui.props(s8.rich, options.style));
|
|
2504
|
+
let texts = [], images = [];
|
|
2505
|
+
for (let i = 0; i < spans; i++) {
|
|
2506
|
+
let text = ui.text("", this.hiddenText), image = ui.image(0, this.natural, this.iconStates[1]);
|
|
2507
|
+
this.root.append(text).append(image), texts.push(text), images.push(image);
|
|
2508
|
+
}
|
|
2509
|
+
this.texts = texts, this.images = images, this.mark = new AiMark(ui, options.mark), this.root.append(this.mark.root), options.flowAround !== void 0 && this.root.flowAround(options.flowAround), options.markup !== void 0 && this.set(options.markup, options.source ?? null);
|
|
2510
|
+
}
|
|
2511
|
+
flowAround(exclusions) {
|
|
2512
|
+
return this.root.flowAround(exclusions), this;
|
|
2513
|
+
}
|
|
2514
|
+
get marked() {
|
|
2515
|
+
return this.mark.shown;
|
|
2516
|
+
}
|
|
2517
|
+
get markup() {
|
|
2518
|
+
return this.current;
|
|
2519
|
+
}
|
|
2520
|
+
get spans() {
|
|
2521
|
+
return this.shown?.count ?? 0;
|
|
2522
|
+
}
|
|
2523
|
+
show(result) {
|
|
2524
|
+
this.set(result.value, result.source);
|
|
2525
|
+
}
|
|
2526
|
+
set(markup, source = null) {
|
|
2527
|
+
if (markup === this.current && this.shown !== null && isAiGenerated(source) === isAiGenerated(this.source)) return;
|
|
2528
|
+
this.source = source;
|
|
2529
|
+
let parsed = this.cache.get(markup);
|
|
2530
|
+
parsed === void 0 && (parsed = parseRich(markup, this.icons, this.texts.length), this.cache.size >= (64) && this.cache.clear(), this.cache.set(markup, parsed));
|
|
2531
|
+
let previous = this.shown?.count ?? 0;
|
|
2532
|
+
this.current = markup, this.shown = parsed;
|
|
2533
|
+
for (let i = 0; i < parsed.count; i++) {
|
|
2534
|
+
if (parsed.kinds[i] === (1)) {
|
|
2535
|
+
this.texts[i].style(this.hiddenText), this.images[i].image(parsed.icons[i], this.natural[0], this.natural[1]), this.images[i].style(this.iconStates[0]);
|
|
2536
|
+
continue;
|
|
2537
|
+
}
|
|
2538
|
+
this.images[i].style(this.iconStates[1]), this.texts[i].text(parsed.texts[i]), this.texts[i].style(this.textStates[parsed.styles[i]]);
|
|
2539
|
+
}
|
|
2540
|
+
for (let i = parsed.count; i < previous; i++)
|
|
2541
|
+
this.texts[i].style(this.hiddenText), this.images[i].style(this.iconStates[1]);
|
|
2542
|
+
this.a11y.options.label = aiLabel(parsed.plain, this.mark.show(source)), this.a11y.apply(this.root);
|
|
2543
|
+
}
|
|
2544
|
+
};
|
|
2545
|
+
function richText(ui, options = {}) {
|
|
2546
|
+
return new RichText(ui, options);
|
|
2547
|
+
}
|
|
2548
|
+
|
|
2549
|
+
// src/interactives/worlds/index.ts
|
|
2550
|
+
var worlds_exports = {};
|
|
2551
|
+
__export(worlds_exports, {
|
|
2552
|
+
ACTION_BASE: () => ACTION_BASE,
|
|
2553
|
+
Action: () => Action,
|
|
2554
|
+
BOUNDS_MAX: () => BOUNDS_MAX,
|
|
2555
|
+
BOUNDS_MIN: () => BOUNDS_MIN,
|
|
2556
|
+
BOUNDS_WORDS: () => BOUNDS_WORDS,
|
|
2557
|
+
CENTIDEGREES_PER_TURN: () => CENTIDEGREES_PER_TURN,
|
|
2558
|
+
COMMAND_BYTES: () => COMMAND_BYTES,
|
|
2559
|
+
COMMAND_OP_ID_BYTES: () => COMMAND_OP_ID_BYTES,
|
|
2560
|
+
CommandWriter: () => CommandWriter,
|
|
2561
|
+
DEFAULT_ANGLE_STEP_CENTIDEGREES: () => DEFAULT_ANGLE_STEP_CENTIDEGREES,
|
|
2562
|
+
DEFAULT_GRID_MM: () => DEFAULT_GRID_MM,
|
|
2563
|
+
Ground: () => Ground,
|
|
2564
|
+
Lighting: () => Lighting,
|
|
2565
|
+
Likeness: () => Likeness,
|
|
2566
|
+
LocalWorld: () => LocalWorld,
|
|
2567
|
+
MAX_SELECT_IDS: () => MAX_SELECT_IDS,
|
|
2568
|
+
MILLIMETRES_PER_METRE: () => MILLIMETRES_PER_METRE,
|
|
2569
|
+
MessageKind: () => MessageKind,
|
|
2570
|
+
NOT_SENT: () => NOT_SENT,
|
|
2571
|
+
NO_BUILDER: () => NO_BUILDER,
|
|
2572
|
+
Notice: () => Notice,
|
|
2573
|
+
OBJECT_RECORD_BYTES: () => OBJECT_RECORD_BYTES,
|
|
2574
|
+
POSITION: () => POSITION,
|
|
2575
|
+
QUATERNION_SCALE: () => QUATERNION_SCALE,
|
|
2576
|
+
ROTATION: () => ROTATION,
|
|
2577
|
+
SCALE: () => SCALE,
|
|
2578
|
+
SCALE_UNIT_PERMILLE: () => SCALE_UNIT_PERMILLE,
|
|
2579
|
+
SNAP_GRID: () => SNAP_GRID,
|
|
2580
|
+
SNAP_SURFACE: () => SNAP_SURFACE,
|
|
2581
|
+
Sanction: () => Sanction,
|
|
2582
|
+
SelectMode: () => SelectMode,
|
|
2583
|
+
Sky: () => Sky,
|
|
2584
|
+
Status: () => Status,
|
|
2585
|
+
TRANSFORM_BYTES: () => TRANSFORM_BYTES,
|
|
2586
|
+
TRANSFORM_WORDS: () => TRANSFORM_WORDS,
|
|
2587
|
+
Visibility: () => Visibility,
|
|
2588
|
+
WORLD_CHANNEL_SLOT: () => WORLD_CHANNEL_SLOT,
|
|
2589
|
+
WORLD_DEPTH_MM: () => WORLD_DEPTH_MM,
|
|
2590
|
+
WORLD_EXTENT_MM: () => WORLD_EXTENT_MM,
|
|
2591
|
+
WorldBuilder: () => WorldBuilder,
|
|
2592
|
+
WorldMirror: () => WorldMirror,
|
|
2593
|
+
WorldRoleCode: () => WorldRoleCode,
|
|
2594
|
+
bounds: () => bounds,
|
|
2595
|
+
canonical: () => canonical,
|
|
2596
|
+
connectWorld: () => connectWorld,
|
|
2597
|
+
copyTransform: () => copyTransform,
|
|
2598
|
+
encodeBare: () => encodeBare,
|
|
2599
|
+
encodeClock: () => encodeClock,
|
|
2600
|
+
encodeDuplicate: () => encodeDuplicate,
|
|
2601
|
+
encodeJoinCopy: () => encodeJoinCopy,
|
|
2602
|
+
encodeModerate: () => encodeModerate,
|
|
2603
|
+
encodePlace: () => encodePlace,
|
|
2604
|
+
encodeSelect: () => encodeSelect,
|
|
2605
|
+
encodeSetTransform: () => encodeSetTransform,
|
|
2606
|
+
encodeSettings: () => encodeSettings,
|
|
2607
|
+
encodeTransformSelection: () => encodeTransformSelection,
|
|
2608
|
+
identityTransform: () => identityTransform,
|
|
2609
|
+
movedAbout: () => movedAbout,
|
|
2610
|
+
overlapsFootprint: () => overlapsFootprint,
|
|
2611
|
+
snapHeightToGrid: () => snapHeightToGrid,
|
|
2612
|
+
snappedToGrid: () => snappedToGrid,
|
|
2613
|
+
withinWorld: () => withinWorld,
|
|
2614
|
+
yawRotation: () => yawRotation
|
|
2615
|
+
});
|
|
2616
|
+
|
|
2617
|
+
// src/interactives/generate/index.ts
|
|
2618
|
+
var generate_exports = {};
|
|
2619
|
+
__export(generate_exports, {
|
|
2620
|
+
CONTENT_CHANNEL_SLOT: () => CONTENT_CHANNEL_SLOT,
|
|
2621
|
+
DEFAULT_RETRIES: () => DEFAULT_RETRIES,
|
|
2622
|
+
DEFAULT_TIMEOUT_MS: () => DEFAULT_TIMEOUT_MS,
|
|
2623
|
+
MAX_TIMEOUT_MS: () => MAX_TIMEOUT_MS,
|
|
2624
|
+
MIN_TIMEOUT_MS: () => MIN_TIMEOUT_MS,
|
|
2625
|
+
REPLICATION_GRACE_MS: () => (2e3),
|
|
2626
|
+
RoomGenerateError: () => RoomGenerateError,
|
|
2627
|
+
acceptContent: () => acceptContent,
|
|
2628
|
+
applyRules: () => applyRules,
|
|
2629
|
+
contentRequest: () => contentRequest,
|
|
2630
|
+
createGenerate: () => createGenerate,
|
|
2631
|
+
createRoomGenerate: () => createRoomGenerate,
|
|
2632
|
+
createTickContentLink: () => createTickContentLink,
|
|
2633
|
+
dialogueSchema: () => dialogueSchema,
|
|
2634
|
+
recipeToScene: () => recipeToScene,
|
|
2635
|
+
requestTickContent: () => requestTickContent,
|
|
2636
|
+
roomRecipeSchema: () => roomRecipeSchema,
|
|
2637
|
+
rule: () => rule,
|
|
2638
|
+
runContent: () => runContent,
|
|
2639
|
+
select: () => select,
|
|
2640
|
+
solveRoom: () => solveRoom,
|
|
2641
|
+
t: () => t,
|
|
2642
|
+
tickContentAsk: () => tickContentAsk,
|
|
2643
|
+
validateValue: () => validateValue
|
|
2644
|
+
});
|
|
2645
|
+
|
|
2646
|
+
// src/interactives/generate/room.ts
|
|
2647
|
+
var REPLICATION_VERSION = 1, REPLICATION_GRACE_MS = 2e3, MAX_REMEMBERED = 256, RoomGenerateError = class extends Error {
|
|
2648
|
+
constructor(message) {
|
|
2649
|
+
super(message), this.name = "RoomGenerateError";
|
|
2650
|
+
}
|
|
2651
|
+
}, encoder = new TextEncoder(), decoder = new TextDecoder();
|
|
2652
|
+
function decode(bytes) {
|
|
2653
|
+
try {
|
|
2654
|
+
let message = JSON.parse(decoder.decode(bytes));
|
|
2655
|
+
return message.v === (1) && typeof message.key == "string" ? message : null;
|
|
2656
|
+
} catch {
|
|
2657
|
+
return null;
|
|
2658
|
+
}
|
|
2659
|
+
}
|
|
2660
|
+
function fallbackValue(request) {
|
|
2661
|
+
return typeof request.fallback == "function" ? request.fallback() : request.fallback;
|
|
2662
|
+
}
|
|
2663
|
+
function fromMessage(request, message) {
|
|
2664
|
+
return message.source === "fallback" || message.value === void 0 ? {
|
|
2665
|
+
value: fallbackValue(request),
|
|
2666
|
+
source: "fallback",
|
|
2667
|
+
reason: message.reason ?? "unavailable",
|
|
2668
|
+
seed: message.seed,
|
|
2669
|
+
runId: null,
|
|
2670
|
+
digest: null
|
|
2671
|
+
} : {
|
|
2672
|
+
value: message.value,
|
|
2673
|
+
source: message.source === "generated" || message.source === "cached" ? "replicated" : message.source,
|
|
2674
|
+
reason: null,
|
|
2675
|
+
seed: message.seed,
|
|
2676
|
+
runId: message.runId,
|
|
2677
|
+
digest: message.digest
|
|
2678
|
+
};
|
|
2679
|
+
}
|
|
2680
|
+
function createRoomGenerate(ai, link) {
|
|
2681
|
+
if (link.authority && ai === null)
|
|
2682
|
+
throw new RoomGenerateError("the room authority needs ctx.ai to generate");
|
|
2683
|
+
let seen = /* @__PURE__ */ new Map(), waiting = /* @__PURE__ */ new Map(), remember = (message) => {
|
|
2684
|
+
if (seen.set(message.key, message), seen.size > (256)) {
|
|
2685
|
+
let oldest = seen.keys().next().value;
|
|
2686
|
+
oldest !== void 0 && seen.delete(oldest);
|
|
2687
|
+
}
|
|
2688
|
+
let waiters = waiting.get(message.key);
|
|
2689
|
+
if (waiters !== void 0) {
|
|
2690
|
+
waiting.delete(message.key);
|
|
2691
|
+
for (let waiter of waiters) waiter(message);
|
|
2692
|
+
}
|
|
2693
|
+
}, unsubscribe = link.subscribe((bytes) => {
|
|
2694
|
+
let message = decode(bytes);
|
|
2695
|
+
message !== null && remember(message);
|
|
2696
|
+
}), follow = (key, request) => {
|
|
2697
|
+
let known = seen.get(key);
|
|
2698
|
+
if (known !== void 0) return Promise.resolve(fromMessage(request, known));
|
|
2699
|
+
let patience = (request.timeoutMs ?? 0) + (2e3);
|
|
2700
|
+
return new Promise((resolve) => {
|
|
2701
|
+
let timer = setTimeout(() => {
|
|
2702
|
+
let list3 = waiting.get(key);
|
|
2703
|
+
if (list3 !== void 0) {
|
|
2704
|
+
let index = list3.indexOf(waiter);
|
|
2705
|
+
index >= 0 && list3.splice(index, 1);
|
|
2706
|
+
}
|
|
2707
|
+
resolve({
|
|
2708
|
+
value: fallbackValue(request),
|
|
2709
|
+
source: "fallback",
|
|
2710
|
+
reason: "offline",
|
|
2711
|
+
seed: request.seed ?? 0,
|
|
2712
|
+
runId: null,
|
|
2713
|
+
digest: null
|
|
2714
|
+
});
|
|
2715
|
+
}, patience), waiter = (message) => {
|
|
2716
|
+
clearTimeout(timer), resolve(fromMessage(request, message));
|
|
2717
|
+
}, list2 = waiting.get(key) ?? [];
|
|
2718
|
+
list2.push(waiter), waiting.set(key, list2);
|
|
2719
|
+
});
|
|
2720
|
+
}, lead = async (kind, key, request) => {
|
|
2721
|
+
let known = seen.get(key);
|
|
2722
|
+
if (known !== void 0) return fromMessage(request, known);
|
|
2723
|
+
let result = await runContent(
|
|
2724
|
+
ai,
|
|
2725
|
+
kind,
|
|
2726
|
+
request,
|
|
2727
|
+
{ room_id: link.roomId, key },
|
|
2728
|
+
key
|
|
2729
|
+
), message = {
|
|
2730
|
+
v: (1),
|
|
2731
|
+
key,
|
|
2732
|
+
source: result.source,
|
|
2733
|
+
reason: result.reason,
|
|
2734
|
+
seed: result.seed,
|
|
2735
|
+
runId: result.runId,
|
|
2736
|
+
digest: result.digest,
|
|
2737
|
+
...result.source === "fallback" ? {} : { value: result.value }
|
|
2738
|
+
};
|
|
2739
|
+
return seen.set(key, message), link.publish(encoder.encode(JSON.stringify(message))), result;
|
|
2740
|
+
}, generate = (kind, key, request) => link.authority ? lead(kind, key, request) : follow(key, request);
|
|
2741
|
+
return {
|
|
2742
|
+
generate,
|
|
2743
|
+
dialogue: (key, request) => generate("dialogue", key, request),
|
|
2744
|
+
text: (key, request) => generate("text", key, request),
|
|
2745
|
+
item: (key, request) => generate("item", key, request),
|
|
2746
|
+
quest: (key, request) => generate("quest", key, request),
|
|
2747
|
+
room: (key, request) => generate("room", key, request),
|
|
2748
|
+
dispose: () => {
|
|
2749
|
+
unsubscribe(), waiting.clear(), seen.clear();
|
|
2750
|
+
}
|
|
2751
|
+
};
|
|
2752
|
+
}
|
|
2753
|
+
|
|
2754
|
+
// src/interactives/generate/scene.ts
|
|
2755
|
+
var MAX_ROOM_SIZE_M = 200, MIN_ROOM_SIZE_M = 2, MAX_ROOM_GROUPS = 16, MAX_GROUP_COUNT = 64, MAX_WITHIN_M = 50;
|
|
2756
|
+
function roomRecipeSchema(kinds, grounds = ["grass"]) {
|
|
2757
|
+
let name = t.string({ min: 1, max: 32, note: "a short snake_case name for the group" });
|
|
2758
|
+
return t.object({
|
|
2759
|
+
name: t.string({ min: 1, max: 60 }),
|
|
2760
|
+
size: t.array(t.number({ min: (2), max: (200) }), {
|
|
2761
|
+
min: 2,
|
|
2762
|
+
max: 2,
|
|
2763
|
+
note: "width and depth in metres"
|
|
2764
|
+
}),
|
|
2765
|
+
ground: t.enum(grounds),
|
|
2766
|
+
style: t.optional(t.string({ max: 40 })),
|
|
2767
|
+
points: t.optional(
|
|
2768
|
+
t.array(
|
|
2769
|
+
t.object({
|
|
2770
|
+
name,
|
|
2771
|
+
at: t.array(t.number({ min: 0, max: (200) }), { min: 2, max: 2 })
|
|
2772
|
+
}),
|
|
2773
|
+
{ max: 8 }
|
|
2774
|
+
)
|
|
2775
|
+
),
|
|
2776
|
+
objects: t.array(
|
|
2777
|
+
t.object({
|
|
2778
|
+
name,
|
|
2779
|
+
kind: t.enum(kinds),
|
|
2780
|
+
count: t.integer({ min: 1, max: (64) }),
|
|
2781
|
+
near: t.optional(t.string({ max: 32 })),
|
|
2782
|
+
within: t.optional(t.number({ min: 0, max: (50) })),
|
|
2783
|
+
facing: t.optional(t.string({ max: 32 })),
|
|
2784
|
+
along: t.optional(t.string({ max: 40 })),
|
|
2785
|
+
on: t.optional(t.string({ max: 32 })),
|
|
2786
|
+
clear: t.optional(t.number({ min: 0, max: 10 })),
|
|
2787
|
+
reachable_from: t.optional(t.string({ max: 32 }))
|
|
2788
|
+
}),
|
|
2789
|
+
{ min: 1, max: (16) }
|
|
2790
|
+
)
|
|
2791
|
+
});
|
|
2792
|
+
}
|
|
2793
|
+
function recipeToScene(recipe, seed) {
|
|
2794
|
+
let points = {};
|
|
2795
|
+
for (let point of recipe.points ?? [])
|
|
2796
|
+
points[point.name] = [point.at[0] ?? 0, point.at[1] ?? 0];
|
|
2797
|
+
let objects = {};
|
|
2798
|
+
for (let group of recipe.objects) {
|
|
2799
|
+
let spec = { kind: group.kind, count: group.count };
|
|
2800
|
+
for (let field of [
|
|
2801
|
+
"near",
|
|
2802
|
+
"within",
|
|
2803
|
+
"facing",
|
|
2804
|
+
"along",
|
|
2805
|
+
"on",
|
|
2806
|
+
"clear",
|
|
2807
|
+
"reachable_from"
|
|
2808
|
+
])
|
|
2809
|
+
group[field] !== void 0 && (spec[field] = group[field]);
|
|
2810
|
+
objects[group.name] = spec;
|
|
2811
|
+
}
|
|
2812
|
+
return {
|
|
2813
|
+
area: {
|
|
2814
|
+
size: [recipe.size[0] ?? (2), recipe.size[1] ?? (2)],
|
|
2815
|
+
ground: recipe.ground,
|
|
2816
|
+
points
|
|
2817
|
+
},
|
|
2818
|
+
objects,
|
|
2819
|
+
...recipe.style === void 0 ? {} : { style: recipe.style },
|
|
2820
|
+
seed
|
|
2821
|
+
};
|
|
2822
|
+
}
|
|
2823
|
+
function solveRoom(recipe, seed, compile, solver) {
|
|
2824
|
+
let compiled = compile(recipe.name, recipeToScene(recipe, seed));
|
|
2825
|
+
return compiled.wire === null ? { status: "rejected", diagnostics: compiled.diagnostics } : { status: "solved", result: solver.solve(compiled.wire, seed), seed };
|
|
2826
|
+
}
|
|
2827
|
+
|
|
2828
|
+
// src/interactives/generate/tick.ts
|
|
2829
|
+
var CONTENT_CHANNEL_SLOT = FRAME_LIMITS.game_channel_slots - 4, CONTENT_FRAGMENT_HEADER_BYTES = 8, MAX_PENDING_RECORDS = 32;
|
|
2830
|
+
function utf8(text) {
|
|
2831
|
+
let out = [];
|
|
2832
|
+
for (let char of text) {
|
|
2833
|
+
let code = char.codePointAt(0) ?? 0;
|
|
2834
|
+
code < 128 ? out.push(code) : code < 2048 ? out.push(192 | code >> 6, 128 | code & 63) : code < 65536 ? out.push(224 | code >> 12, 128 | code >> 6 & 63, 128 | code & 63) : out.push(
|
|
2835
|
+
240 | code >> 18,
|
|
2836
|
+
128 | code >> 12 & 63,
|
|
2837
|
+
128 | code >> 6 & 63,
|
|
2838
|
+
128 | code & 63
|
|
2839
|
+
);
|
|
2840
|
+
}
|
|
2841
|
+
return Uint8Array.from(out);
|
|
2842
|
+
}
|
|
2843
|
+
function tickContentAsk(key, kind, request) {
|
|
2844
|
+
let timeout = Math.min(
|
|
2845
|
+
Math.max(Math.round(request.timeoutMs ?? DEFAULT_TIMEOUT_MS), MIN_TIMEOUT_MS),
|
|
2846
|
+
MAX_TIMEOUT_MS
|
|
2847
|
+
);
|
|
2848
|
+
return utf8(
|
|
2849
|
+
JSON.stringify({
|
|
2850
|
+
key,
|
|
2851
|
+
kind,
|
|
2852
|
+
prompt: request.prompt,
|
|
2853
|
+
schema: kind === "dialogue" && request.schema === void 0 ? null : request.schema?.json ?? null,
|
|
2854
|
+
rules: request.rules ?? [],
|
|
2855
|
+
slots: request.slots ?? [],
|
|
2856
|
+
context: request.context ?? null,
|
|
2857
|
+
language: request.language ?? null,
|
|
2858
|
+
variant: request.variant ?? 0,
|
|
2859
|
+
seed: request.seed ?? null,
|
|
2860
|
+
retries: request.retries ?? DEFAULT_RETRIES,
|
|
2861
|
+
timeout_ms: timeout
|
|
2862
|
+
})
|
|
2863
|
+
);
|
|
2864
|
+
}
|
|
2865
|
+
function requestTickContent(ctx, key, kind, request) {
|
|
2866
|
+
return ctx.outbox(1, tickContentAsk(key, kind, request));
|
|
2867
|
+
}
|
|
2868
|
+
function createTickContentLink(roomId, subscribe) {
|
|
2869
|
+
let listeners = /* @__PURE__ */ new Set(), pending = /* @__PURE__ */ new Map(), unsubscribe = subscribe((payload) => {
|
|
2870
|
+
if (payload.length < (8)) return;
|
|
2871
|
+
let view2 = new DataView(payload.buffer, payload.byteOffset, payload.byteLength), record = view2.getUint32(0, true), index = view2.getUint16(4, true), count2 = view2.getUint16(6, true);
|
|
2872
|
+
if (count2 === 0 || index >= count2) return;
|
|
2873
|
+
let parts = pending.get(record);
|
|
2874
|
+
if ((parts === void 0 || parts.length !== count2) && (parts = new Array(count2).fill(null), pending.set(record, parts), pending.size > (32))) {
|
|
2875
|
+
let oldest = pending.keys().next().value;
|
|
2876
|
+
oldest !== void 0 && oldest !== record && pending.delete(oldest);
|
|
2877
|
+
}
|
|
2878
|
+
if (parts[index] = payload.slice((8)), parts.some((part) => part === null)) return;
|
|
2879
|
+
pending.delete(record);
|
|
2880
|
+
let total = parts.reduce((sum, part) => sum + (part?.length ?? 0), 0), joined = new Uint8Array(total), offset = 0;
|
|
2881
|
+
for (let part of parts)
|
|
2882
|
+
part !== null && (joined.set(part, offset), offset += part.length);
|
|
2883
|
+
for (let listener of listeners) listener(joined);
|
|
2884
|
+
});
|
|
2885
|
+
return {
|
|
2886
|
+
roomId,
|
|
2887
|
+
authority: false,
|
|
2888
|
+
publish: () => {
|
|
2889
|
+
},
|
|
2890
|
+
subscribe: (listener) => (listeners.add(listener), () => {
|
|
2891
|
+
listeners.delete(listener), listeners.size === 0 && unsubscribe();
|
|
2892
|
+
})
|
|
2893
|
+
};
|
|
2894
|
+
}
|
|
2895
|
+
|
|
2896
|
+
// src/interactives/parts/index.ts
|
|
2897
|
+
var parts_exports = {};
|
|
2898
|
+
__export(parts_exports, {
|
|
2899
|
+
CDC_MAX_BYTES: () => CDC_MAX_BYTES,
|
|
2900
|
+
CDC_MIN_BYTES: () => CDC_MIN_BYTES,
|
|
2901
|
+
DELTA_LIMIT: () => (0.5),
|
|
2902
|
+
DeltaOp: () => DeltaOp,
|
|
2903
|
+
MANIFEST_HEADER_BYTES: () => MANIFEST_HEADER_BYTES,
|
|
2904
|
+
MANIFEST_MAGIC: () => MANIFEST_MAGIC,
|
|
2905
|
+
MANIFEST_PART_BYTES: () => MANIFEST_PART_BYTES,
|
|
2906
|
+
MANIFEST_VERSION: () => MANIFEST_VERSION,
|
|
2907
|
+
MAX_ASSET_BYTES: () => MAX_ASSET_BYTES,
|
|
2908
|
+
MAX_MANIFEST_PARTS: () => MAX_MANIFEST_PARTS,
|
|
2909
|
+
MIN_PART_BYTES: () => (2048),
|
|
2910
|
+
PART_HEADER_BYTES: () => PART_HEADER_BYTES,
|
|
2911
|
+
PART_MAGIC: () => PART_MAGIC,
|
|
2912
|
+
PART_VERSION: () => PART_VERSION,
|
|
2913
|
+
PartFormatError: () => PartFormatError,
|
|
2914
|
+
PartIndex: () => PartIndex,
|
|
2915
|
+
PartKind: () => PartKind,
|
|
2916
|
+
SEGMENT_BYTES: () => SEGMENT_BYTES,
|
|
2917
|
+
SegmentOp: () => SegmentOp,
|
|
2918
|
+
WEAVE_BOUNDARY_MASK: () => WEAVE_BOUNDARY_MASK,
|
|
2919
|
+
WEAVE_CHILD_ENTRY_BYTES: () => WEAVE_CHILD_ENTRY_BYTES,
|
|
2920
|
+
WEAVE_HEAD_DOMAIN: () => WEAVE_HEAD_DOMAIN,
|
|
2921
|
+
WEAVE_LEAF_DECORATED: () => WEAVE_LEAF_DECORATED,
|
|
2922
|
+
WEAVE_LEAF_ENTRY_BYTES: () => WEAVE_LEAF_ENTRY_BYTES,
|
|
2923
|
+
WEAVE_LEAF_TWINNED: () => WEAVE_LEAF_TWINNED,
|
|
2924
|
+
WEAVE_MAX_HEIGHT: () => WEAVE_MAX_HEIGHT,
|
|
2925
|
+
WEAVE_MAX_NODE_BYTES: () => WEAVE_MAX_NODE_BYTES,
|
|
2926
|
+
WEAVE_MAX_NODE_ENTRIES: () => WEAVE_MAX_NODE_ENTRIES,
|
|
2927
|
+
WEAVE_MIN_NODE_ENTRIES: () => WEAVE_MIN_NODE_ENTRIES,
|
|
2928
|
+
WEAVE_NODE_HEADER_BYTES: () => WEAVE_NODE_HEADER_BYTES,
|
|
2929
|
+
WEAVE_NODE_MAGIC: () => WEAVE_NODE_MAGIC,
|
|
2930
|
+
WEAVE_NODE_ZONE: () => WEAVE_NODE_ZONE,
|
|
2931
|
+
WEAVE_VERSION: () => WEAVE_VERSION,
|
|
2932
|
+
WeaveRefusal: () => WeaveRefusal,
|
|
2933
|
+
WeaveVerifyError: () => WeaveVerifyError,
|
|
2934
|
+
applyDelta: () => applyDelta,
|
|
2935
|
+
assemble: () => assemble,
|
|
2936
|
+
assembleInto: () => assembleInto,
|
|
2937
|
+
buildAsset: () => buildAsset,
|
|
2938
|
+
buildWeave: () => buildWeave,
|
|
2939
|
+
childDigestAt: () => childDigestAt,
|
|
2940
|
+
chunkWeaveSource: () => chunkWeaveSource,
|
|
2941
|
+
coalesce: () => coalesce,
|
|
2942
|
+
combinedBases: () => combinedBases,
|
|
2943
|
+
contentSpans: () => contentSpans,
|
|
2944
|
+
decodeManifest: () => decodeManifest,
|
|
2945
|
+
decodePart: () => decodePart,
|
|
2946
|
+
deliverSchedule: () => deliverSchedule,
|
|
2947
|
+
encodeDelta: () => encodeDelta,
|
|
2948
|
+
encodeManifest: () => encodeManifest,
|
|
2949
|
+
encodePart: () => encodePart,
|
|
2950
|
+
isManifest: () => isManifest,
|
|
2951
|
+
leafAt: () => leafAt,
|
|
2952
|
+
leafDigest: () => leafDigest,
|
|
2953
|
+
leafDigestAt: () => leafDigestAt,
|
|
2954
|
+
leafFlags: () => leafFlags,
|
|
2955
|
+
leafLength: () => leafLength,
|
|
2956
|
+
leafZone: () => leafZone,
|
|
2957
|
+
manifestBytes: () => manifestBytes,
|
|
2958
|
+
nodeMatches: () => nodeMatches,
|
|
2959
|
+
openWeaveHead: () => openWeaveHead,
|
|
2960
|
+
openWeaveSession: () => openWeaveSession,
|
|
2961
|
+
partKindName: () => partKindName,
|
|
2962
|
+
planWeave: () => planWeave,
|
|
2963
|
+
progressiveSpans: () => progressiveSpans,
|
|
2964
|
+
sealPart: () => sealPart,
|
|
2965
|
+
segmentOutput: () => segmentOutput,
|
|
2966
|
+
soleSpan: () => soleSpan,
|
|
2967
|
+
splitAsset: () => splitAsset,
|
|
2968
|
+
storeWeaveSource: () => storeWeaveSource,
|
|
2969
|
+
structuralSpans: () => structuralSpans,
|
|
2970
|
+
unweaveIndex: () => unweaveIndex,
|
|
2971
|
+
validWeaveRoot: () => validWeaveRoot,
|
|
2972
|
+
verifyChild: () => verifyChild,
|
|
2973
|
+
verifyRoot: () => verifyRoot,
|
|
2974
|
+
walkWeave: () => walkWeave,
|
|
2975
|
+
weaveHeadMessage: () => weaveHeadMessage,
|
|
2976
|
+
weaveNodeCount: () => weaveNodeCount,
|
|
2977
|
+
weaveNodeLevel: () => weaveNodeLevel,
|
|
2978
|
+
weaveNodeValid: () => weaveNodeValid,
|
|
2979
|
+
weaveParts: () => weaveParts,
|
|
2980
|
+
woven: () => woven
|
|
2981
|
+
});
|
|
2982
|
+
|
|
2983
|
+
// src/interactives/parts/split.ts
|
|
2984
|
+
var MIN_PART_BYTES = 2048, CDC_MIN_BYTES = 8 * 1024, CDC_MAX_BYTES = 128 * 1024, CDC_MASK = 32767, GEAR_SEED = 2654435769, GLB_MAGIC = 1179937895, GLB_VERSION = 2, GLB_HEADER_BYTES = 12, GLB_CHUNK_HEADER_BYTES = 8, GLB_JSON = 1313821514, GLB_BIN = 5130562, KTX2_IDENTIFIER = [171, 75, 84, 88, 32, 50, 48, 187, 13, 10, 26, 10], KTX2_LEVEL_COUNT = 40, KTX2_LEVEL_INDEX = 80, KTX2_LEVEL_BYTES = 24, CELLS_MAGIC = 1263556419, CELLS_HEADER_BYTES = 16, CELLS_ENTRY_BYTES = 16, WORLD_MAGIC = 1145853763;
|
|
2985
|
+
function view(bytes) {
|
|
2986
|
+
return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
2987
|
+
}
|
|
2988
|
+
function gearTable() {
|
|
2989
|
+
let table = new Uint32Array(256), x = (2654435769);
|
|
2990
|
+
for (let i = 0; i < 256; i++)
|
|
2991
|
+
x ^= x << 13, x ^= x >>> 17, x ^= x << 5, table[i] = x >>> 0;
|
|
2992
|
+
return table;
|
|
2993
|
+
}
|
|
2994
|
+
var GEAR = gearTable();
|
|
2995
|
+
function contentSpans(bytes, start, end, kind) {
|
|
2996
|
+
let out = [], at = start;
|
|
2997
|
+
for (; at < end; ) {
|
|
2998
|
+
let limit = Math.min(end, at + CDC_MAX_BYTES), cut = limit;
|
|
2999
|
+
if (limit - at > CDC_MIN_BYTES) {
|
|
3000
|
+
let h = 0;
|
|
3001
|
+
for (let i = at + CDC_MIN_BYTES; i < limit; i++)
|
|
3002
|
+
if (h = (h << 1) + GEAR[bytes[i]] >>> 0, (h & (32767)) === 0) {
|
|
3003
|
+
cut = i + 1;
|
|
3004
|
+
break;
|
|
3005
|
+
}
|
|
3006
|
+
}
|
|
3007
|
+
out.push({ start: at, end: cut, kind }), at = cut;
|
|
3008
|
+
}
|
|
3009
|
+
return out;
|
|
3010
|
+
}
|
|
3011
|
+
function covering(length, ranges) {
|
|
3012
|
+
ranges.sort((a, b) => a.start - b.start || b.end - a.end);
|
|
3013
|
+
let out = [], cursor = 0;
|
|
3014
|
+
for (let r of ranges)
|
|
3015
|
+
r.start < cursor || r.end > length || r.end <= r.start || (r.start > cursor && out.push({ start: cursor, end: r.start, kind: null }), out.push(r), cursor = r.end);
|
|
3016
|
+
return cursor < length && out.push({ start: cursor, end: length, kind: null }), out;
|
|
3017
|
+
}
|
|
3018
|
+
function list(value) {
|
|
3019
|
+
return Array.isArray(value) ? value : [];
|
|
3020
|
+
}
|
|
3021
|
+
function num(value) {
|
|
3022
|
+
return typeof value == "number" && Number.isInteger(value) && value >= 0 ? value : null;
|
|
3023
|
+
}
|
|
3024
|
+
function glbViewKinds(gltf) {
|
|
3025
|
+
let kinds = /* @__PURE__ */ new Map(), accessors = list(gltf.accessors), mark = (accessor, kind) => {
|
|
3026
|
+
let a = num(accessor), view2 = a === null ? null : num(accessors[a]?.bufferView);
|
|
3027
|
+
view2 !== null && !kinds.has(view2) && kinds.set(view2, kind);
|
|
3028
|
+
};
|
|
3029
|
+
for (let mesh of list(gltf.meshes))
|
|
3030
|
+
for (let primitive of list(mesh.primitives)) {
|
|
3031
|
+
mark(primitive.indices, PartKind.mesh_index);
|
|
3032
|
+
let attributes = primitive.attributes ?? {};
|
|
3033
|
+
for (let key of Object.keys(attributes).sort()) mark(attributes[key], PartKind.mesh_vertex);
|
|
3034
|
+
for (let target of list(primitive.targets)) for (let key of Object.keys(target).sort()) mark(target[key], PartKind.mesh_vertex);
|
|
3035
|
+
}
|
|
3036
|
+
for (let skin of list(gltf.skins)) mark(skin.inverseBindMatrices, PartKind.skeleton);
|
|
3037
|
+
for (let animation of list(gltf.animations))
|
|
3038
|
+
for (let sampler of list(animation.samplers))
|
|
3039
|
+
mark(sampler.input, PartKind.clip), mark(sampler.output, PartKind.clip);
|
|
3040
|
+
for (let image of list(gltf.images)) {
|
|
3041
|
+
let view2 = num(image.bufferView);
|
|
3042
|
+
view2 !== null && !kinds.has(view2) && kinds.set(view2, PartKind.image);
|
|
3043
|
+
}
|
|
3044
|
+
return kinds;
|
|
3045
|
+
}
|
|
3046
|
+
function splitGlb(bytes) {
|
|
3047
|
+
if (bytes.length < (12) + (8)) return null;
|
|
3048
|
+
let v = view(bytes);
|
|
3049
|
+
if (v.getUint32(0, true) !== (1179937895) || v.getUint32(4, true) !== (2) || v.getUint32(8, true) !== bytes.length) return null;
|
|
3050
|
+
let jsonLength = v.getUint32((12), true);
|
|
3051
|
+
if (v.getUint32((12) + 4, true) !== (1313821514)) return null;
|
|
3052
|
+
let jsonStart = (12) + (8), jsonEnd = jsonStart + jsonLength;
|
|
3053
|
+
if (jsonEnd > bytes.length) return null;
|
|
3054
|
+
let gltf;
|
|
3055
|
+
try {
|
|
3056
|
+
gltf = JSON.parse(new TextDecoder().decode(bytes.subarray(jsonStart, jsonEnd)));
|
|
3057
|
+
} catch {
|
|
3058
|
+
return null;
|
|
3059
|
+
}
|
|
3060
|
+
let ranges = [{ start: jsonStart, end: jsonEnd, kind: PartKind.scene }], binHeader = jsonEnd;
|
|
3061
|
+
if (binHeader + (8) <= bytes.length && v.getUint32(binHeader + 4, true) === (5130562)) {
|
|
3062
|
+
let binStart = binHeader + (8), binEnd = Math.min(bytes.length, binStart + v.getUint32(binHeader, true)), kinds = glbViewKinds(gltf), views = list(gltf.bufferViews);
|
|
3063
|
+
for (let i = 0; i < views.length; i++) {
|
|
3064
|
+
let bufferView = views[i], kind = kinds.get(i) ?? PartKind.data, source = bufferView.extensions?.EXT_meshopt_compression ?? bufferView;
|
|
3065
|
+
if ((num(source.buffer) ?? 0) !== 0) continue;
|
|
3066
|
+
let offset = num(source.byteOffset) ?? 0, length = num(source.byteLength);
|
|
3067
|
+
if (length === null) continue;
|
|
3068
|
+
let start = binStart + offset, end = start + length;
|
|
3069
|
+
end <= binEnd && ranges.push({ start, end, kind });
|
|
3070
|
+
}
|
|
3071
|
+
}
|
|
3072
|
+
return covering(bytes.length, ranges);
|
|
3073
|
+
}
|
|
3074
|
+
function isKtx2(bytes) {
|
|
3075
|
+
if (bytes.length < (80)) return false;
|
|
3076
|
+
for (let i = 0; i < KTX2_IDENTIFIER.length; i++) if (bytes[i] !== KTX2_IDENTIFIER[i]) return false;
|
|
3077
|
+
return true;
|
|
3078
|
+
}
|
|
3079
|
+
function splitKtx2(bytes) {
|
|
3080
|
+
if (!isKtx2(bytes)) return null;
|
|
3081
|
+
let v = view(bytes), levels = Math.max(1, v.getUint32((40), true));
|
|
3082
|
+
if ((80) + levels * (24) > bytes.length) return null;
|
|
3083
|
+
let ranges = [];
|
|
3084
|
+
for (let l = 0; l < levels; l++) {
|
|
3085
|
+
let at = (80) + l * (24), offset = Number(v.getBigUint64(at, true)), length = Number(v.getBigUint64(at + 8, true));
|
|
3086
|
+
offset + length <= bytes.length && ranges.push({ start: offset, end: offset + length, kind: PartKind.texture });
|
|
3087
|
+
}
|
|
3088
|
+
return covering(bytes.length, ranges);
|
|
3089
|
+
}
|
|
3090
|
+
function splitCells(bytes) {
|
|
3091
|
+
if (bytes.length < (16)) return null;
|
|
3092
|
+
let v = view(bytes);
|
|
3093
|
+
if (v.getUint32(0, true) !== (1263556419)) return null;
|
|
3094
|
+
let count2 = v.getUint32(8, true);
|
|
3095
|
+
if ((16) + count2 * (16) > bytes.length) return null;
|
|
3096
|
+
let ranges = [];
|
|
3097
|
+
for (let e = 0; e < count2; e++) {
|
|
3098
|
+
let at = (16) + e * (16), offset = v.getUint32(at + 4, true), length = v.getUint32(at + 8, true);
|
|
3099
|
+
ranges.push({ start: offset, end: offset + length, kind: PartKind.cell });
|
|
3100
|
+
}
|
|
3101
|
+
return covering(bytes.length, ranges);
|
|
3102
|
+
}
|
|
3103
|
+
function expandLarge(bytes, spans) {
|
|
3104
|
+
let out = [];
|
|
3105
|
+
for (let s9 of spans)
|
|
3106
|
+
if (s9.kind !== null && s9.end - s9.start > CDC_MAX_BYTES) for (let c of contentSpans(bytes, s9.start, s9.end, s9.kind)) out.push(c);
|
|
3107
|
+
else out.push(s9);
|
|
3108
|
+
return out;
|
|
3109
|
+
}
|
|
3110
|
+
function joinSmall(spans, minPart) {
|
|
3111
|
+
let out = [];
|
|
3112
|
+
for (let i = 0; i < spans.length; i++) {
|
|
3113
|
+
let s9 = spans[i];
|
|
3114
|
+
if (s9.kind === null) {
|
|
3115
|
+
out.push(s9);
|
|
3116
|
+
continue;
|
|
3117
|
+
}
|
|
3118
|
+
let end = s9.end, j = i + 1;
|
|
3119
|
+
for (; end - s9.start < minPart; ) {
|
|
3120
|
+
let k = j;
|
|
3121
|
+
for (; k < spans.length && spans[k].kind === null && spans[k].end - spans[k].start <= (16) && spans[k].end - end <= (16); ) k++;
|
|
3122
|
+
let next = spans[k];
|
|
3123
|
+
if (next === void 0 || next.kind !== s9.kind || next.start - end > (16) || next.end - s9.start > CDC_MAX_BYTES) break;
|
|
3124
|
+
end = next.end, j = k + 1;
|
|
3125
|
+
}
|
|
3126
|
+
out.push({ start: s9.start, end, kind: s9.kind }), i = j - 1;
|
|
3127
|
+
}
|
|
3128
|
+
return out;
|
|
3129
|
+
}
|
|
3130
|
+
var MAX_JOIN_GAP = 16;
|
|
3131
|
+
function coalesce(input, minPart = (2048)) {
|
|
3132
|
+
let spans = joinSmall(input, minPart), out = [];
|
|
3133
|
+
for (let s9 of spans) {
|
|
3134
|
+
let kind = s9.kind !== null && s9.end - s9.start >= minPart ? s9.kind : null, last = out[out.length - 1];
|
|
3135
|
+
kind === null && last !== void 0 && last.kind === null && last.end === s9.start ? out[out.length - 1] = { start: last.start, end: s9.end, kind: null } : out.push({ start: s9.start, end: s9.end, kind });
|
|
3136
|
+
}
|
|
3137
|
+
return out;
|
|
3138
|
+
}
|
|
3139
|
+
function structuralSpans(bytes) {
|
|
3140
|
+
let structured = splitGlb(bytes) ?? splitKtx2(bytes) ?? splitCells(bytes);
|
|
3141
|
+
return structured !== null ? expandLarge(bytes, structured) : bytes.length >= 4 && view(bytes).getUint32(0, true) === (1145853763) ? contentSpans(bytes, 0, bytes.length, PartKind.data) : null;
|
|
3142
|
+
}
|
|
3143
|
+
var PROGRESSIVE_PART_KIND = {
|
|
3144
|
+
[ProgressiveKind.opaque]: PartKind.data,
|
|
3145
|
+
[ProgressiveKind.texture]: PartKind.texture,
|
|
3146
|
+
[ProgressiveKind.mesh]: PartKind.mesh_vertex,
|
|
3147
|
+
[ProgressiveKind.splat]: PartKind.data,
|
|
3148
|
+
[ProgressiveKind.audio]: PartKind.audio,
|
|
3149
|
+
[ProgressiveKind.cells]: PartKind.cell
|
|
3150
|
+
};
|
|
3151
|
+
function progressiveSpans(bytes) {
|
|
3152
|
+
let bounds2 = containerBounds(bytes);
|
|
3153
|
+
if (bounds2 === null) return null;
|
|
3154
|
+
let kind = PROGRESSIVE_PART_KIND[bounds2.kind] ?? PartKind.data, refine = [], at = bounds2.first;
|
|
3155
|
+
for (let end of bounds2.unitEnds)
|
|
3156
|
+
end <= at || (refine.push({ start: at, end, kind }), at = end);
|
|
3157
|
+
return { base: [{ start: 0, end: bounds2.first, kind }], refine };
|
|
3158
|
+
}
|
|
3159
|
+
function splitAsset(bytes, minPart = (2048)) {
|
|
3160
|
+
let progressive = progressiveSpans(bytes);
|
|
3161
|
+
if (progressive !== null) {
|
|
3162
|
+
let merged2 = [...coalesce(expandLarge(bytes, progressive.base), minPart), ...coalesce(expandLarge(bytes, progressive.refine), minPart)];
|
|
3163
|
+
return merged2.some((s9) => s9.kind !== null) ? merged2 : null;
|
|
3164
|
+
}
|
|
3165
|
+
let spans = structuralSpans(bytes);
|
|
3166
|
+
if (spans === null) return null;
|
|
3167
|
+
let merged = coalesce(spans, minPart);
|
|
3168
|
+
return merged.some((s9) => s9.kind !== null) ? merged : null;
|
|
3169
|
+
}
|
|
3170
|
+
|
|
3171
|
+
// src/interactives/parts/build.ts
|
|
3172
|
+
var DELTA_LIMIT = 0.5, ANCHOR_WINDOW = 64, ANCHOR_MASK = 511, MIN_SHARED_ANCHORS = 0.25, SAME_LENGTH_CANDIDATES = 4, HASH_BASE = 16777619;
|
|
3173
|
+
function anchors(body) {
|
|
3174
|
+
let out = /* @__PURE__ */ new Set(), h = 0;
|
|
3175
|
+
for (let i = 0; i < body.length; i++) {
|
|
3176
|
+
if (h = Math.imul(h, 31) + body[i] | 0, (h & (511)) !== 0 || i + (64) > body.length) continue;
|
|
3177
|
+
let w = 0;
|
|
3178
|
+
for (let j = i; j < i + (64); j++) w = Math.imul(w, (16777619)) + body[j] | 0;
|
|
3179
|
+
out.add(w);
|
|
3180
|
+
}
|
|
3181
|
+
return out;
|
|
3182
|
+
}
|
|
3183
|
+
function combinedBases(...sources) {
|
|
3184
|
+
return {
|
|
3185
|
+
has: (digest) => sources.some((s9) => s9.has(digest)),
|
|
3186
|
+
candidates: (kind, body) => {
|
|
3187
|
+
let out = [];
|
|
3188
|
+
for (let s9 of sources) for (let c of s9.candidates(kind, body)) out.some((o) => o.digest === c.digest) || out.push(c);
|
|
3189
|
+
return out;
|
|
3190
|
+
}
|
|
3191
|
+
};
|
|
3192
|
+
}
|
|
3193
|
+
var PartIndex = class {
|
|
3194
|
+
constructor() {
|
|
3195
|
+
this.parts = [];
|
|
3196
|
+
this.digests = /* @__PURE__ */ new Set();
|
|
3197
|
+
this.byAnchor = /* @__PURE__ */ new Map();
|
|
3198
|
+
this.byLength = /* @__PURE__ */ new Map();
|
|
3199
|
+
}
|
|
3200
|
+
get size() {
|
|
3201
|
+
return this.parts.length;
|
|
3202
|
+
}
|
|
3203
|
+
has(digest) {
|
|
3204
|
+
return this.digests.has(digest);
|
|
3205
|
+
}
|
|
3206
|
+
add(part) {
|
|
3207
|
+
if (this.digests.has(part.digest)) return;
|
|
3208
|
+
this.digests.add(part.digest);
|
|
3209
|
+
let at = this.parts.length;
|
|
3210
|
+
this.parts.push(part);
|
|
3211
|
+
for (let a of anchors(part.body)) {
|
|
3212
|
+
let list2 = this.byAnchor.get(a);
|
|
3213
|
+
list2 === void 0 ? this.byAnchor.set(a, [at]) : list2.push(at);
|
|
3214
|
+
}
|
|
3215
|
+
let key = `${part.kind}:${part.body.length}`, same = this.byLength.get(key);
|
|
3216
|
+
same === void 0 ? this.byLength.set(key, [at]) : same.push(at);
|
|
3217
|
+
}
|
|
3218
|
+
candidates(kind, body) {
|
|
3219
|
+
let out = [], mine = anchors(body);
|
|
3220
|
+
if (mine.size > 0) {
|
|
3221
|
+
let counts = /* @__PURE__ */ new Map();
|
|
3222
|
+
for (let a of mine) for (let at of this.byAnchor.get(a) ?? []) counts.set(at, (counts.get(at) ?? 0) + 1);
|
|
3223
|
+
let best = -1, bestCount = 0;
|
|
3224
|
+
for (let [at, count2] of counts)
|
|
3225
|
+
this.parts[at].kind === kind && (count2 > bestCount || count2 === bestCount && at < best) && (best = at, bestCount = count2);
|
|
3226
|
+
best >= 0 && bestCount >= mine.size * (0.25) && out.push(best);
|
|
3227
|
+
}
|
|
3228
|
+
for (let at of (this.byLength.get(`${kind}:${body.length}`) ?? []).slice(0, (4))) out.indexOf(at) < 0 && out.push(at);
|
|
3229
|
+
return out.map((at) => this.parts[at]);
|
|
3230
|
+
}
|
|
3231
|
+
}, Literal = class {
|
|
3232
|
+
constructor() {
|
|
3233
|
+
this.chunks = [];
|
|
3234
|
+
this.length = 0;
|
|
3235
|
+
}
|
|
3236
|
+
push(bytes) {
|
|
3237
|
+
let at = this.length;
|
|
3238
|
+
return this.chunks.push(bytes), this.length += bytes.length, at;
|
|
3239
|
+
}
|
|
3240
|
+
bytes() {
|
|
3241
|
+
let out = new Uint8Array(this.length), at = 0;
|
|
3242
|
+
for (let c of this.chunks)
|
|
3243
|
+
out.set(c, at), at += c.length;
|
|
3244
|
+
return out;
|
|
3245
|
+
}
|
|
3246
|
+
};
|
|
3247
|
+
function sealPart(kind, body, seal) {
|
|
3248
|
+
let payload = encodePart(kind, body);
|
|
3249
|
+
return { digest: seal(payload), kind, body: payload.subarray(payload.length - body.length), payload };
|
|
3250
|
+
}
|
|
3251
|
+
function buildAsset(bytes, assetKind, seal, options = {}) {
|
|
3252
|
+
let spans = splitAsset(bytes, options.minPart ?? (2048));
|
|
3253
|
+
if (spans === null) return null;
|
|
3254
|
+
let literal = new Literal(), refs = [], sealed = [], slot2 = /* @__PURE__ */ new Map(), segments = [], deltas = [], partSlot = (part) => {
|
|
3255
|
+
let known = slot2.get(part.digest);
|
|
3256
|
+
if (known !== void 0) return known;
|
|
3257
|
+
let at = refs.length;
|
|
3258
|
+
return slot2.set(part.digest, at), refs.push({ digest: part.digest, kind: part.kind, length: part.body.length }), sealed.push(part), at;
|
|
3259
|
+
};
|
|
3260
|
+
for (let span of spans) {
|
|
3261
|
+
let body = bytes.subarray(span.start, span.end);
|
|
3262
|
+
if (span.kind === null) {
|
|
3263
|
+
segments.push({ op: SegmentOp.literal, offset: literal.push(body), length: body.length });
|
|
3264
|
+
continue;
|
|
3265
|
+
}
|
|
3266
|
+
let part = sealPart(span.kind, body, seal), bases = options.bases ?? null, derived = false;
|
|
3267
|
+
if (bases !== null && !bases.has(part.digest))
|
|
3268
|
+
for (let base of bases.candidates(span.kind, body)) {
|
|
3269
|
+
let delta = encodeDelta(base.body, body, Math.floor(body.length * (0.5)));
|
|
3270
|
+
if (delta !== null) {
|
|
3271
|
+
segments.push({ op: SegmentOp.delta, part: partSlot(base), offset: literal.push(delta), length: delta.length, output: body.length }), deltas.push({ base: base.digest, variantBytes: body.length, deltaBytes: delta.length }), derived = true;
|
|
3272
|
+
break;
|
|
3273
|
+
}
|
|
3274
|
+
}
|
|
3275
|
+
derived || segments.push({ op: SegmentOp.part, part: partSlot(part), offset: 0, length: body.length });
|
|
3276
|
+
}
|
|
3277
|
+
let manifest = { kind: assetKind, length: bytes.length, parts: refs, segments, literal: literal.bytes() };
|
|
3278
|
+
return { manifest: encodeManifest(manifest), parts: sealed, deltas, literalBytes: manifest.literal.length };
|
|
3279
|
+
}
|
|
3280
|
+
|
|
3281
|
+
// src/interactives/progressive/index.ts
|
|
3282
|
+
var progressive_exports = {};
|
|
3283
|
+
__export(progressive_exports, {
|
|
3284
|
+
DEFAULT_PROGRESSIVE_KINDS: () => DEFAULT_PROGRESSIVE_KINDS,
|
|
3285
|
+
FILL_BYTE_MAX: () => FILL_BYTE_MAX,
|
|
3286
|
+
HEADER_BYTES: () => HEADER_BYTES,
|
|
3287
|
+
Header: () => Header,
|
|
3288
|
+
LEVEL_BYTES: () => LEVEL_BYTES,
|
|
3289
|
+
MAX_PROGRESSIVE_BYTES: () => MAX_PROGRESSIVE_BYTES,
|
|
3290
|
+
MAX_PROGRESSIVE_DECODE_BYTES: () => MAX_PROGRESSIVE_DECODE_BYTES,
|
|
3291
|
+
MERGE_PARAM_BYTES: () => MERGE_PARAM_BYTES,
|
|
3292
|
+
MIN_PROGRESSIVE_BYTES: () => MIN_PROGRESSIVE_BYTES,
|
|
3293
|
+
PATCH_BYTES: () => PATCH_BYTES,
|
|
3294
|
+
PPM: () => PPM,
|
|
3295
|
+
PROGRESSIVE_MAGIC: () => PROGRESSIVE_MAGIC,
|
|
3296
|
+
PROGRESSIVE_VERSION: () => PROGRESSIVE_VERSION,
|
|
3297
|
+
PatchOp: () => PatchOp,
|
|
3298
|
+
ProgressiveCancelled: () => ProgressiveCancelled,
|
|
3299
|
+
ProgressiveDecoder: () => ProgressiveDecoder,
|
|
3300
|
+
ProgressiveFeed: () => ProgressiveFeed,
|
|
3301
|
+
ProgressiveFormatError: () => ProgressiveFormatError,
|
|
3302
|
+
ProgressiveKind: () => ProgressiveKind,
|
|
3303
|
+
ProgressiveLayout: () => ProgressiveLayout,
|
|
3304
|
+
SAMPLE_BYTES: () => SAMPLE_BYTES,
|
|
3305
|
+
SEGMENT_BYTES: () => SEGMENT_BYTES2,
|
|
3306
|
+
SEGMENT_STAGED: () => SEGMENT_STAGED,
|
|
3307
|
+
TableWriter: () => TableWriter,
|
|
3308
|
+
UNIT_BYTES: () => UNIT_BYTES,
|
|
3309
|
+
UNLIFT_PARAM_BYTES: () => UNLIFT_PARAM_BYTES,
|
|
3310
|
+
buildProgressive: () => buildProgressive,
|
|
3311
|
+
checkLayout: () => checkLayout,
|
|
3312
|
+
coarseKeys: () => coarseKeys,
|
|
3313
|
+
containerBounds: () => containerBounds,
|
|
3314
|
+
decodeProgressive: () => decodeProgressive,
|
|
3315
|
+
encodeContainer: () => encodeContainer,
|
|
3316
|
+
headBytes: () => headBytes,
|
|
3317
|
+
isCoarseKey: () => isCoarseKey,
|
|
3318
|
+
isProgressive: () => isProgressive,
|
|
3319
|
+
liftForward: () => liftForward,
|
|
3320
|
+
planAudio: () => planAudio,
|
|
3321
|
+
planCells: () => planCells,
|
|
3322
|
+
planMesh: () => planMesh,
|
|
3323
|
+
planSplat: () => planSplat,
|
|
3324
|
+
planTexture: () => planTexture,
|
|
3325
|
+
progressiveKindName: () => progressiveKindName,
|
|
3326
|
+
readKtx2: () => readKtx2,
|
|
3327
|
+
readLayout: () => readLayout,
|
|
3328
|
+
writePatch: () => writePatch
|
|
3329
|
+
});
|
|
3330
|
+
|
|
3331
|
+
// src/interactives/progressive/audio.ts
|
|
3332
|
+
var RIFF = 1179011410, WAVE = 1163280727, FMT = 544501094, DATA = 1635017060, RIFF_HEADER_BYTES = 12, CHUNK_HEADER_BYTES = 8, PCM = 1, BITS = 16, FMT_CHANNELS = 2, FMT_RATE = 4, FMT_BYTE_RATE = 8, FMT_BITS = 14, FMT_MIN_BYTES = 16, RIFF_SIZE = 4, MIN_BASE_RATE = 8e3, MAX_BANDS = 3;
|
|
3333
|
+
function u32(value) {
|
|
3334
|
+
let out = new Uint8Array(4);
|
|
3335
|
+
return new DataView(out.buffer).setUint32(0, value, true), out;
|
|
3336
|
+
}
|
|
3337
|
+
function isWave(bytes) {
|
|
3338
|
+
if (bytes.length < (12)) return false;
|
|
3339
|
+
let v = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
3340
|
+
return v.getUint32(0, true) === (1179011410) && v.getUint32(8, true) === (1163280727);
|
|
3341
|
+
}
|
|
3342
|
+
function planAudio(bytes) {
|
|
3343
|
+
if (!isWave(bytes)) return null;
|
|
3344
|
+
let v = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength), at = (12), fmt = -1, dataStart = -1, dataBytes = 0;
|
|
3345
|
+
for (; at + (8) <= bytes.length; ) {
|
|
3346
|
+
let id = v.getUint32(at, true), size = v.getUint32(at + 4, true), body = at + (8);
|
|
3347
|
+
if (id === (544501094) && size >= (16) && (fmt = body), id === (1635017060)) {
|
|
3348
|
+
dataStart = body, dataBytes = size;
|
|
3349
|
+
break;
|
|
3350
|
+
}
|
|
3351
|
+
at = body + size + (size & 1);
|
|
3352
|
+
}
|
|
3353
|
+
if (fmt < 0 || dataStart < 0 || dataStart + dataBytes !== bytes.length || v.getUint16(fmt, true) !== (1) || v.getUint16(fmt + (14), true) !== (16)) return null;
|
|
3354
|
+
let channels = v.getUint16(fmt + (2), true), rate = v.getUint32(fmt + (4), true), block = channels * SAMPLE_BYTES;
|
|
3355
|
+
if (channels === 0 || dataBytes % block !== 0) return null;
|
|
3356
|
+
let frames = dataBytes / block, bands = 0;
|
|
3357
|
+
for (; bands < (3) && rate % 2 ** (bands + 1) === 0 && rate / 2 ** (bands + 1) >= (8e3) && frames >> bands + 1 > 0; ) bands++;
|
|
3358
|
+
if (bands === 0) return null;
|
|
3359
|
+
let samples = new Int16Array(frames * channels);
|
|
3360
|
+
for (let i = 0; i < samples.length; i++) samples[i] = v.getInt16(dataStart + i * SAMPLE_BYTES, true);
|
|
3361
|
+
let lows = [samples], details = [new Int16Array(0)], counts = [frames];
|
|
3362
|
+
for (let k = 1; k <= bands; k++) {
|
|
3363
|
+
let lifted = liftForward(lows[k - 1], counts[k - 1], channels);
|
|
3364
|
+
lows.push(lifted.low), details.push(lifted.detail), counts.push(Math.ceil(counts[k - 1] / 2));
|
|
3365
|
+
}
|
|
3366
|
+
let table = new TableWriter(), state = (k) => {
|
|
3367
|
+
let r = rate / 2 ** k, size = counts[k] * block;
|
|
3368
|
+
return [
|
|
3369
|
+
{ op: PatchOp.write, a: (4), b: table.bytes(u32(dataStart + size - (8))), c: 4 },
|
|
3370
|
+
{ op: PatchOp.write, a: fmt + (4), b: table.bytes(u32(r)), c: 4 },
|
|
3371
|
+
{ op: PatchOp.write, a: fmt + (8), b: table.bytes(u32(r * block)), c: 4 },
|
|
3372
|
+
{ op: PatchOp.write, a: dataStart - 4, b: table.bytes(u32(size)), c: 4 }
|
|
3373
|
+
];
|
|
3374
|
+
}, pcm = (s9) => {
|
|
3375
|
+
let out = new Uint8Array(s9.length * SAMPLE_BYTES), ov = new DataView(out.buffer);
|
|
3376
|
+
for (let i = 0; i < s9.length; i++) ov.setInt16(i * SAMPLE_BYTES, s9[i], true);
|
|
3377
|
+
return out;
|
|
3378
|
+
}, levels = [
|
|
3379
|
+
[
|
|
3380
|
+
{
|
|
3381
|
+
segments: [
|
|
3382
|
+
{ dest: 0, bytes: bytes.subarray(0, dataStart) },
|
|
3383
|
+
{ dest: dataStart, bytes: pcm(lows[bands]) }
|
|
3384
|
+
],
|
|
3385
|
+
patches: state(bands),
|
|
3386
|
+
quality: Math.floor(PPM / 2 ** bands)
|
|
3387
|
+
}
|
|
3388
|
+
]
|
|
3389
|
+
];
|
|
3390
|
+
for (let k = bands; k >= 1; k--) {
|
|
3391
|
+
let params = table.words(counts[k], counts[k - 1], channels);
|
|
3392
|
+
levels.push([
|
|
3393
|
+
{
|
|
3394
|
+
segments: [{ dest: 0, bytes: pcm(details[k]), staged: true }],
|
|
3395
|
+
patches: [{ op: PatchOp.unlift, a: dataStart, b: 0, c: params }, ...state(k - 1)],
|
|
3396
|
+
quality: k === 1 ? PPM : Math.floor(PPM / 2 ** (k - 1))
|
|
3397
|
+
}
|
|
3398
|
+
]);
|
|
3399
|
+
}
|
|
3400
|
+
return { kind: ProgressiveKind.audio, output: bytes.length, levels, table: table.finish() };
|
|
3401
|
+
}
|
|
3402
|
+
|
|
3403
|
+
// src/interactives/progressive/cells.ts
|
|
3404
|
+
var PACK_MAGIC = 1263556419, PACK_VERSION = 3, PACK_HEADER_BYTES = 16, PACK_ENTRY_BYTES = 16, PACK_COUNT = 8, ENTRY_OFFSET = 4, ENTRY_LENGTH = 8, ENTRY_LEVEL = 12, LEVEL_PROXY = 2;
|
|
3405
|
+
function isCellPack(bytes) {
|
|
3406
|
+
return bytes.length >= (16) && new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(0, true) === (1263556419);
|
|
3407
|
+
}
|
|
3408
|
+
function count(value) {
|
|
3409
|
+
let out = new Uint8Array(4);
|
|
3410
|
+
return new DataView(out.buffer).setUint32(0, value, true), out;
|
|
3411
|
+
}
|
|
3412
|
+
function planCells(bytes) {
|
|
3413
|
+
if (!isCellPack(bytes)) return null;
|
|
3414
|
+
let v = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
3415
|
+
if (v.getUint32(4, true) !== (3)) return null;
|
|
3416
|
+
let cells = v.getUint32((8), true), tableEnd = (16) + cells * (16);
|
|
3417
|
+
if (cells < 2 || tableEnd > bytes.length) return null;
|
|
3418
|
+
let offsets = [], level = (e) => v.getUint32((16) + e * (16) + (12), true), tiers = level(0) === (2);
|
|
3419
|
+
for (let e = 0; e < cells; e++) {
|
|
3420
|
+
let at = (16) + e * (16), offset = v.getUint32(at + (4), true), length = v.getUint32(at + (8), true);
|
|
3421
|
+
if ((tiers ? level(e) !== (2) : level(e) >= (2)) || offset < tableEnd || offset + length > bytes.length || e > 0 && offset <= offsets[e - 1] || e > 0 && offsets[e - 1] + v.getUint32(at - (16) + (8), true) > offset) return null;
|
|
3422
|
+
offsets.push(offset);
|
|
3423
|
+
}
|
|
3424
|
+
let end = (e) => e + 1 < cells ? offsets[e + 1] : bytes.length, bodies = bytes.length - offsets[0], table = new TableWriter(), quality = (e) => e === cells - 1 ? PPM : Math.floor((end(e) - offsets[0]) * PPM / bodies), levels = [[{ segments: [{ dest: 0, bytes: bytes.subarray(0, end(0)) }], patches: [writePatch(table, (8), count(1))], quality: quality(0) }]];
|
|
3425
|
+
for (let e = 1; e < cells; e++) {
|
|
3426
|
+
let unit = { segments: [{ dest: offsets[e], bytes: bytes.subarray(offsets[e], end(e)) }], patches: [writePatch(table, (8), count(e + 1))], quality: quality(e) };
|
|
3427
|
+
(e & e - 1) === 0 && levels.push([]), levels[levels.length - 1].push(unit);
|
|
3428
|
+
}
|
|
3429
|
+
return { kind: ProgressiveKind.cells, output: bytes.length, levels, table: table.finish() };
|
|
3430
|
+
}
|
|
3431
|
+
|
|
3432
|
+
// src/interactives/progressive/simplify.ts
|
|
3433
|
+
function stampKey(from, to) {
|
|
3434
|
+
return from * 1048576 + to % 1048576;
|
|
3435
|
+
}
|
|
3436
|
+
var LOD_RATIO = 4, MIN_LOD_TRIANGLES = 64, MIN_PROGRESSIVE_TRIANGLES = 256, Heap = class {
|
|
3437
|
+
constructor() {
|
|
3438
|
+
this.cost = [];
|
|
3439
|
+
this.from = [];
|
|
3440
|
+
this.to = [];
|
|
3441
|
+
this.stamp = [];
|
|
3442
|
+
}
|
|
3443
|
+
get size() {
|
|
3444
|
+
return this.cost.length;
|
|
3445
|
+
}
|
|
3446
|
+
push(cost, from, to, stamp) {
|
|
3447
|
+
let i = this.cost.length;
|
|
3448
|
+
for (this.cost.push(cost), this.from.push(from), this.to.push(to), this.stamp.push(stamp); i > 0; ) {
|
|
3449
|
+
let parent = i - 1 >> 1;
|
|
3450
|
+
if (!this.less(i, parent)) break;
|
|
3451
|
+
this.swap(i, parent), i = parent;
|
|
3452
|
+
}
|
|
3453
|
+
}
|
|
3454
|
+
less(a, b) {
|
|
3455
|
+
let d = this.cost[a] - this.cost[b];
|
|
3456
|
+
return d !== 0 ? d < 0 : this.from[a] - this.from[b] < 0 || this.from[a] === this.from[b] && this.to[a] < this.to[b];
|
|
3457
|
+
}
|
|
3458
|
+
swap(a, b) {
|
|
3459
|
+
let c = this.cost[a];
|
|
3460
|
+
this.cost[a] = this.cost[b], this.cost[b] = c;
|
|
3461
|
+
let f = this.from[a];
|
|
3462
|
+
this.from[a] = this.from[b], this.from[b] = f;
|
|
3463
|
+
let t2 = this.to[a];
|
|
3464
|
+
this.to[a] = this.to[b], this.to[b] = t2;
|
|
3465
|
+
let s9 = this.stamp[a];
|
|
3466
|
+
this.stamp[a] = this.stamp[b], this.stamp[b] = s9;
|
|
3467
|
+
}
|
|
3468
|
+
pop(out) {
|
|
3469
|
+
if (this.cost.length === 0) return false;
|
|
3470
|
+
out[0] = this.from[0], out[1] = this.to[0], out[2] = this.stamp[0];
|
|
3471
|
+
let last = this.cost.length - 1;
|
|
3472
|
+
this.swap(0, last), this.cost.pop(), this.from.pop(), this.to.pop(), this.stamp.pop();
|
|
3473
|
+
let i = 0, n = this.cost.length;
|
|
3474
|
+
for (; ; ) {
|
|
3475
|
+
let l = 2 * i + 1, r = l + 1, m = i;
|
|
3476
|
+
if (l < n && this.less(l, m) && (m = l), r < n && this.less(r, m) && (m = r), m === i) break;
|
|
3477
|
+
this.swap(i, m), i = m;
|
|
3478
|
+
}
|
|
3479
|
+
return true;
|
|
3480
|
+
}
|
|
3481
|
+
};
|
|
3482
|
+
function addPlane(q, at, nx, ny, nz, d, w) {
|
|
3483
|
+
q[at] += w * nx * nx, q[at + 1] += w * nx * ny, q[at + 2] += w * nx * nz, q[at + 3] += w * nx * d, q[at + 4] += w * ny * ny, q[at + 5] += w * ny * nz, q[at + 6] += w * ny * d, q[at + 7] += w * nz * nz, q[at + 8] += w * nz * d, q[at + 9] += w * d * d;
|
|
3484
|
+
}
|
|
3485
|
+
function evaluate(q, a, b, x, y, z) {
|
|
3486
|
+
let s9 = (k) => q[a + k] + q[b + k];
|
|
3487
|
+
return s9(0) * x * x + 2 * s9(1) * x * y + 2 * s9(2) * x * z + 2 * s9(3) * x + s9(4) * y * y + 2 * s9(5) * y * z + 2 * s9(6) * y + s9(7) * z * z + 2 * s9(8) * z + s9(9);
|
|
3488
|
+
}
|
|
3489
|
+
function weld(positions, vertices) {
|
|
3490
|
+
let bits = new Uint32Array(positions.buffer, positions.byteOffset, vertices * 3), seen = /* @__PURE__ */ new Map(), of = new Int32Array(vertices);
|
|
3491
|
+
for (let w = 0; w < vertices; w++) {
|
|
3492
|
+
let key = `${bits[w * 3]},${bits[w * 3 + 1]},${bits[w * 3 + 2]}`, known = seen.get(key);
|
|
3493
|
+
known === void 0 ? (of[w] = seen.size, seen.set(key, seen.size)) : of[w] = known;
|
|
3494
|
+
}
|
|
3495
|
+
return { of, count: seen.size };
|
|
3496
|
+
}
|
|
3497
|
+
function simplifyLods(input, targets) {
|
|
3498
|
+
let { positions, indices, vertices, signatures, signatureWidth } = input, faces = indices.length / 3, { of, count: count2 } = weld(positions, vertices), px = new Float64Array(count2), py = new Float64Array(count2), pz = new Float64Array(count2);
|
|
3499
|
+
for (let w = 0; w < vertices; w++)
|
|
3500
|
+
px[of[w]] = positions[w * 3], py[of[w]] = positions[w * 3 + 1], pz[of[w]] = positions[w * 3 + 2];
|
|
3501
|
+
let corners = Int32Array.from(indices), alive = new Uint8Array(faces).fill(1), ring = Array.from({ length: count2 }, () => []);
|
|
3502
|
+
for (let f = 0; f < faces; f++) for (let k = 0; k < 3; k++) ring[of[corners[f * 3 + k]]].push(f);
|
|
3503
|
+
let q = new Float64Array(count2 * 10), normal = (f, out) => {
|
|
3504
|
+
let a = of[corners[f * 3]], b = of[corners[f * 3 + 1]], c = of[corners[f * 3 + 2]], ux = px[b] - px[a], uy = py[b] - py[a], uz = pz[b] - pz[a], vx = px[c] - px[a], vy = py[c] - py[a], vz = pz[c] - pz[a], nx = uy * vz - uz * vy, ny = uz * vx - ux * vz, nz = ux * vy - uy * vx, len = Math.hypot(nx, ny, nz);
|
|
3505
|
+
return out[0] = len > 0 ? nx / len : 0, out[1] = len > 0 ? ny / len : 0, out[2] = len > 0 ? nz / len : 0, len * 0.5;
|
|
3506
|
+
}, n = [0, 0, 0], edgeFaces = /* @__PURE__ */ new Map(), edgeKey = (a, b) => a < b ? a * count2 + b : b * count2 + a;
|
|
3507
|
+
for (let f = 0; f < faces; f++) {
|
|
3508
|
+
let area = normal(f, n), a = of[corners[f * 3]];
|
|
3509
|
+
if (area > 1e-12) {
|
|
3510
|
+
let d = -(n[0] * px[a] + n[1] * py[a] + n[2] * pz[a]);
|
|
3511
|
+
for (let k = 0; k < 3; k++) addPlane(q, of[corners[f * 3 + k]] * 10, n[0], n[1], n[2], d, area);
|
|
3512
|
+
}
|
|
3513
|
+
for (let k = 0; k < 3; k++) {
|
|
3514
|
+
let key = edgeKey(of[corners[f * 3 + k]], of[corners[f * 3 + (k + 1) % 3]]), list2 = edgeFaces.get(key);
|
|
3515
|
+
list2 === void 0 ? edgeFaces.set(key, [f]) : list2.push(f);
|
|
3516
|
+
}
|
|
3517
|
+
}
|
|
3518
|
+
let wedgeAt = (f, p) => {
|
|
3519
|
+
for (let k = 0; k < 3; k++) if (of[corners[f * 3 + k]] === p) return corners[f * 3 + k];
|
|
3520
|
+
return -1;
|
|
3521
|
+
};
|
|
3522
|
+
for (let [key, list2] of edgeFaces) {
|
|
3523
|
+
let a = Math.floor(key / count2), b = key % count2, seam = list2.length === 2 && (wedgeAt(list2[0], a) !== wedgeAt(list2[1], a) || wedgeAt(list2[0], b) !== wedgeAt(list2[1], b));
|
|
3524
|
+
if (list2.length !== 1 && !seam) continue;
|
|
3525
|
+
let weight = list2.length === 1 ? 16 : 2;
|
|
3526
|
+
for (let f of list2) {
|
|
3527
|
+
normal(f, n);
|
|
3528
|
+
let ex = px[b] - px[a], ey = py[b] - py[a], ez = pz[b] - pz[a], cx = ey * n[2] - ez * n[1], cy = ez * n[0] - ex * n[2], cz = ex * n[1] - ey * n[0], len = Math.hypot(cx, cy, cz);
|
|
3529
|
+
if (len <= 0) continue;
|
|
3530
|
+
cx /= len, cy /= len, cz /= len;
|
|
3531
|
+
let d = -(cx * px[a] + cy * py[a] + cz * pz[a]), w = weight * (ex * ex + ey * ey + ez * ez);
|
|
3532
|
+
addPlane(q, a * 10, cx, cy, cz, d, w), addPlane(q, b * 10, cx, cy, cz, d, w);
|
|
3533
|
+
}
|
|
3534
|
+
}
|
|
3535
|
+
let stamp = new Int32Array(count2), removed = new Uint8Array(count2), heap = new Heap(), cost = (u, v) => evaluate(q, u * 10, v * 10, px[v], py[v], pz[v]), pushAround = (u) => {
|
|
3536
|
+
let seen = /* @__PURE__ */ new Set();
|
|
3537
|
+
for (let f of ring[u])
|
|
3538
|
+
if (alive[f] !== 0)
|
|
3539
|
+
for (let k = 0; k < 3; k++) {
|
|
3540
|
+
let v = of[corners[f * 3 + k]];
|
|
3541
|
+
v === u || seen.has(v) || (seen.add(v), heap.push(cost(u, v), u, v, stampKey(stamp[u], stamp[v])), heap.push(cost(v, u), v, u, stampKey(stamp[v], stamp[u])));
|
|
3542
|
+
}
|
|
3543
|
+
};
|
|
3544
|
+
for (let p = 0; p < count2; p++) pushAround(p);
|
|
3545
|
+
let live = faces, lods = [], snapshot = () => {
|
|
3546
|
+
let out = new Uint32Array(live * 3), at = 0;
|
|
3547
|
+
for (let f = 0; f < faces; f++)
|
|
3548
|
+
alive[f] !== 0 && (out[at++] = corners[f * 3], out[at++] = corners[f * 3 + 1], out[at++] = corners[f * 3 + 2]);
|
|
3549
|
+
lods.push(out);
|
|
3550
|
+
}, before = [0, 0, 0], after = [0, 0, 0], nearest2 = (w, candidates) => {
|
|
3551
|
+
if (signatures === null || candidates.length === 1) return candidates[0];
|
|
3552
|
+
let best = candidates[0], bestDistance = 1 / 0;
|
|
3553
|
+
for (let c of candidates) {
|
|
3554
|
+
let d = 0;
|
|
3555
|
+
for (let k = 0; k < signatureWidth; k++) {
|
|
3556
|
+
let e = signatures[w * signatureWidth + k] - signatures[c * signatureWidth + k];
|
|
3557
|
+
d += e * e;
|
|
3558
|
+
}
|
|
3559
|
+
(d < bestDistance || d === bestDistance && c < best) && (best = c, bestDistance = d);
|
|
3560
|
+
}
|
|
3561
|
+
return best;
|
|
3562
|
+
}, valid = (u, v) => {
|
|
3563
|
+
let shared = false;
|
|
3564
|
+
for (let f of ring[u]) {
|
|
3565
|
+
if (alive[f] === 0) continue;
|
|
3566
|
+
let hasV = false;
|
|
3567
|
+
for (let k = 0; k < 3; k++) of[corners[f * 3 + k]] === v && (hasV = true);
|
|
3568
|
+
if (hasV) {
|
|
3569
|
+
shared = true;
|
|
3570
|
+
continue;
|
|
3571
|
+
}
|
|
3572
|
+
normal(f, before);
|
|
3573
|
+
let saved = [px[u], py[u], pz[u]];
|
|
3574
|
+
px[u] = px[v], py[u] = py[v], pz[u] = pz[v];
|
|
3575
|
+
let area = normal(f, after);
|
|
3576
|
+
if (px[u] = saved[0], py[u] = saved[1], pz[u] = saved[2], area <= 1e-12 || before[0] * after[0] + before[1] * after[1] + before[2] * after[2] < 0.25) return false;
|
|
3577
|
+
}
|
|
3578
|
+
return shared;
|
|
3579
|
+
}, collapse = (u, v) => {
|
|
3580
|
+
let mapped = /* @__PURE__ */ new Map(), targets2 = [];
|
|
3581
|
+
for (let f of ring[v])
|
|
3582
|
+
if (alive[f] !== 0)
|
|
3583
|
+
for (let k = 0; k < 3; k++) {
|
|
3584
|
+
let w = corners[f * 3 + k];
|
|
3585
|
+
of[w] === v && targets2.indexOf(w) < 0 && targets2.push(w);
|
|
3586
|
+
}
|
|
3587
|
+
for (let f of ring[u]) {
|
|
3588
|
+
if (alive[f] === 0) continue;
|
|
3589
|
+
let wu = wedgeAt(f, u), wv = wedgeAt(f, v);
|
|
3590
|
+
wv >= 0 && !mapped.has(wu) && mapped.set(wu, wv);
|
|
3591
|
+
}
|
|
3592
|
+
for (let f of ring[u])
|
|
3593
|
+
if (alive[f] !== 0) {
|
|
3594
|
+
if (wedgeAt(f, v) >= 0) {
|
|
3595
|
+
alive[f] = 0, live--;
|
|
3596
|
+
continue;
|
|
3597
|
+
}
|
|
3598
|
+
for (let k = 0; k < 3; k++) {
|
|
3599
|
+
let w = corners[f * 3 + k];
|
|
3600
|
+
if (of[w] !== u) continue;
|
|
3601
|
+
let to = mapped.get(w);
|
|
3602
|
+
to === void 0 && (to = nearest2(w, targets2), mapped.set(w, to)), corners[f * 3 + k] = to;
|
|
3603
|
+
}
|
|
3604
|
+
ring[v].push(f);
|
|
3605
|
+
}
|
|
3606
|
+
ring[u] = [], removed[u] = 1;
|
|
3607
|
+
for (let k = 0; k < 10; k++) q[v * 10 + k] += q[u * 10 + k];
|
|
3608
|
+
stamp[v]++;
|
|
3609
|
+
let neighbours = /* @__PURE__ */ new Set();
|
|
3610
|
+
for (let f of ring[v]) if (alive[f] === 1) for (let k = 0; k < 3; k++) neighbours.add(of[corners[f * 3 + k]]);
|
|
3611
|
+
for (let p of neighbours) p !== v && stamp[p]++;
|
|
3612
|
+
pushAround(v);
|
|
3613
|
+
for (let p of neighbours) p !== v && pushAround(p);
|
|
3614
|
+
}, popped = [0, 0, 0];
|
|
3615
|
+
for (let t2 = 0; t2 < targets.length; t2++) {
|
|
3616
|
+
let target = targets[t2];
|
|
3617
|
+
for (; live > target && heap.pop(popped); ) {
|
|
3618
|
+
let u = popped[0], v = popped[1];
|
|
3619
|
+
removed[u] === 1 || removed[v] === 1 || popped[2] === stampKey(stamp[u], stamp[v]) && valid(u, v) && collapse(u, v);
|
|
3620
|
+
}
|
|
3621
|
+
let previous = lods.length === 0 ? faces : lods[lods.length - 1].length / 3;
|
|
3622
|
+
if (live > target && live > previous * 0.8 || (snapshot(), live > target)) break;
|
|
3623
|
+
}
|
|
3624
|
+
return lods;
|
|
3625
|
+
}
|
|
3626
|
+
function lodTargets(triangles) {
|
|
3627
|
+
let out = [], t2 = Math.floor(triangles / (4));
|
|
3628
|
+
for (; t2 >= (64); )
|
|
3629
|
+
out.push(t2), t2 = Math.floor(t2 / (4));
|
|
3630
|
+
return out;
|
|
3631
|
+
}
|
|
3632
|
+
|
|
3633
|
+
// src/interactives/progressive/texture.ts
|
|
3634
|
+
var KTX2_IDENTIFIER2 = [171, 75, 84, 88, 32, 50, 48, 187, 13, 10, 26, 10], KTX2_WIDTH = 20, KTX2_HEIGHT = 24, KTX2_DEPTH = 28, KTX2_LEVEL_COUNT2 = 40, KTX2_SCHEME = 44, KTX2_LEVEL_INDEX2 = 80, KTX2_LEVEL_BYTES2 = 24, KTX2_LEVEL_LENGTH = 8, KTX2_MAX_LEVELS = 32, SCHEME_BASIS_LZ = 1, BASE_TEXTURE_EDGE = 64;
|
|
3635
|
+
function isKtx2At(bytes, start, end) {
|
|
3636
|
+
if (end - start < (80) + (24)) return false;
|
|
3637
|
+
for (let i = 0; i < KTX2_IDENTIFIER2.length; i++) if (bytes[start + i] !== KTX2_IDENTIFIER2[i]) return false;
|
|
3638
|
+
return true;
|
|
3639
|
+
}
|
|
3640
|
+
function readKtx2(bytes, start = 0, end = bytes.length) {
|
|
3641
|
+
if (!isKtx2At(bytes, start, end)) return null;
|
|
3642
|
+
let v = new DataView(bytes.buffer, bytes.byteOffset + start, end - start);
|
|
3643
|
+
if (v.getUint32((44), true) === (1)) return null;
|
|
3644
|
+
let levels = Math.max(1, v.getUint32((40), true));
|
|
3645
|
+
if (levels > (32) || (80) + levels * (24) > end - start) return null;
|
|
3646
|
+
let offsets = [];
|
|
3647
|
+
for (let l = 0; l < levels; l++) {
|
|
3648
|
+
let at = (80) + l * (24), offset = Number(v.getBigUint64(at, true)), length = Number(v.getBigUint64(at + (8), true));
|
|
3649
|
+
if (offset + length > end - start) return null;
|
|
3650
|
+
offsets.push(offset);
|
|
3651
|
+
}
|
|
3652
|
+
if (offsets[levels - 1] < (80) + levels * (24)) return null;
|
|
3653
|
+
for (let l = 0; l < levels; l++) {
|
|
3654
|
+
let length = Number(v.getBigUint64((80) + l * (24) + (8), true));
|
|
3655
|
+
if (offsets[l] + length > (l === 0 ? end - start : offsets[l - 1]) || l + 1 < levels && offsets[l + 1] >= offsets[l]) return null;
|
|
3656
|
+
}
|
|
3657
|
+
return { start, end, width: v.getUint32((20), true), height: v.getUint32((24), true), depth: v.getUint32((28), true), levels, offsets };
|
|
3658
|
+
}
|
|
3659
|
+
function levelEnd(k, level) {
|
|
3660
|
+
return k.start + (level === 0 ? k.end - k.start : k.offsets[level - 1]);
|
|
3661
|
+
}
|
|
3662
|
+
function levelStart(k, level) {
|
|
3663
|
+
return k.start + k.offsets[level];
|
|
3664
|
+
}
|
|
3665
|
+
function shrink(size, level) {
|
|
3666
|
+
return size === 0 ? 0 : Math.max(1, size >>> level);
|
|
3667
|
+
}
|
|
3668
|
+
function texels(k, level) {
|
|
3669
|
+
return shrink(k.width, level) * Math.max(1, shrink(k.height, level)) * Math.max(1, shrink(k.depth, level));
|
|
3670
|
+
}
|
|
3671
|
+
function baseLevel(k, edge = (64)) {
|
|
3672
|
+
let level = k.levels - 1;
|
|
3673
|
+
for (; level > 0 && Math.max(shrink(k.width, level - 1), shrink(k.height, level - 1)) <= edge; ) level--;
|
|
3674
|
+
return level;
|
|
3675
|
+
}
|
|
3676
|
+
var KtxStates = class {
|
|
3677
|
+
constructor(bytes, k, table) {
|
|
3678
|
+
this.bytes = bytes;
|
|
3679
|
+
this.k = k;
|
|
3680
|
+
this.table = table;
|
|
3681
|
+
this.indexAt = -1;
|
|
3682
|
+
}
|
|
3683
|
+
state(finest) {
|
|
3684
|
+
let k = this.k, index = k.start + (80);
|
|
3685
|
+
this.indexAt < 0 && (this.indexAt = this.table.bytes(Uint8Array.from(this.bytes.subarray(index, index + k.levels * (24)))));
|
|
3686
|
+
let fields = Uint8Array.from(this.bytes.subarray(k.start + (20), k.start + (40) + 4)), d = new DataView(fields.buffer);
|
|
3687
|
+
return d.setUint32((20) - (20), shrink(k.width, finest), true), d.setUint32((24) - (20), shrink(k.height, finest), true), d.setUint32((28) - (20), shrink(k.depth, finest), true), d.setUint32((40) - (20), k.levels - finest, true), [
|
|
3688
|
+
writePatch(this.table, k.start + (20), fields),
|
|
3689
|
+
{ op: PatchOp.write, a: index, b: this.indexAt + finest * (24), c: (k.levels - finest) * (24) }
|
|
3690
|
+
];
|
|
3691
|
+
}
|
|
3692
|
+
};
|
|
3693
|
+
function planTexture(bytes) {
|
|
3694
|
+
let k = readKtx2(bytes);
|
|
3695
|
+
if (k === null) return null;
|
|
3696
|
+
let table = new TableWriter(), states = new KtxStates(bytes, k, table), full = texels(k, 0), base = baseLevel(k), quality = (level) => Math.floor(texels(k, level) * PPM / full), levels = [
|
|
3697
|
+
[{ segments: [{ dest: 0, bytes: bytes.subarray(0, levelEnd(k, base)) }], patches: base === 0 ? [] : states.state(base), quality: base === 0 ? PPM : quality(base) }]
|
|
3698
|
+
];
|
|
3699
|
+
for (let level = base - 1; level >= 0; level--) {
|
|
3700
|
+
let start = levelStart(k, level);
|
|
3701
|
+
levels.push([{ segments: [{ dest: start, bytes: bytes.subarray(start, levelEnd(k, level)) }], patches: states.state(level), quality: level === 0 ? PPM : quality(level) }]);
|
|
3702
|
+
}
|
|
3703
|
+
return { kind: ProgressiveKind.texture, output: bytes.length, levels, table: table.finish() };
|
|
3704
|
+
}
|
|
3705
|
+
|
|
3706
|
+
// src/interactives/progressive/mesh.ts
|
|
3707
|
+
var GLB_MAGIC2 = 1179937895, GLB_VERSION2 = 2, GLB_HEADER_BYTES2 = 12, GLB_CHUNK_HEADER_BYTES2 = 8, GLB_JSON2 = 1313821514, GLB_BIN2 = 5130562, GLB_ALIGN = 4, JSON_PAD = 32, COUNT_WIDTH = 10, SENTINEL_BASE = 91e8, TRIANGLES = 4, FLOAT = 5126, UNSIGNED_BYTE = 5121, UNSIGNED_SHORT = 5123, UNSIGNED_INT = 5125, MESHOPT = "EXT_meshopt_compression", KTX2_MIME = "image/ktx2", INSTANCING = "EXT_mesh_gpu_instancing", STEP = "STEP", LINEAR = "LINEAR", MIN_DECIMATE_KEYS = 16, DECIMATE_STEP = 4, COMPONENT_BYTES = { 5120: 1, 5121: 1, 5122: 2, 5123: 2, 5125: 4, 5126: 4 }, TYPE_COMPONENTS = { SCALAR: 1, VEC2: 2, VEC3: 3, VEC4: 4, MAT2: 4, MAT3: 9, MAT4: 16 };
|
|
3708
|
+
function elementBytes(a) {
|
|
3709
|
+
return (COMPONENT_BYTES[a.componentType] ?? 0) * (TYPE_COMPONENTS[a.type] ?? 0);
|
|
3710
|
+
}
|
|
3711
|
+
function readGlb(bytes) {
|
|
3712
|
+
if (bytes.length < (12) + (8)) return null;
|
|
3713
|
+
let v = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
3714
|
+
if (v.getUint32(0, true) !== (1179937895) || v.getUint32(4, true) !== (2) || v.getUint32(8, true) !== bytes.length) return null;
|
|
3715
|
+
let jsonLength = v.getUint32((12), true);
|
|
3716
|
+
if (v.getUint32((12) + 4, true) !== (1313821514)) return null;
|
|
3717
|
+
let jsonStart = (12) + (8), jsonEnd = jsonStart + jsonLength;
|
|
3718
|
+
if (jsonEnd + (8) > bytes.length) return null;
|
|
3719
|
+
let binLength = v.getUint32(jsonEnd, true);
|
|
3720
|
+
if (v.getUint32(jsonEnd + 4, true) !== (5130562) || jsonEnd + (8) + binLength !== bytes.length) return null;
|
|
3721
|
+
let jsonText = new TextDecoder().decode(bytes.subarray(jsonStart, jsonEnd));
|
|
3722
|
+
try {
|
|
3723
|
+
return { gltf: JSON.parse(jsonText), jsonText, bin: bytes.subarray(jsonEnd + (8)) };
|
|
3724
|
+
} catch {
|
|
3725
|
+
return null;
|
|
3726
|
+
}
|
|
3727
|
+
}
|
|
3728
|
+
function countUsers(gltf) {
|
|
3729
|
+
let accessors = Array.from({ length: gltf.accessors?.length ?? 0 }, () => 0), views = Array.from({ length: gltf.bufferViews?.length ?? 0 }, () => 0), use = (a) => {
|
|
3730
|
+
a !== void 0 && a >= 0 && a < accessors.length && accessors[a]++;
|
|
3731
|
+
};
|
|
3732
|
+
for (let mesh of gltf.meshes ?? [])
|
|
3733
|
+
for (let p of mesh.primitives) {
|
|
3734
|
+
use(p.indices);
|
|
3735
|
+
for (let key of Object.keys(p.attributes)) use(p.attributes[key]);
|
|
3736
|
+
for (let t2 of p.targets ?? []) for (let key of Object.keys(t2)) use(t2[key]);
|
|
3737
|
+
}
|
|
3738
|
+
for (let s9 of gltf.skins ?? []) use(s9.inverseBindMatrices);
|
|
3739
|
+
for (let a of gltf.animations ?? [])
|
|
3740
|
+
for (let s9 of a.samplers)
|
|
3741
|
+
use(s9.input), use(s9.output);
|
|
3742
|
+
for (let n of gltf.nodes ?? []) {
|
|
3743
|
+
let attributes = n.extensions?.[INSTANCING]?.attributes;
|
|
3744
|
+
if (attributes !== void 0) for (let key of Object.keys(attributes)) use(attributes[key]);
|
|
3745
|
+
}
|
|
3746
|
+
let view2 = (index) => {
|
|
3747
|
+
index !== void 0 && index >= 0 && index < views.length && views[index]++;
|
|
3748
|
+
};
|
|
3749
|
+
for (let a of gltf.accessors ?? []) {
|
|
3750
|
+
view2(a.bufferView);
|
|
3751
|
+
let sparse = a.sparse;
|
|
3752
|
+
view2(sparse?.indices?.bufferView), view2(sparse?.values?.bufferView);
|
|
3753
|
+
}
|
|
3754
|
+
for (let image of gltf.images ?? []) view2(image.bufferView);
|
|
3755
|
+
return { accessors, views };
|
|
3756
|
+
}
|
|
3757
|
+
function plainView(gltf, index) {
|
|
3758
|
+
if (index === void 0) return null;
|
|
3759
|
+
let view2 = gltf.bufferViews?.[index];
|
|
3760
|
+
return view2 === void 0 || view2.buffer !== 0 || view2.extensions?.[MESHOPT] !== void 0 ? null : view2;
|
|
3761
|
+
}
|
|
3762
|
+
function plainAccessor(gltf, index) {
|
|
3763
|
+
let a = gltf.accessors?.[index];
|
|
3764
|
+
return a === void 0 || a.sparse !== void 0 || a.bufferView === void 0 || elementBytes(a) === 0 ? null : a;
|
|
3765
|
+
}
|
|
3766
|
+
function readFloats(bin, start, stride, count2, width) {
|
|
3767
|
+
let out = new Float32Array(count2 * width), v = new DataView(bin.buffer, bin.byteOffset, bin.byteLength);
|
|
3768
|
+
for (let i = 0; i < count2; i++) for (let k = 0; k < width; k++) out[i * width + k] = v.getFloat32(start + i * stride + k * 4, true);
|
|
3769
|
+
return out;
|
|
3770
|
+
}
|
|
3771
|
+
function readIndices(bin, start, count2, componentType) {
|
|
3772
|
+
let out = new Uint32Array(count2), v = new DataView(bin.buffer, bin.byteOffset, bin.byteLength);
|
|
3773
|
+
for (let i = 0; i < count2; i++)
|
|
3774
|
+
out[i] = componentType === (5125) ? v.getUint32(start + i * 4, true) : componentType === (5123) ? v.getUint16(start + i * 2, true) : v.getUint8(start + i);
|
|
3775
|
+
return out;
|
|
3776
|
+
}
|
|
3777
|
+
function encodeIndices(indices, rank, componentType) {
|
|
3778
|
+
let size = COMPONENT_BYTES[componentType], out = new Uint8Array(indices.length * size), v = new DataView(out.buffer);
|
|
3779
|
+
for (let i = 0; i < indices.length; i++) {
|
|
3780
|
+
let value = rank[indices[i]];
|
|
3781
|
+
componentType === (5125) ? v.setUint32(i * 4, value, true) : componentType === (5123) ? v.setUint16(i * 2, value, true) : v.setUint8(i, value);
|
|
3782
|
+
}
|
|
3783
|
+
return out;
|
|
3784
|
+
}
|
|
3785
|
+
function primitiveRows(gltf, users, p, vertices) {
|
|
3786
|
+
let accessors = [...Object.values(p.attributes), ...(p.targets ?? []).flatMap((t2) => Object.values(t2))], byView = /* @__PURE__ */ new Map();
|
|
3787
|
+
for (let index of accessors) {
|
|
3788
|
+
let a = plainAccessor(gltf, index);
|
|
3789
|
+
if (a === null || a.count !== vertices || users.accessors[index] !== 1 || plainView(gltf, a.bufferView) === null) return null;
|
|
3790
|
+
let list2 = byView.get(a.bufferView) ?? [];
|
|
3791
|
+
list2.push(index), byView.set(a.bufferView, list2);
|
|
3792
|
+
}
|
|
3793
|
+
let rows = [];
|
|
3794
|
+
for (let [viewIndex, list2] of byView) {
|
|
3795
|
+
let view2 = gltf.bufferViews[viewIndex];
|
|
3796
|
+
if (users.views[viewIndex] !== list2.length) return null;
|
|
3797
|
+
if (list2.length === 1) {
|
|
3798
|
+
let a = gltf.accessors[list2[0]], stride2 = view2.byteStride ?? elementBytes(a);
|
|
3799
|
+
if ((a.byteOffset ?? 0) + vertices * stride2 > view2.byteLength) return null;
|
|
3800
|
+
rows.push({ start: (view2.byteOffset ?? 0) + (a.byteOffset ?? 0), stride: stride2 });
|
|
3801
|
+
continue;
|
|
3802
|
+
}
|
|
3803
|
+
let stride = view2.byteStride;
|
|
3804
|
+
if (stride === void 0 || vertices * stride > view2.byteLength) return null;
|
|
3805
|
+
for (let index of list2) {
|
|
3806
|
+
let a = gltf.accessors[index];
|
|
3807
|
+
if ((a.byteOffset ?? 0) + elementBytes(a) > stride) return null;
|
|
3808
|
+
}
|
|
3809
|
+
rows.push({ start: view2.byteOffset ?? 0, stride });
|
|
3810
|
+
}
|
|
3811
|
+
return rows;
|
|
3812
|
+
}
|
|
3813
|
+
function planPrimitive(gltf, users, bin, p, index) {
|
|
3814
|
+
if ((p.mode ?? (4)) !== (4) || p.indices === void 0 || p.extensions !== void 0) return null;
|
|
3815
|
+
let position = p.attributes.POSITION;
|
|
3816
|
+
if (position === void 0) return null;
|
|
3817
|
+
let pa = plainAccessor(gltf, position);
|
|
3818
|
+
if (pa === null || pa.componentType !== (5126) || pa.type !== "VEC3") return null;
|
|
3819
|
+
let vertices = pa.count, ia = plainAccessor(gltf, p.indices);
|
|
3820
|
+
if (ia === null || ia.type !== "SCALAR" || users.accessors[p.indices] !== 1 || ia.componentType !== (5121) && ia.componentType !== (5123) && ia.componentType !== (5125) || ia.count % 3 !== 0 || ia.count / 3 < (256)) return null;
|
|
3821
|
+
let iv = plainView(gltf, ia.bufferView);
|
|
3822
|
+
if (iv === null || iv.byteStride !== void 0 || users.views[ia.bufferView] !== 1) return null;
|
|
3823
|
+
let indexStart = (iv.byteOffset ?? 0) + (ia.byteOffset ?? 0), indexBytes = ia.count * elementBytes(ia);
|
|
3824
|
+
if ((ia.byteOffset ?? 0) + indexBytes > iv.byteLength) return null;
|
|
3825
|
+
let rows = primitiveRows(gltf, users, p, vertices);
|
|
3826
|
+
if (rows === null) return null;
|
|
3827
|
+
let pv = gltf.bufferViews[pa.bufferView], positions = readFloats(bin, (pv.byteOffset ?? 0) + (pa.byteOffset ?? 0), pv.byteStride ?? elementBytes(pa), vertices, 3), indices = readIndices(bin, indexStart, ia.count, ia.componentType);
|
|
3828
|
+
for (let i = 0; i < indices.length; i++) if (indices[i] >= vertices) return null;
|
|
3829
|
+
let signatureParts = [], signatureWidth = 0;
|
|
3830
|
+
for (let [name, width] of [
|
|
3831
|
+
["TEXCOORD_0", 2],
|
|
3832
|
+
["NORMAL", 3]
|
|
3833
|
+
]) {
|
|
3834
|
+
let at2 = p.attributes[name], a = at2 === void 0 ? null : plainAccessor(gltf, at2);
|
|
3835
|
+
if (a === null || a.componentType !== (5126)) continue;
|
|
3836
|
+
let view2 = gltf.bufferViews[a.bufferView];
|
|
3837
|
+
signatureParts.push(readFloats(bin, (view2.byteOffset ?? 0) + (a.byteOffset ?? 0), view2.byteStride ?? elementBytes(a), vertices, width)), signatureWidth += width;
|
|
3838
|
+
}
|
|
3839
|
+
let signatures = null;
|
|
3840
|
+
if (signatureWidth > 0) {
|
|
3841
|
+
signatures = new Float32Array(vertices * signatureWidth);
|
|
3842
|
+
let offset = 0;
|
|
3843
|
+
for (let part of signatureParts) {
|
|
3844
|
+
let width = part.length / vertices;
|
|
3845
|
+
for (let w = 0; w < vertices; w++) for (let k = 0; k < width; k++) signatures[w * signatureWidth + offset + k] = part[w * width + k];
|
|
3846
|
+
offset += width;
|
|
3847
|
+
}
|
|
3848
|
+
}
|
|
3849
|
+
let coarse = simplifyLods({ positions, indices, vertices, signatures, signatureWidth }, lodTargets(ia.count / 3));
|
|
3850
|
+
if (coarse.length === 0) return null;
|
|
3851
|
+
let lods = [...coarse.reverse(), indices], group = new Uint32Array(vertices).fill(lods.length - 1);
|
|
3852
|
+
for (let k = lods.length - 1; k >= 0; k--) for (let w of lods[k]) group[w] = k;
|
|
3853
|
+
let order = Uint32Array.from({ length: vertices }, (_, i) => i).sort((a, b) => group[a] - group[b] || a - b), rank = new Uint32Array(vertices);
|
|
3854
|
+
for (let i = 0; i < vertices; i++) rank[order[i]] = i;
|
|
3855
|
+
let prefix = [], at = 0;
|
|
3856
|
+
for (let k = 0; k < lods.length; k++) {
|
|
3857
|
+
for (; at < vertices && group[order[at]] <= k; ) at++;
|
|
3858
|
+
prefix.push(at);
|
|
3859
|
+
}
|
|
3860
|
+
return prefix[lods.length - 1] = vertices, { index, rows, indexStart, indexBytes, componentType: ia.componentType, lods, prefix, order, rank };
|
|
3861
|
+
}
|
|
3862
|
+
function planClips(gltf, users) {
|
|
3863
|
+
let byInput = /* @__PURE__ */ new Map(), blocked = /* @__PURE__ */ new Set();
|
|
3864
|
+
for (let a of gltf.animations ?? [])
|
|
3865
|
+
for (let s9 of a.samplers) {
|
|
3866
|
+
let interpolation = s9.interpolation ?? LINEAR;
|
|
3867
|
+
interpolation !== LINEAR && interpolation !== STEP && blocked.add(s9.input);
|
|
3868
|
+
let list2 = byInput.get(s9.input) ?? [];
|
|
3869
|
+
list2.push(s9), byInput.set(s9.input, list2);
|
|
3870
|
+
}
|
|
3871
|
+
let out = [], claimed = /* @__PURE__ */ new Set();
|
|
3872
|
+
for (let [input, samplers] of byInput) {
|
|
3873
|
+
if (blocked.has(input)) continue;
|
|
3874
|
+
let ia = plainAccessor(gltf, input);
|
|
3875
|
+
if (ia === null || ia.componentType !== (5126) || ia.type !== "SCALAR" || ia.count < (16) || users.accessors[input] !== samplers.length) continue;
|
|
3876
|
+
let accessors = [input], ok = true;
|
|
3877
|
+
for (let s9 of samplers) {
|
|
3878
|
+
(s9.output === input || accessors.includes(s9.output) || users.accessors[s9.output] !== 1) && (ok = false);
|
|
3879
|
+
let oa = plainAccessor(gltf, s9.output);
|
|
3880
|
+
(oa === null || oa.count % ia.count !== 0) && (ok = false), accessors.push(s9.output);
|
|
3881
|
+
}
|
|
3882
|
+
if (!ok || accessors.some((a) => claimed.has(a))) continue;
|
|
3883
|
+
let plans = [];
|
|
3884
|
+
for (let index of accessors) {
|
|
3885
|
+
let a = gltf.accessors[index], view2 = plainView(gltf, a.bufferView);
|
|
3886
|
+
if (view2 === null || view2.byteStride !== void 0) {
|
|
3887
|
+
ok = false;
|
|
3888
|
+
break;
|
|
3889
|
+
}
|
|
3890
|
+
let rowBytes = a.count / ia.count * elementBytes(a);
|
|
3891
|
+
if ((a.byteOffset ?? 0) + ia.count * rowBytes > view2.byteLength) {
|
|
3892
|
+
ok = false;
|
|
3893
|
+
break;
|
|
3894
|
+
}
|
|
3895
|
+
plans.push({ accessor: index, start: (view2.byteOffset ?? 0) + (a.byteOffset ?? 0), rowBytes });
|
|
3896
|
+
}
|
|
3897
|
+
if (ok) {
|
|
3898
|
+
for (let a of accessors) claimed.add(a);
|
|
3899
|
+
out.push({ keys: ia.count, accessors: plans });
|
|
3900
|
+
}
|
|
3901
|
+
}
|
|
3902
|
+
return out;
|
|
3903
|
+
}
|
|
3904
|
+
function planImages(gltf, users, bin) {
|
|
3905
|
+
let out = [];
|
|
3906
|
+
for (let image of gltf.images ?? []) {
|
|
3907
|
+
if (image.mimeType !== KTX2_MIME || image.bufferView === void 0 || users.views[image.bufferView] !== 1) continue;
|
|
3908
|
+
let view2 = plainView(gltf, image.bufferView);
|
|
3909
|
+
if (view2 === null) continue;
|
|
3910
|
+
let start = view2.byteOffset ?? 0, k = readKtx2(bin, start, start + view2.byteLength);
|
|
3911
|
+
k === null || baseLevel(k) === 0 || out.push({ start, end: start + view2.byteLength });
|
|
3912
|
+
}
|
|
3913
|
+
return out;
|
|
3914
|
+
}
|
|
3915
|
+
function overlapping(ranges) {
|
|
3916
|
+
let sorted = [...ranges].sort((a, b) => a.start - b.start || a.end - b.end), bad = /* @__PURE__ */ new Set();
|
|
3917
|
+
for (let i = 1; i < sorted.length; i++)
|
|
3918
|
+
sorted[i].start < sorted[i - 1].end && (bad.add(sorted[i].owner), bad.add(sorted[i - 1].owner));
|
|
3919
|
+
return bad;
|
|
3920
|
+
}
|
|
3921
|
+
function digits(value) {
|
|
3922
|
+
return new TextEncoder().encode(String(value).padStart((10), " "));
|
|
3923
|
+
}
|
|
3924
|
+
function sentinelOffsets(json, sentinels) {
|
|
3925
|
+
let text = new TextDecoder("latin1").decode(json), out = [];
|
|
3926
|
+
for (let s9 of sentinels) {
|
|
3927
|
+
let needle = String(s9), at = text.indexOf(needle);
|
|
3928
|
+
if (at < 0 || text.indexOf(needle, at + 1) >= 0) return null;
|
|
3929
|
+
out.push(at);
|
|
3930
|
+
}
|
|
3931
|
+
return out;
|
|
3932
|
+
}
|
|
3933
|
+
function firstLevelBytes(plan) {
|
|
3934
|
+
let n = 0;
|
|
3935
|
+
for (let unit of plan.levels[0] ?? []) for (let segment of unit.segments) n += segment.bytes.length;
|
|
3936
|
+
return n;
|
|
3937
|
+
}
|
|
3938
|
+
function planMesh(bytes) {
|
|
3939
|
+
let boot = planBootTier(bytes), layered = planMeshLevels(bytes);
|
|
3940
|
+
return boot === null ? layered : layered === null ? boot : firstLevelBytes(layered.plan) < firstLevelBytes(boot.plan) ? layered : boot;
|
|
3941
|
+
}
|
|
3942
|
+
function planMeshLevels(bytes) {
|
|
3943
|
+
let glb = readGlb(bytes);
|
|
3944
|
+
if (glb === null) return null;
|
|
3945
|
+
let { gltf } = glb;
|
|
3946
|
+
for (let b = 1; b < (gltf.buffers ?? []).length; b++) {
|
|
3947
|
+
let buffer = (gltf.buffers ?? [])[b];
|
|
3948
|
+
if (buffer.uri !== void 0 || buffer.extensions?.[MESHOPT] === void 0) return null;
|
|
3949
|
+
}
|
|
3950
|
+
if (gltf.buffers?.[0]?.uri !== void 0) return null;
|
|
3951
|
+
let users = countUsers(gltf), bin = Uint8Array.from(glb.bin), primitives = [], primitiveIndex = 0;
|
|
3952
|
+
for (let mesh of gltf.meshes ?? [])
|
|
3953
|
+
for (let p of mesh.primitives) {
|
|
3954
|
+
let planned = planPrimitive(gltf, users, bin, p, primitiveIndex);
|
|
3955
|
+
planned !== null && primitives.push(planned), primitiveIndex++;
|
|
3956
|
+
}
|
|
3957
|
+
let images = planImages(gltf, users, bin), clips = planClips(gltf, users), ranges = [];
|
|
3958
|
+
for (let p of primitives) {
|
|
3959
|
+
for (let r of p.rows) ranges.push({ start: r.start, end: r.start + p.order.length * r.stride, owner: `p${p.index}` });
|
|
3960
|
+
ranges.push({ start: p.indexStart, end: p.indexStart + p.indexBytes, owner: `p${p.index}` });
|
|
3961
|
+
}
|
|
3962
|
+
images.forEach((im, i) => ranges.push({ start: im.start, end: im.end, owner: `i${i}` })), clips.forEach((c, i) => {
|
|
3963
|
+
for (let a of c.accessors) ranges.push({ start: a.start, end: a.start + c.keys * a.rowBytes, owner: `c${i}` });
|
|
3964
|
+
});
|
|
3965
|
+
let bad = overlapping(ranges), keptPrimitives = primitives.filter((p) => !bad.has(`p${p.index}`));
|
|
3966
|
+
if (images = images.filter((_, i) => !bad.has(`i${i}`)), clips = clips.filter((_, i) => !bad.has(`c${i}`)), keptPrimitives.length === 0 && images.length === 0 && clips.length === 0) return null;
|
|
3967
|
+
for (let p of keptPrimitives) {
|
|
3968
|
+
for (let r of p.rows) {
|
|
3969
|
+
let length = p.order.length * r.stride, old = bin.slice(r.start, r.start + length);
|
|
3970
|
+
for (let i = 0; i < p.order.length; i++) bin.set(old.subarray(p.order[i] * r.stride, (p.order[i] + 1) * r.stride), r.start + i * r.stride);
|
|
3971
|
+
}
|
|
3972
|
+
bin.set(encodeIndices(p.lods[p.lods.length - 1], p.rank, p.componentType), p.indexStart);
|
|
3973
|
+
}
|
|
3974
|
+
let edited = structuredClone(gltf), sentinels = [], counted = [], sentinel = (accessor) => {
|
|
3975
|
+
let a = edited.accessors[accessor], value = (91e8) + counted.length;
|
|
3976
|
+
counted.push({ accessor, full: a.count }), sentinels.push(value), a.count = value;
|
|
3977
|
+
};
|
|
3978
|
+
for (let p of keptPrimitives) {
|
|
3979
|
+
let prim = (edited.meshes ?? []).flatMap((m) => m.primitives)[p.index], a = edited.accessors[prim.indices];
|
|
3980
|
+
delete a.min, delete a.max, sentinel(prim.indices);
|
|
3981
|
+
}
|
|
3982
|
+
for (let c of clips) for (let a of c.accessors) sentinel(a.accessor);
|
|
3983
|
+
let encoded = new TextEncoder().encode(JSON.stringify(edited)), jsonLength = Math.ceil(encoded.length / (4)) * (4), json = new Uint8Array(jsonLength).fill((32));
|
|
3984
|
+
json.set(encoded);
|
|
3985
|
+
let found = sentinelOffsets(json, sentinels);
|
|
3986
|
+
if (found === null) return null;
|
|
3987
|
+
let jsonAt = (12) + (8), countAt = /* @__PURE__ */ new Map();
|
|
3988
|
+
counted.forEach((c, i) => {
|
|
3989
|
+
json.set(digits(c.full), found[i]), countAt.set(c.accessor, jsonAt + found[i]);
|
|
3990
|
+
});
|
|
3991
|
+
let binAt = jsonAt + jsonLength + (8), source = new Uint8Array(binAt + bin.length), sv = new DataView(source.buffer);
|
|
3992
|
+
return sv.setUint32(0, (1179937895), true), sv.setUint32(4, (2), true), sv.setUint32(8, source.length, true), sv.setUint32((12), jsonLength, true), sv.setUint32((12) + 4, (1313821514), true), source.set(json, jsonAt), sv.setUint32(jsonAt + jsonLength, bin.length, true), sv.setUint32(jsonAt + jsonLength + 4, (5130562), true), source.set(bin, binAt), { plan: schedule(source, binAt, keptPrimitives, images, clips, countAt, gltf), source };
|
|
3993
|
+
}
|
|
3994
|
+
function schedule(source, binAt, primitives, images, clips, countAt, gltf) {
|
|
3995
|
+
let table = new TableWriter(), slice = (start, end) => ({ dest: start, bytes: source.subarray(start, end) }), countPatch = (accessor, value) => writePatch(table, countAt.get(accessor), digits(value)), dynamic = [], base = [], basePatches = [], refinements = [], components = [], primitiveList = (gltf.meshes ?? []).flatMap((m) => m.primitives), order = 0;
|
|
3996
|
+
for (let p of primitives) {
|
|
3997
|
+
let indexAccessor = primitiveList[p.index].indices, indexStart = binAt + p.indexStart, rows = p.rows.map((r) => ({ start: binAt + r.start, stride: r.stride })), weight = p.indexBytes;
|
|
3998
|
+
for (let r of rows)
|
|
3999
|
+
dynamic.push({ start: r.start, end: r.start + p.order.length * r.stride, owner: "" }), weight += p.order.length * r.stride;
|
|
4000
|
+
dynamic.push({ start: indexStart, end: indexStart + p.indexBytes, owner: "" });
|
|
4001
|
+
let full = p.lods[p.lods.length - 1].length, component = { weight, quality: p.lods[0].length / full };
|
|
4002
|
+
components.push(component);
|
|
4003
|
+
for (let r of rows) base.push(slice(r.start, r.start + p.prefix[0] * r.stride));
|
|
4004
|
+
base.push({ dest: indexStart, bytes: encodeIndices(p.lods[0], p.rank, p.componentType) }), basePatches.push(countPatch(indexAccessor, p.lods[0].length));
|
|
4005
|
+
for (let k = 1; k < p.lods.length; k++) {
|
|
4006
|
+
let segments = rows.map((r) => slice(r.start + p.prefix[k - 1] * r.stride, r.start + p.prefix[k] * r.stride)), indices = k === p.lods.length - 1 ? source.subarray(indexStart, indexStart + p.indexBytes) : encodeIndices(p.lods[k], p.rank, p.componentType);
|
|
4007
|
+
segments.push({ dest: 0, bytes: indices, staged: true });
|
|
4008
|
+
let patches = [{ op: PatchOp.staged, a: indexStart, b: 0, c: indices.length }, countPatch(indexAccessor, p.lods[k].length)];
|
|
4009
|
+
refinements.push({ step: k, order: order++, unit: { segments, patches }, component, quality: p.lods[k].length / full });
|
|
4010
|
+
}
|
|
4011
|
+
}
|
|
4012
|
+
for (let image of images) {
|
|
4013
|
+
let start = binAt + image.start, k = readKtx2(source, start, binAt + image.end);
|
|
4014
|
+
dynamic.push({ start, end: binAt + image.end, owner: "" });
|
|
4015
|
+
let b = baseLevel(k), full = texels(k, 0), component = { weight: image.end - image.start, quality: texels(k, b) / full };
|
|
4016
|
+
components.push(component);
|
|
4017
|
+
let states = new KtxStates(source, k, table);
|
|
4018
|
+
base.push(slice(start, levelEnd(k, b))), basePatches.push(...states.state(b));
|
|
4019
|
+
for (let level = b - 1; level >= 0; level--) {
|
|
4020
|
+
let unit = { segments: [slice(levelStart(k, level), levelEnd(k, level))], patches: states.state(level) };
|
|
4021
|
+
refinements.push({ step: b - level, order: order++, unit, component, quality: texels(k, level) / full });
|
|
4022
|
+
}
|
|
4023
|
+
}
|
|
4024
|
+
for (let clip of clips) {
|
|
4025
|
+
let coarse = coarseKeys(clip.keys, (4)), weight = 0, staged = [], patches = [], stagingAt = 0;
|
|
4026
|
+
for (let a of clip.accessors) {
|
|
4027
|
+
let start = binAt + a.start, length = clip.keys * a.rowBytes;
|
|
4028
|
+
weight += length, dynamic.push({ start, end: start + length, owner: "" });
|
|
4029
|
+
let front = new Uint8Array(coarse * a.rowBytes), rest = new Uint8Array((clip.keys - coarse) * a.rowBytes), f = 0, r = 0;
|
|
4030
|
+
for (let i = 0; i < clip.keys; i++) {
|
|
4031
|
+
let row = source.subarray(start + i * a.rowBytes, start + (i + 1) * a.rowBytes);
|
|
4032
|
+
isCoarseKey(i, clip.keys, (4)) ? front.set(row, f++ * a.rowBytes) : rest.set(row, r++ * a.rowBytes);
|
|
4033
|
+
}
|
|
4034
|
+
base.push({ dest: start, bytes: front });
|
|
4035
|
+
let ratio = a.rowBytes / elementBytes(gltf.accessors[a.accessor]);
|
|
4036
|
+
basePatches.push(countPatch(a.accessor, coarse * ratio)), staged.push({ dest: stagingAt, bytes: rest, staged: true }), patches.push({ op: PatchOp.merge, a: start, b: stagingAt, c: table.words(clip.keys, a.rowBytes, (4)) }), patches.push(countPatch(a.accessor, clip.keys * ratio)), stagingAt += rest.length;
|
|
4037
|
+
}
|
|
4038
|
+
let component = { weight, quality: coarse / clip.keys };
|
|
4039
|
+
components.push(component), refinements.push({ step: 1, order: order++, unit: { segments: staged, patches }, component, quality: 1 });
|
|
4040
|
+
}
|
|
4041
|
+
dynamic.sort((a, b) => a.start - b.start);
|
|
4042
|
+
let statics = [slice(0, binAt)], cursor = binAt;
|
|
4043
|
+
for (let r of dynamic)
|
|
4044
|
+
r.start > cursor && statics.push(slice(cursor, r.start)), cursor = Math.max(cursor, r.end);
|
|
4045
|
+
cursor < source.length && statics.push(slice(cursor, source.length));
|
|
4046
|
+
let staticWeight = 0;
|
|
4047
|
+
for (let s9 of statics) staticWeight += s9.bytes.length;
|
|
4048
|
+
let total = staticWeight;
|
|
4049
|
+
for (let c of components) total += c.weight;
|
|
4050
|
+
let quality = () => {
|
|
4051
|
+
let value = staticWeight;
|
|
4052
|
+
for (let c of components) value += c.weight * c.quality;
|
|
4053
|
+
return Math.min(PPM, Math.floor(value * PPM / total));
|
|
4054
|
+
}, levels = [[{ segments: [...statics, ...base], patches: basePatches, quality: quality() }]];
|
|
4055
|
+
refinements.sort((a, b) => a.step - b.step || unitBytes(a.unit) - unitBytes(b.unit) || a.order - b.order);
|
|
4056
|
+
let step = 0;
|
|
4057
|
+
for (let i = 0; i < refinements.length; i++) {
|
|
4058
|
+
let r = refinements[i];
|
|
4059
|
+
r.component.quality = r.quality;
|
|
4060
|
+
let last = i === refinements.length - 1, unit = { ...r.unit, quality: last ? PPM : quality() };
|
|
4061
|
+
r.step !== step && (levels.push([]), step = r.step), levels[levels.length - 1].push(unit);
|
|
4062
|
+
}
|
|
4063
|
+
return { kind: ProgressiveKind.mesh, output: source.length, levels, table: table.finish() };
|
|
4064
|
+
}
|
|
4065
|
+
function unitBytes(unit) {
|
|
4066
|
+
let n = 0;
|
|
4067
|
+
for (let s9 of unit.segments) n += s9.bytes.length;
|
|
4068
|
+
return n;
|
|
4069
|
+
}
|
|
4070
|
+
var BOOT_HINT = "cimplify_boot", BOOT_HINT_VERSION = 1;
|
|
4071
|
+
function accessorRefs(value, out) {
|
|
4072
|
+
if (typeof value == "number" && Number.isInteger(value)) out.add(value);
|
|
4073
|
+
else if (Array.isArray(value)) for (let v of value) accessorRefs(v, out);
|
|
4074
|
+
else if (value !== null && typeof value == "object") for (let v of Object.values(value)) accessorRefs(v, out);
|
|
4075
|
+
}
|
|
4076
|
+
function usedAccessors(gltf) {
|
|
4077
|
+
let used = /* @__PURE__ */ new Set();
|
|
4078
|
+
for (let mesh of gltf.meshes ?? [])
|
|
4079
|
+
for (let p of mesh.primitives) {
|
|
4080
|
+
p.indices !== void 0 && used.add(p.indices);
|
|
4081
|
+
for (let a of Object.values(p.attributes)) used.add(a);
|
|
4082
|
+
for (let t2 of p.targets ?? []) for (let a of Object.values(t2)) used.add(a);
|
|
4083
|
+
accessorRefs(p.extensions, used);
|
|
4084
|
+
}
|
|
4085
|
+
for (let s9 of gltf.skins ?? []) s9.inverseBindMatrices !== void 0 && used.add(s9.inverseBindMatrices);
|
|
4086
|
+
for (let a of gltf.animations ?? [])
|
|
4087
|
+
for (let s9 of a.samplers)
|
|
4088
|
+
used.add(s9.input), used.add(s9.output);
|
|
4089
|
+
for (let n of gltf.nodes ?? []) accessorRefs(n.extensions?.[INSTANCING]?.attributes, used);
|
|
4090
|
+
return used;
|
|
4091
|
+
}
|
|
4092
|
+
function usedViews(gltf, accessors) {
|
|
4093
|
+
let views = /* @__PURE__ */ new Set();
|
|
4094
|
+
for (let index of accessors) {
|
|
4095
|
+
let a = gltf.accessors?.[index];
|
|
4096
|
+
a?.bufferView !== void 0 && views.add(a.bufferView);
|
|
4097
|
+
let sparse = a?.sparse;
|
|
4098
|
+
sparse?.indices?.bufferView !== void 0 && views.add(sparse.indices.bufferView), sparse?.values?.bufferView !== void 0 && views.add(sparse.values.bufferView);
|
|
4099
|
+
}
|
|
4100
|
+
for (let image of gltf.images ?? []) image.bufferView !== void 0 && views.add(image.bufferView);
|
|
4101
|
+
return views;
|
|
4102
|
+
}
|
|
4103
|
+
function viewRange(view2) {
|
|
4104
|
+
let compressed = view2.extensions?.[MESHOPT];
|
|
4105
|
+
return compressed !== void 0 ? compressed.buffer === 0 ? [compressed.byteOffset ?? 0, (compressed.byteOffset ?? 0) + compressed.byteLength] : null : view2.buffer === 0 ? [view2.byteOffset ?? 0, (view2.byteOffset ?? 0) + view2.byteLength] : null;
|
|
4106
|
+
}
|
|
4107
|
+
function paddedJson(json, length) {
|
|
4108
|
+
let out = new Uint8Array(length).fill((32));
|
|
4109
|
+
return out.set(json), out;
|
|
4110
|
+
}
|
|
4111
|
+
function planBootTier(bytes) {
|
|
4112
|
+
let glb = readGlb(bytes);
|
|
4113
|
+
if (glb === null) return null;
|
|
4114
|
+
let root = glb.gltf, hint = root.extras?.[BOOT_HINT];
|
|
4115
|
+
if (hint === void 0 || hint.version !== (1)) return null;
|
|
4116
|
+
let whole = structuredClone(root);
|
|
4117
|
+
delete whole.extras[BOOT_HINT], Object.keys(whole.extras ?? {}).length === 0 && delete whole.extras;
|
|
4118
|
+
let base = structuredClone(whole);
|
|
4119
|
+
for (let p of hint.primitives ?? []) {
|
|
4120
|
+
let primitive = base.meshes?.[p.mesh]?.primitives[p.primitive];
|
|
4121
|
+
if (primitive === void 0) return null;
|
|
4122
|
+
primitive.attributes = { ...p.attributes }, primitive.indices = p.indices, delete primitive.extensions;
|
|
4123
|
+
}
|
|
4124
|
+
for (let s9 of hint.samplers ?? []) {
|
|
4125
|
+
let sampler = base.animations?.[s9.animation]?.samplers[s9.sampler];
|
|
4126
|
+
if (sampler === void 0) return null;
|
|
4127
|
+
sampler.input = s9.input, sampler.output = s9.output;
|
|
4128
|
+
}
|
|
4129
|
+
(base.animations ?? []).forEach((animation, index) => {
|
|
4130
|
+
index !== (hint.clip ?? 0) && (animation.samplers = [], animation.channels = []);
|
|
4131
|
+
});
|
|
4132
|
+
let live = usedAccessors(base), baseViews = usedViews(base, live);
|
|
4133
|
+
base.accessors = (base.accessors ?? []).map(
|
|
4134
|
+
(accessor, index) => live.has(index) || accessor.bufferView === void 0 || baseViews.has(accessor.bufferView) ? accessor : { bufferView: accessor.bufferView, componentType: (5121), count: 1, type: "SCALAR" }
|
|
4135
|
+
);
|
|
4136
|
+
let late = [];
|
|
4137
|
+
(base.bufferViews ?? []).forEach((view2, index) => {
|
|
4138
|
+
if (baseViews.has(index)) return;
|
|
4139
|
+
let range = viewRange(view2);
|
|
4140
|
+
range !== null && late.push(range), view2.extensions?.[MESHOPT] !== void 0 && (delete view2.extensions[MESHOPT], Object.keys(view2.extensions).length === 0 && delete view2.extensions);
|
|
4141
|
+
});
|
|
4142
|
+
let kept = (whole.bufferViews ?? []).map((view2, index) => baseViews.has(index) ? viewRange(view2) : null).filter((r) => r !== null), reserved = late.filter(([start, end]) => !kept.some(([a, b]) => a < end && start < b));
|
|
4143
|
+
if (reserved.length === 0) return null;
|
|
4144
|
+
let encoder2 = new TextEncoder(), baseJson = encoder2.encode(JSON.stringify(base)), wholeJson = encoder2.encode(JSON.stringify(whole)), length = Math.ceil(Math.max(baseJson.length, wholeJson.length) / (4)) * (4), jsonAt = (12) + (8), binAt = jsonAt + length + (8), source = new Uint8Array(binAt + glb.bin.length), sv = new DataView(source.buffer);
|
|
4145
|
+
sv.setUint32(0, (1179937895), true), sv.setUint32(4, (2), true), sv.setUint32(8, source.length, true), sv.setUint32((12), length, true), sv.setUint32((12) + 4, (1313821514), true), source.set(paddedJson(wholeJson, length), jsonAt), sv.setUint32(binAt - (8), glb.bin.length, true), sv.setUint32(binAt - (8) + 4, (5130562), true), source.set(glb.bin, binAt), reserved.sort((a, b) => a[0] - b[0]);
|
|
4146
|
+
let slice = (start, end) => ({ dest: start, bytes: source.subarray(start, end) }), head = [slice(0, jsonAt), { dest: jsonAt, bytes: baseJson }, slice(binAt - (8), binAt)], pad = { op: PatchOp.fill, a: jsonAt + baseJson.length, b: (32), c: length - baseJson.length }, refinement = [slice(jsonAt, jsonAt + length)], cursor = 0, deferred = 0;
|
|
4147
|
+
for (let [start, end] of reserved) {
|
|
4148
|
+
start > cursor && head.push(slice(binAt + cursor, binAt + start));
|
|
4149
|
+
let from = Math.max(start, cursor);
|
|
4150
|
+
end > from && (refinement.push(slice(binAt + from, binAt + end)), deferred += end - from), cursor = Math.max(cursor, end);
|
|
4151
|
+
}
|
|
4152
|
+
cursor < glb.bin.length && head.push(slice(binAt + cursor, binAt + glb.bin.length));
|
|
4153
|
+
let quality = Math.floor((source.length - deferred) * PPM / source.length), table = new TableWriter();
|
|
4154
|
+
return {
|
|
4155
|
+
plan: {
|
|
4156
|
+
kind: ProgressiveKind.mesh,
|
|
4157
|
+
output: source.length,
|
|
4158
|
+
levels: [[{ segments: head, patches: pad.c > 0 ? [pad] : [], quality }], [{ segments: refinement, patches: [], quality: PPM }]],
|
|
4159
|
+
table: table.finish()
|
|
4160
|
+
},
|
|
4161
|
+
source
|
|
4162
|
+
};
|
|
4163
|
+
}
|
|
4164
|
+
|
|
4165
|
+
// src/interactives/progressive/mips.ts
|
|
4166
|
+
var VK_R8G8B8A8_UNORM = 37, VK_R8G8B8A8_SRGB = 43, VK_R16G16B16A16_SFLOAT = 97, SCHEME_NONE = 0, SCHEME_ZSTD = 2, HEADER_VK_FORMAT = 12, HEADER_TYPE_SIZE = 16, HEADER_WIDTH = 20, HEADER_HEIGHT = 24, HEADER_DEPTH = 28, HEADER_LAYERS = 32, HEADER_FACES = 36, HEADER_LEVELS = 40, HEADER_SCHEME = 44, HEADER_DFD_OFFSET = 48, HEADER_DFD_LENGTH = 52, HEADER_KVD_OFFSET = 56, HEADER_KVD_LENGTH = 60, HEADER_SGD_OFFSET = 64, HEADER_SGD_LENGTH = 72, LEVEL_INDEX = 80, LEVEL_ENTRY = 24, LEVEL_LENGTH = 8, LEVEL_UNCOMPRESSED = 16, CHANNELS = 4, HALF_BYTES = 2, ALIGN = 4, SRGB_CUTOFF = 0.04045, SRGB_LINEAR_CUTOFF = 31308e-7, SRGB_SCALE = 12.92, SRGB_A = 0.055, SRGB_GAMMA = 2.4, BYTE_MAX = 255, HALF_EXPONENT_BIAS = 15, FLOAT_EXPONENT_BIAS = 127, HALF_MANTISSA_BITS = 10, FLOAT_MANTISSA_BITS = 23, HALF_EXPONENT_MAX = 31, SAMPLES_PER_TEXEL = 4;
|
|
4167
|
+
function formatOf(vk) {
|
|
4168
|
+
return vk === (37) ? "unorm" : vk === (43) ? "srgb" : vk === (97) ? "half" : null;
|
|
4169
|
+
}
|
|
4170
|
+
var scratch = new DataView(new ArrayBuffer(4));
|
|
4171
|
+
function halfToFloat(bits) {
|
|
4172
|
+
let sign = bits & 32768 ? -1 : 1, exponent = bits >> (10) & (31), mantissa = bits & 1023;
|
|
4173
|
+
return exponent === 0 ? sign * mantissa * 2 ** (1 - (15) - (10)) : exponent === (31) ? mantissa === 0 ? sign * (1 / 0) : Number.NaN : sign * (1 + mantissa / (1 << (10))) * 2 ** (exponent - (15));
|
|
4174
|
+
}
|
|
4175
|
+
function floatToHalf(value) {
|
|
4176
|
+
scratch.setFloat32(0, value);
|
|
4177
|
+
let bits = scratch.getUint32(0), sign = bits >>> 16 & 32768, exponent = (bits >>> (23) & 255) - (127) + (15), mantissa = bits & 8388607;
|
|
4178
|
+
return exponent <= 0 ? sign : exponent >= (31) ? sign | 31744 : sign | exponent << (10) | mantissa >>> (23) - (10);
|
|
4179
|
+
}
|
|
4180
|
+
function toLinear(byte) {
|
|
4181
|
+
let c = byte / (255);
|
|
4182
|
+
return c <= (0.04045) ? c / (12.92) : ((c + (0.055)) / (1 + (0.055))) ** (2.4);
|
|
4183
|
+
}
|
|
4184
|
+
function toSrgb(linear) {
|
|
4185
|
+
let c = linear <= (31308e-7) ? linear * (12.92) : (1 + (0.055)) * linear ** (1 / (2.4)) - (0.055);
|
|
4186
|
+
return Math.round(Math.min(1, Math.max(0, c)) * (255));
|
|
4187
|
+
}
|
|
4188
|
+
function read(level, format) {
|
|
4189
|
+
let texels2 = format === "half" ? level.length / (2) : level.length, out = new Float32Array(texels2);
|
|
4190
|
+
if (format === "half") {
|
|
4191
|
+
let view2 = new DataView(level.buffer, level.byteOffset, level.byteLength);
|
|
4192
|
+
for (let i = 0; i < texels2; i++) out[i] = halfToFloat(view2.getUint16(i * (2), true));
|
|
4193
|
+
} else
|
|
4194
|
+
for (let i = 0; i < texels2; i++) out[i] = format === "srgb" && i % (4) !== (4) - 1 ? toLinear(level[i]) : level[i] / (255);
|
|
4195
|
+
return out;
|
|
4196
|
+
}
|
|
4197
|
+
function write(values, format) {
|
|
4198
|
+
if (format === "half") {
|
|
4199
|
+
let out2 = new Uint8Array(values.length * (2)), view2 = new DataView(out2.buffer);
|
|
4200
|
+
for (let i = 0; i < values.length; i++) view2.setUint16(i * (2), floatToHalf(values[i]), true);
|
|
4201
|
+
return out2;
|
|
4202
|
+
}
|
|
4203
|
+
let out = new Uint8Array(values.length);
|
|
4204
|
+
for (let i = 0; i < values.length; i++)
|
|
4205
|
+
out[i] = format === "srgb" && i % (4) !== (4) - 1 ? toSrgb(values[i]) : Math.round(Math.min(1, Math.max(0, values[i])) * (255));
|
|
4206
|
+
return out;
|
|
4207
|
+
}
|
|
4208
|
+
function halve(source, width, height) {
|
|
4209
|
+
let w = Math.max(1, width >>> 1), h = Math.max(1, height >>> 1), out = new Float32Array(w * h * (4));
|
|
4210
|
+
for (let y = 0; y < h; y++)
|
|
4211
|
+
for (let x = 0; x < w; x++)
|
|
4212
|
+
for (let c = 0; c < (4); c++) {
|
|
4213
|
+
let sum = 0;
|
|
4214
|
+
for (let dy = 0; dy < 2; dy++)
|
|
4215
|
+
for (let dx = 0; dx < 2; dx++) {
|
|
4216
|
+
let sx = Math.min(width - 1, x * 2 + dx), sy = Math.min(height - 1, y * 2 + dy);
|
|
4217
|
+
sum += source[(sy * width + sx) * (4) + c];
|
|
4218
|
+
}
|
|
4219
|
+
out[(y * w + x) * (4) + c] = sum / (4);
|
|
4220
|
+
}
|
|
4221
|
+
return { values: out, width: w, height: h };
|
|
4222
|
+
}
|
|
4223
|
+
function align(value) {
|
|
4224
|
+
return Math.ceil(value / (4)) * (4);
|
|
4225
|
+
}
|
|
4226
|
+
function withMipChain(bytes, inflate, compress) {
|
|
4227
|
+
if (!isKtx2At(bytes, 0, bytes.length)) return null;
|
|
4228
|
+
let v = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength), format = formatOf(v.getUint32((12), true)), scheme = v.getUint32((44), true), width = v.getUint32((20), true), height = v.getUint32((24), true);
|
|
4229
|
+
if (format === null || Math.max(1, v.getUint32((40), true)) !== 1 || v.getUint32((28), true) !== 0 || v.getUint32((32), true) > 1 || v.getUint32((36), true) !== 1 || width < 2 || height < 2 || scheme !== (0) && (scheme !== (2) || inflate === null || compress === null) || Number(v.getBigUint64((72), true)) !== 0) return null;
|
|
4230
|
+
let offset = Number(v.getBigUint64((80), true)), length = Number(v.getBigUint64((80) + (8), true)), stored = bytes.subarray(offset, offset + length), level0 = scheme === (2) ? inflate?.(stored) ?? null : stored, texelBytes = format === "half" ? (4) * (2) : (4);
|
|
4231
|
+
if (level0 === null || level0.length !== width * height * texelBytes) return null;
|
|
4232
|
+
let levels = [level0], current = { values: read(level0, format), width, height };
|
|
4233
|
+
for (; current.width > 1 || current.height > 1; )
|
|
4234
|
+
current = halve(current.values, current.width, current.height), levels.push(write(current.values, format));
|
|
4235
|
+
let encoded = levels.map((level) => scheme === (2) && compress !== null ? compress(level) : level), dfdOffset = v.getUint32((48), true), dfdLength = v.getUint32((52), true), kvdOffset = v.getUint32((56), true), kvdLength = v.getUint32((60), true), indexEnd = (80) + levels.length * (24), newDfd = align(indexEnd), newKvd = kvdLength === 0 ? 0 : align(newDfd + dfdLength), at = align(kvdLength === 0 ? newDfd + dfdLength : newKvd + kvdLength), placed = new Array(levels.length).fill(0);
|
|
4236
|
+
for (let l = levels.length - 1; l >= 0; l--)
|
|
4237
|
+
placed[l] = at, at = align(at + encoded[l].length);
|
|
4238
|
+
let total = placed[0] + encoded[0].length, out = new Uint8Array(total), w = new DataView(out.buffer);
|
|
4239
|
+
return out.set(bytes.subarray(0, (80))), w.setUint32((40), levels.length, true), w.setUint32((48), newDfd, true), w.setUint32((56), newKvd, true), w.setBigUint64((64), 0n, true), w.setBigUint64((72), 0n, true), w.setUint32((16), v.getUint32((16), true), true), levels.forEach((level, l) => {
|
|
4240
|
+
let entry = (80) + l * (24);
|
|
4241
|
+
w.setBigUint64(entry, BigInt(placed[l]), true), w.setBigUint64(entry + (8), BigInt(encoded[l].length), true), w.setBigUint64(entry + (16), BigInt(level.length), true);
|
|
4242
|
+
}), out.set(bytes.subarray(dfdOffset, dfdOffset + dfdLength), newDfd), kvdLength > 0 && out.set(bytes.subarray(kvdOffset, kvdOffset + kvdLength), newKvd), encoded.forEach((level, l) => out.set(level, placed[l])), out;
|
|
4243
|
+
}
|
|
4244
|
+
|
|
4245
|
+
// src/interactives/progressive/splat.ts
|
|
4246
|
+
var CSPL_MAGIC = 1280332611, CSPL_VERSION = 3, CSPL_VERSION_STATIC = 2, CSPL_HEADER_BYTES = 120, CSPL_HEADER_BYTES_STATIC = 96, CSPL_REGIONS = 96, CSPL_SKIN = 100, REGION_PLANES = 1, SKIN_PLANES = 8, CSPL_COUNT = 8, CSPL_FLAGS = 12, CSPL_LEVEL1 = 56, CSPL_LEVEL2 = 60, CSPL_PALETTE = 64, CSPL_PAYLOAD = 92, SH_DEGREE_MASK = 255, CODEC_SHIFT = 8, CODEC_MASK = 255, CODEC_RAW = 0, CODEC_ZSTD = 1, BASE_PLANES = 16, LABEL_PLANES = 2, CHANNELS2 = 3, REST_BY_DEGREE = [0, 3, 8, 15];
|
|
4247
|
+
function isSplatChunk(bytes) {
|
|
4248
|
+
return bytes.length >= (96) && new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(0, true) === (1280332611);
|
|
4249
|
+
}
|
|
4250
|
+
function planSplat(bytes, inflate, compress) {
|
|
4251
|
+
if (!isSplatChunk(bytes) || compress === null) return null;
|
|
4252
|
+
let v = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength), version = v.getUint32(4, true);
|
|
4253
|
+
if (version !== (3) && version !== (2)) return null;
|
|
4254
|
+
let headerBytes = version === (3) ? (120) : (96);
|
|
4255
|
+
if (bytes.length < headerBytes) return null;
|
|
4256
|
+
let skinned = version === (3) && v.getUint32((100), true) !== 0, labelled = version === (3) && v.getUint32((96), true) !== 0, count2 = v.getUint32((8), true), flags = v.getUint32((12), true), codec = flags >>> (8) & (255), degree = flags & (255);
|
|
4257
|
+
if (degree >= REST_BY_DEGREE.length) return null;
|
|
4258
|
+
let planes = (16) + (degree > 0 ? (2) : 0) + (labelled ? (1) : 0) + (skinned ? (8) : 0), paletteBytes = v.getUint32((64), true) * REST_BY_DEGREE[degree] * (3), payloadBytes = v.getUint32((92), true);
|
|
4259
|
+
if (headerBytes + payloadBytes !== bytes.length || count2 === 0) return null;
|
|
4260
|
+
let payload = bytes.subarray(headerBytes), raw = codec === (0) ? payload : codec === (1) && inflate !== null ? inflate(payload) : null;
|
|
4261
|
+
if (raw === null || raw.length !== count2 * planes + paletteBytes) return null;
|
|
4262
|
+
let level1 = Math.min(count2, v.getUint32((56), true)), level2 = Math.min(level1, v.getUint32((60), true)), bounds2 = [0, level2, level1, count2].filter((b, i, all) => i === 0 || b > all[i - 1]), bands = bounds2.length - 1;
|
|
4263
|
+
if (bands < 2) return null;
|
|
4264
|
+
let frames = [];
|
|
4265
|
+
for (let p = 0; p < planes; p++) {
|
|
4266
|
+
let row = [];
|
|
4267
|
+
for (let k = 0; k < bands; k++) row.push(compress(raw.subarray(p * count2 + bounds2[k], p * count2 + bounds2[k + 1])));
|
|
4268
|
+
frames.push(row);
|
|
4269
|
+
}
|
|
4270
|
+
let palette = paletteBytes > 0 ? compress(raw.subarray(count2 * planes)) : new Uint8Array(0), payloadFor = (last) => {
|
|
4271
|
+
let n = palette.length;
|
|
4272
|
+
for (let p = 0; p < planes; p++) for (let k = 0; k <= last; k++) n += frames[p][k].length;
|
|
4273
|
+
return n;
|
|
4274
|
+
}, full = payloadFor(bands - 1), source = new Uint8Array(headerBytes + full);
|
|
4275
|
+
source.set(bytes.subarray(0, headerBytes));
|
|
4276
|
+
let sv = new DataView(source.buffer);
|
|
4277
|
+
sv.setUint32((12), flags & -65281 | (1) << (8), true), sv.setUint32((92), full, true);
|
|
4278
|
+
let at = headerBytes;
|
|
4279
|
+
for (let p = 0; p < planes; p++)
|
|
4280
|
+
for (let k = 0; k < bands; k++)
|
|
4281
|
+
source.set(frames[p][k], at), at += frames[p][k].length;
|
|
4282
|
+
source.set(palette, at);
|
|
4283
|
+
let table = new TableWriter(), scratch2 = frames.map(() => []), staging = 0, paletteAt = 0, levels = [];
|
|
4284
|
+
for (let k = 0; k < bands; k++) {
|
|
4285
|
+
let segments = [];
|
|
4286
|
+
for (let p = 0; p < planes; p++)
|
|
4287
|
+
scratch2[p].push(staging), segments.push({ dest: staging, bytes: frames[p][k], staged: true }), staging += frames[p][k].length;
|
|
4288
|
+
k === 0 && palette.length > 0 && (paletteAt = staging, segments.push({ dest: staging, bytes: palette, staged: true }), staging += palette.length);
|
|
4289
|
+
let records = bounds2[k + 1], last = k === bands - 1, header = source.slice(0, headerBytes), hv = new DataView(header.buffer);
|
|
4290
|
+
hv.setUint32((8), records, true), hv.setUint32((56), Math.min(level1, records), true), hv.setUint32((60), Math.min(level2, records), true), hv.setUint32((92), payloadFor(k), true);
|
|
4291
|
+
let patches = [writePatch(table, 0, header)], out = headerBytes;
|
|
4292
|
+
for (let p = 0; p < planes; p++)
|
|
4293
|
+
for (let b = 0; b <= k; b++)
|
|
4294
|
+
patches.push({ op: PatchOp.staged, a: out, b: scratch2[p][b], c: frames[p][b].length }), out += frames[p][b].length;
|
|
4295
|
+
palette.length > 0 && (patches.push({ op: PatchOp.staged, a: out, b: paletteAt, c: palette.length }), out += palette.length), patches.push({ op: PatchOp.length, a: out, b: 0, c: 0 }), levels.push([{ segments, patches, quality: last ? PPM : Math.floor(records * PPM / count2) }]);
|
|
4296
|
+
}
|
|
4297
|
+
return { plan: { kind: ProgressiveKind.splat, output: source.length, levels, table: table.finish() }, source };
|
|
4298
|
+
}
|
|
4299
|
+
|
|
4300
|
+
// src/interactives/progressive/build.ts
|
|
4301
|
+
var MIN_PROGRESSIVE_BYTES = 16 * 1024, DEFAULT_PROGRESSIVE_KINDS = /* @__PURE__ */ new Set(["texture", "mesh", "audio", "cells", "splat"]);
|
|
4302
|
+
function planFor(bytes, options) {
|
|
4303
|
+
let allowed = (kind) => options.kinds === void 0 || options.kinds.has(kind), mesh = allowed("mesh") ? planMesh(bytes) : null;
|
|
4304
|
+
if (mesh !== null) return mesh;
|
|
4305
|
+
if (allowed("texture")) {
|
|
4306
|
+
let mipped = withMipChain(bytes, options.inflate ?? null, options.compress ?? null) ?? bytes, texture = planTexture(mipped);
|
|
4307
|
+
if (texture !== null) return { plan: texture, source: mipped };
|
|
4308
|
+
}
|
|
4309
|
+
let splat = allowed("splat") ? planSplat(bytes, options.inflate ?? null, options.compress ?? null) : null;
|
|
4310
|
+
if (splat !== null) return splat;
|
|
4311
|
+
let audio = allowed("audio") ? planAudio(bytes) : null;
|
|
4312
|
+
if (audio !== null) return { plan: audio, source: bytes };
|
|
4313
|
+
let cells = allowed("cells") ? planCells(bytes) : null;
|
|
4314
|
+
return cells !== null ? { plan: cells, source: bytes } : null;
|
|
4315
|
+
}
|
|
4316
|
+
function buildProgressive(input, options = {}) {
|
|
4317
|
+
if (input.length < (options.minBytes ?? MIN_PROGRESSIVE_BYTES)) return null;
|
|
4318
|
+
let bytes = new Uint8Array(input.buffer, input.byteOffset, input.byteLength), planned = planFor(bytes, options);
|
|
4319
|
+
if (planned === null || planned.plan.levels.length < 2) return null;
|
|
4320
|
+
let encoded = encodeContainer(planned.plan);
|
|
4321
|
+
return {
|
|
4322
|
+
kind: planned.plan.kind,
|
|
4323
|
+
source: planned.source,
|
|
4324
|
+
container: encoded.bytes,
|
|
4325
|
+
head: encoded.head,
|
|
4326
|
+
first: encoded.first,
|
|
4327
|
+
levelEnds: encoded.levelEnds,
|
|
4328
|
+
unitEnds: encoded.unitEnds,
|
|
4329
|
+
levelQuality: planned.plan.levels.map((l) => l[l.length - 1].quality)
|
|
4330
|
+
};
|
|
4331
|
+
}
|
|
4332
|
+
|
|
4333
|
+
export { AI_MARK_LABEL, AI_MARK_NAMESPACE, AI_MARK_SOURCES, AI_MARK_TEXT, AiMark, Badge, COZY_PASTEL, ChatLog, ChatPanel, Countdown, DEFAULT_AI_MARK, DEFAULT_LANGUAGES, DEFAULT_QUALITIES, DamageNumbers, Dropdown, FANTASY_PARCHMENT, GeneratedText, InventoryGrid, KIT_NAMESPACE, Leaderboard, LoadingScreen, MAP_HEADING, MAP_PAN_X, MAP_PAN_Y, Minimap, Modal, ModalStack, NEON_ARCADE, PauseScreen, RICH_COLORS, RadialMenu, ResultsScreen, RichText, RichTextError, SIMULATOR_FIXED_STEP_MS, SPORTS_BROADCAST, SettingsScreen, SimulatorUnsupportedError, Slider, THEME_PACKS, TextButton, Toggle, Tooltip, TutorialHint, UI_DEFAULT_FONT, UI_FONT_ROLES, UI_FONT_SET, UiFocusScope, UiNavigator, UiParticles, VirtualList, aiLabel, aiMark, aiMarkTheme, aiMarkVars, applyThemePack, badge, chatLog, chatPanel, countdown, createSimulatorCtx, currentThemePack, damageNumbers, dropdown, focusNodeOf, fontStyle, generatedText, generate_exports as generation, inventoryGrid, isAiGenerated, kitFamily, kitVars, leaderboard, loadingScreen, minimap, modal, modalStack, parts_exports as parts, pauseScreen, progressive_exports as progressive, radialMenu, registerUiFont, resultsScreen, richText, settingsScreen, slider, textButton, themePack, toggle, tooltip, tutorialHint, uiParticles, virtualList, worlds_exports as worlds };
|