From 5211b00d9329c73cc1ef026facc9e77aa1b38050 Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Fri, 28 Jun 2024 04:15:48 +0000 Subject: [PATCH] =?UTF-8?q?Deploying=20to=20pages=20from=20@=20thepaperpil?= =?UTF-8?q?ot/pages@e8e6e124509bfd4a86462c298d470021181676fb=20?= =?UTF-8?q?=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 404.html | 6 +- about/index.html | 14 +- ...p-omr8fP.js => about_index.md.DNEsxkhw.js} | 2 +- assets/about_index.md.DNEsxkhw.lean.js | 1 + assets/about_index.md.p-omr8fP.lean.js | 1 - assets/app.C2YOVlNw.js | 1 + assets/app.JJhOCmj_.js | 1 - ...mP78.js => changelog_index.md.DFC25qVi.js} | 2 +- ...js => changelog_index.md.DFC25qVi.lean.js} | 2 +- ...asLpNF.js => VPLocalSearchBox.hF612Jrh.js} | 4 +- assets/chunks/framework.DvHfxfnp.js | 1 + assets/chunks/framework.VBE0TPts.js | 1 - assets/chunks/theme.Bb5kJd_v.js | 3948 +++++++++++++++++ assets/chunks/theme.Bc6XxFSB.js | 3946 ---------------- .../garden_activitypub_index.md.CWpyy_YP.js | 1 + ...rden_activitypub_index.md.CWpyy_YP.lean.js | 1 + .../garden_activitypub_index.md.DLZvHPXj.js | 1 - ...rden_activitypub_index.md.DLZvHPXj.lean.js | 1 - ...n_advent-incremental_index.md.DJsWBIkL.js} | 2 +- ...ent-incremental_index.md.DJsWBIkL.lean.js} | 2 +- ...ificial-intelligence_index.md.B-XBqRL_.js} | 2 +- ...al-intelligence_index.md.B-XBqRL_.lean.js} | 2 +- ...js => garden_atproto_index.md.DGb10zg_.js} | 2 +- ... garden_atproto_index.md.DGb10zg_.lean.js} | 2 +- ...> garden_babble-buds_index.md.Cdl6QJzR.js} | 2 +- ...den_babble-buds_index.md.Cdl6QJzR.lean.js} | 2 +- ..._capture-the-citadel_index.md.BSzKEtwa.js} | 2 +- ...ure-the-citadel_index.md.BSzKEtwa.lean.js} | 2 +- ... => garden_chat-glue_index.md.BybR6u1O.js} | 2 +- ...arden_chat-glue_index.md.BybR6u1O.lean.js} | 2 +- ...garden_chronological_index.md.CwbET-Cb.js} | 2 +- ...n_chronological_index.md.CwbET-Cb.lean.js} | 2 +- ...5.js => garden_cinny_index.md.ZTWxRUBw.js} | 2 +- ...=> garden_cinny_index.md.ZTWxRUBw.lean.js} | 2 +- ...den_command-palettes_index.md.BrnpBbTf.js} | 2 +- ...ommand-palettes_index.md.BrnpBbTf.lean.js} | 2 +- ...js => garden_commune_index.md.V0TqobbD.js} | 2 +- ... garden_commune_index.md.V0TqobbD.lean.js} | 2 +- ... garden_davey-wreden_index.md.0Vgk25Ik.js} | 2 +- ...en_davey-wreden_index.md.0Vgk25Ik.lean.js} | 2 +- ...garden_decentralized_index.md.DYgiFscC.js} | 2 +- ...n_decentralized_index.md.DYgiFscC.lean.js} | 2 +- ...=> garden_dice-armor_index.md.BE5P-PMF.js} | 2 +- ...rden_dice-armor_index.md.BE5P-PMF.lean.js} | 2 +- ...arden_digital-gardens_index.md.BTOMV_DV.js | 1 - ..._digital-gardens_index.md.BTOMV_DV.lean.js | 1 - ...arden_digital-gardens_index.md.CWPuJsJg.js | 1 + ..._digital-gardens_index.md.CWPuJsJg.lean.js | 1 + ...n_federated-identity_index.md.-RBu4BIs.js} | 2 +- ...erated-identity_index.md.-RBu4BIs.lean.js} | 2 +- ...js => garden_fedi-v2_index.md.BPYmNsKX.js} | 2 +- ... garden_fedi-v2_index.md.BPYmNsKX.lean.js} | 2 +- ... => garden_fediverse_index.md.CexXroKb.js} | 2 +- ...arden_fediverse_index.md.CexXroKb.lean.js} | 2 +- assets/garden_forgejo_index.md.-Mf7Kiyr.js | 1 + .../garden_forgejo_index.md.-Mf7Kiyr.lean.js | 1 + assets/garden_forgejo_index.md.DjFZ67LJ.js | 1 - .../garden_forgejo_index.md.DjFZ67LJ.lean.js | 1 - ...onological-dichotomy_index.md.PROF6kb-.js} | 2 +- ...gical-dichotomy_index.md.PROF6kb-.lean.js} | 2 +- ...s => garden_freeform_index.md.BGHRpas3.js} | 2 +- ...garden_freeform_index.md.BGHRpas3.lean.js} | 2 +- ...garden_game-dev-tree_index.md.NAi3ceZ1.js} | 2 +- ...n_game-dev-tree_index.md.NAi3ceZ1.lean.js} | 2 +- assets/garden_garden-rss_index.md.DGe30PZV.js | 1 + ...arden_garden-rss_index.md.DGe30PZV.lean.js | 1 + assets/garden_garden-rss_index.md.FzV6pCp6.js | 1 - ...arden_garden-rss_index.md.FzV6pCp6.lean.js | 1 - ...appeal-to-developers_index.md.BoP7bn3q.js} | 2 +- ...l-to-developers_index.md.BoP7bn3q.lean.js} | 2 +- ...ls_appeal-to-players_index.md.CXnADb0-.js} | 2 +- ...peal-to-players_index.md.CXnADb0-.lean.js} | 2 +- ...s_defining-the-genre_index.md.DwYrHYrF.js} | 2 +- ...ining-the-genre_index.md.DwYrHYrF.lean.js} | 2 +- ...uide-to-incrementals_index.md.BQydin-1.js} | 2 +- ...to-incrementals_index.md.BQydin-1.lean.js} | 2 +- ...navigating-criticism_index.md.Cma7NB5L.js} | 2 +- ...ating-criticism_index.md.Cma7NB5L.lean.js} | 2 +- ...tals_what-is-content_index.md.DXGnOHrD.js} | 2 +- ...what-is-content_index.md.DXGnOHrD.lean.js} | 2 +- ...en_incremental-social_index.md.B1XcCjeN.js | 1 - ...cremental-social_index.md.B1XcCjeN.lean.js | 1 - ...en_incremental-social_index.md.CsX_i8Lw.js | 1 + ...cremental-social_index.md.CsX_i8Lw.lean.js | 1 + assets/garden_ivy-road_index.md.DEFjS1hP.js | 1 - .../garden_ivy-road_index.md.DEFjS1hP.lean.js | 1 - assets/garden_ivy-road_index.md.DcoTLA7N.js | 1 + .../garden_ivy-road_index.md.DcoTLA7N.lean.js | 1 + ....js => garden_kronos_index.md.Cu7rVJ0m.js} | 2 +- ...> garden_kronos_index.md.Cu7rVJ0m.lean.js} | 2 +- ...rden_life-is-strange_index.md.DZxs1spf.js} | 2 +- ...life-is-strange_index.md.DZxs1spf.lean.js} | 2 +- ....js => garden_logseq_index.md.BtOsUfE8.js} | 2 +- .../garden_logseq_index.md.BtOsUfE8.lean.js | 1 + .../garden_logseq_index.md.CGpHVto-.lean.js | 1 - assets/garden_matrix_index.md.BuCnqAik.js | 1 - .../garden_matrix_index.md.BuCnqAik.lean.js | 1 - assets/garden_matrix_index.md.DkFciSU3.js | 1 + .../garden_matrix_index.md.DkFciSU3.lean.js | 1 + ...CI.js => garden_mbin_index.md.DL7RJU0g.js} | 2 +- ... => garden_mbin_index.md.DL7RJU0g.lean.js} | 2 +- assets/garden_mtx_index.md.BrTCy3ds.js | 1 - assets/garden_mtx_index.md.BrTCy3ds.lean.js | 1 - assets/garden_mtx_index.md.BwWrNpeS.js | 1 + assets/garden_mtx_index.md.BwWrNpeS.lean.js | 1 + ..._my-personal-website_index.md.CGVQsQif.js} | 2 +- ...ersonal-website_index.md.CGVQsQif.lean.js} | 2 +- ...rden_my-projects_index.md.BTL4J3HO.lean.js | 1 - ...> garden_my-projects_index.md.pIi7fe_T.js} | 2 +- ...rden_my-projects_index.md.pIi7fe_T.lean.js | 1 + assets/garden_nostr_index.md.DQgV1bMu.js | 1 + assets/garden_nostr_index.md.DQgV1bMu.lean.js | 1 + assets/garden_nostr_index.md.DuRG5Z1P.js | 1 - assets/garden_nostr_index.md.DuRG5Z1P.lean.js | 1 - .../garden_open-source_index.md.D0998lGJ.js | 1 + ...rden_open-source_index.md.D0998lGJ.lean.js | 1 + .../garden_open-source_index.md.D7bOPf6D.js | 1 - ...rden_open-source_index.md.D7bOPf6D.lean.js | 1 - .../garden_opti-speech_index.md.CRwm6q2W.js | 1 + ...rden_opti-speech_index.md.CRwm6q2W.lean.js | 1 + .../garden_opti-speech_index.md.VQVokYBw.js | 1 - ...rden_opti-speech_index.md.VQVokYBw.lean.js | 1 - ...rden_planar-pioneers_index.md.Bkbkl8EX.js} | 2 +- ...planar-pioneers_index.md.Bkbkl8EX.lean.js} | 2 +- ...en_pre-order-bonuses_index.md.shTakEi9.js} | 2 +- ...e-order-bonuses_index.md.shTakEi9.lean.js} | 2 +- ...den_premium-currency_index.md.C5KciJ55.js} | 2 +- ...remium-currency_index.md.C5KciJ55.lean.js} | 2 +- ... => garden_profectus_index.md.upNDNXA9.js} | 2 +- ...arden_profectus_index.md.upNDNXA9.lean.js} | 2 +- ... garden_social-media_index.md.BdEPqp0F.js} | 2 +- ...en_social-media_index.md.BdEPqp0F.lean.js} | 2 +- assets/garden_synapse_index.md.BkDI3Nqf.js | 1 - .../garden_synapse_index.md.BkDI3Nqf.lean.js | 1 - assets/garden_synapse_index.md.BvwgQk4N.js | 1 + .../garden_synapse_index.md.BvwgQk4N.lean.js | 1 + ...the-beginner-s-guide_index.md.CaCS8ERA.js} | 2 +- ...eginner-s-guide_index.md.CaCS8ERA.lean.js} | 2 +- ... garden_the-cozy-web_index.md.BlzW7dqM.js} | 2 +- ...en_the-cozy-web_index.md.BlzW7dqM.lean.js} | 2 +- ...dieweb_amplification_index.md.C7orSKJb.js} | 2 +- ...b_amplification_index.md.C7orSKJb.lean.js} | 2 +- ...eweb_signature-blocks_index.md.Cb_LJurF.js | 1 + ...signature-blocks_index.md.Cb_LJurF.lean.js | 1 + ...eweb_signature-blocks_index.md.ZTvTccur.js | 1 - ...signature-blocks_index.md.ZTvTccur.lean.js | 1 - ...garden_the-small-web_index.md.BXEnXP2C.js} | 2 +- ...n_the-small-web_index.md.BXEnXP2C.lean.js} | 2 +- ...en_this-knowledge-hub_index.md.BDMSkEmc.js | 1 + ...is-knowledge-hub_index.md.BDMSkEmc.lean.js | 1 + ...en_this-knowledge-hub_index.md.BeloVRmr.js | 1 - ...is-knowledge-hub_index.md.BeloVRmr.lean.js | 1 - ...1.js => garden_v-ecs_index.md.Eos2Bywd.js} | 2 +- ...=> garden_v-ecs_index.md.Eos2Bywd.lean.js} | 2 +- ...eo-game-monetization_index.md.CF0Gozbk.js} | 2 +- ...me-monetization_index.md.CF0Gozbk.lean.js} | 2 +- ... => garden_vitepress_index.md.Jhyyyy8E.js} | 2 +- ...arden_vitepress_index.md.Jhyyyy8E.lean.js} | 2 +- assets/garden_wanderstop_index.md.-GaIeUe_.js | 1 - ...arden_wanderstop_index.md.-GaIeUe_.lean.js | 1 - assets/garden_wanderstop_index.md.DAn8eZ1Y.js | 1 + ...arden_wanderstop_index.md.DAn8eZ1Y.lean.js | 1 + assets/garden_webrings_index.md.CopTyfrh.js | 1 + .../garden_webrings_index.md.CopTyfrh.lean.js | 1 + assets/garden_webrings_index.md.D5KgyhV9.js | 1 - .../garden_webrings_index.md.D5KgyhV9.lean.js | 1 - assets/garden_weird_index.md.CVpFc8I8.js | 1 - assets/garden_weird_index.md.CVpFc8I8.lean.js | 1 - assets/garden_weird_index.md.H-M1_Y4d.js | 1 + assets/garden_weird_index.md.H-M1_Y4d.lean.js | 1 + ...als_design_criticism_index.md.BSUq6GVs.js} | 2 +- ...esign_criticism_index.md.BSUq6GVs.lean.js} | 2 +- ...uide-to-incrementals_index.md.D0no5q0d.js} | 2 +- ...to-incrementals_index.md.D0no5q0d.lean.js} | 2 +- ...gy_appeal-developers_index.md.BdUXpm07.js} | 2 +- ...peal-developers_index.md.BdUXpm07.lean.js} | 2 +- ...dology_appeal-gamers_index.md.DIzXBzVM.js} | 2 +- ...y_appeal-gamers_index.md.DIzXBzVM.lean.js} | 2 +- ...als_ludology_content_index.md.BFqVGpC-.js} | 2 +- ...udology_content_index.md.BFqVGpC-.lean.js} | 2 +- ..._ludology_definition_index.md.NOaZSuDh.js} | 2 +- ...logy_definition_index.md.NOaZSuDh.lean.js} | 2 +- assets/index.md.BanIo7zz.js | 1 - assets/index.md.BanIo7zz.lean.js | 1 - assets/index.md.DTY4Urhb.js | 55 + assets/index.md.DTY4Urhb.lean.js | 55 + ...d.CdesjOn4.js => now_index.md.BMPjLpxb.js} | 2 +- ....lean.js => now_index.md.BMPjLpxb.lean.js} | 2 +- ...devtree_2.0-format-changes.md.DRd3bhvM.js} | 2 +- ...ree_2.0-format-changes.md.DRd3bhvM.lean.js | 1 + ...ree_2.0-format-changes.md.DWZ5VgEH.lean.js | 1 - ... public_gamedevtree_README.md.DVS2_5Qr.js} | 2 +- ...ic_gamedevtree_README.md.DVS2_5Qr.lean.js} | 2 +- ...blic_gamedevtree_changelog.md.Bp63oq83.js} | 2 +- ...gamedevtree_changelog.md.Bp63oq83.lean.js} | 2 +- ...devtree_docs_!general-info.md.DK2xr3yI.js} | 2 +- ...ee_docs_!general-info.md.DK2xr3yI.lean.js} | 2 +- ...edevtree_docs_achievements.md.jhkjuzaR.js} | 2 +- ...ree_docs_achievements.md.jhkjuzaR.lean.js} | 2 +- ...blic_gamedevtree_docs_bars.md.CBtj98pG.js} | 2 +- ...gamedevtree_docs_bars.md.CBtj98pG.lean.js} | 2 +- ...docs_basic-layer-breakdown.md.Ykqytlzk.js} | 2 +- ...basic-layer-breakdown.md.Ykqytlzk.lean.js} | 2 +- ..._gamedevtree_docs_buyables.md.C7aL_4eK.js} | 2 +- ...devtree_docs_buyables.md.C7aL_4eK.lean.js} | 2 +- ...amedevtree_docs_challenges.md.cvYq35wY.js} | 2 +- ...vtree_docs_challenges.md.cvYq35wY.lean.js} | 2 +- ...amedevtree_docs_clickables.md.CwLsimiU.js} | 2 +- ...vtree_docs_clickables.md.CwLsimiU.lean.js} | 2 +- ...ee_docs_custom-tab-layouts.md.DIYFlfWc.js} | 2 +- ...cs_custom-tab-layouts.md.DIYFlfWc.lean.js} | 2 +- ...evtree_docs_getting-started.md.CyNrXhyL.js | 1 + ...e_docs_getting-started.md.CyNrXhyL.lean.js | 1 + ...evtree_docs_getting-started.md.DZiPQZAv.js | 1 - ...e_docs_getting-started.md.DZiPQZAv.lean.js | 1 - ...gamedevtree_docs_infoboxes.md.B4DD8BvC.js} | 2 +- ...evtree_docs_infoboxes.md.B4DD8BvC.lean.js} | 2 +- ...evtree_docs_layer-features.md.I54r8Buk.js} | 2 +- ...e_docs_layer-features.md.I54r8Buk.lean.js} | 2 +- ...devtree_docs_main-mod-info.md.SBsEn9C7.js} | 2 +- ...ee_docs_main-mod-info.md.SBsEn9C7.lean.js} | 2 +- ...amedevtree_docs_milestones.md.Idyk5tE3.js} | 2 +- ...vtree_docs_milestones.md.Idyk5tE3.lean.js} | 2 +- ...docs_subtabs-and-microtabs.md.BhlicLTn.js} | 2 +- ...subtabs-and-microtabs.md.BhlicLTn.lean.js} | 2 +- ...edevtree_docs_updating-tmt.md.Clk0TMnI.js} | 2 +- ...ree_docs_updating-tmt.md.Clk0TMnI.lean.js} | 2 +- ..._gamedevtree_docs_upgrades.md.BspSzPzA.js} | 2 +- ...devtree_docs_upgrades.md.BspSzPzA.lean.js} | 2 +- ... Things_2.0-format-changes.md.BM0FXptY.js} | 2 +- ...gs_2.0-format-changes.md.BM0FXptY.lean.js} | 2 +- ...js => public_kronos_README.md.zcQPLTsl.js} | 2 +- ... public_kronos_README.md.zcQPLTsl.lean.js} | 2 +- ...=> public_kronos_changelog.md.BB6U1JML.js} | 2 +- ...blic_kronos_changelog.md.BB6U1JML.lean.js} | 2 +- ..._kronos_docs_!general-info.md.jKiOCSlr.js} | 2 +- ...os_docs_!general-info.md.jKiOCSlr.lean.js} | 2 +- ...c_kronos_docs_achievements.md.CWA5xmwG.js} | 2 +- ...nos_docs_achievements.md.CWA5xmwG.lean.js} | 2 +- ...=> public_kronos_docs_bars.md.DU3nCdnU.js} | 4 +- ...blic_kronos_docs_bars.md.DU3nCdnU.lean.js} | 2 +- ...docs_basic-layer-breakdown.md.BZhX1dEF.js} | 2 +- ...basic-layer-breakdown.md.BZhX1dEF.lean.js} | 2 +- ...ublic_kronos_docs_buyables.md.0zoux8fQ.js} | 2 +- ..._kronos_docs_buyables.md.0zoux8fQ.lean.js} | 2 +- ...lic_kronos_docs_challenges.md.DvQ_P73q.js} | 2 +- ...ronos_docs_challenges.md.DvQ_P73q.lean.js} | 2 +- ...lic_kronos_docs_clickables.md.C1ENZgWW.js} | 2 +- ...ronos_docs_clickables.md.C1ENZgWW.lean.js} | 2 +- ...os_docs_custom-tab-layouts.md.D4DCXZo7.js} | 2 +- ...cs_custom-tab-layouts.md.D4DCXZo7.lean.js} | 2 +- ...kronos_docs_getting-started.md.N-haPVCK.js | 1 + ...s_docs_getting-started.md.N-haPVCK.lean.js | 1 + ...kronos_docs_getting-started.md.qT4YQHFa.js | 1 - ...s_docs_getting-started.md.qT4YQHFa.lean.js | 1 - ...> public_kronos_docs_grids.md.DGDenQsi.js} | 2 +- ...lic_kronos_docs_grids.md.DGDenQsi.lean.js} | 2 +- ...blic_kronos_docs_infoboxes.md.BXXHzXvY.js} | 2 +- ...kronos_docs_infoboxes.md.BXXHzXvY.lean.js} | 2 +- ...kronos_docs_layer-features.md.C1uOzCZ-.js} | 2 +- ...s_docs_layer-features.md.C1uOzCZ-.lean.js} | 2 +- ..._kronos_docs_main-mod-info.md.TWb3xDwG.js} | 2 +- ...os_docs_main-mod-info.md.TWb3xDwG.lean.js} | 2 +- ...lic_kronos_docs_milestones.md.BqiEbWx4.js} | 2 +- ...ronos_docs_milestones.md.BqiEbWx4.lean.js} | 2 +- ...blic_kronos_docs_particles.md.a4-BPTpH.js} | 2 +- ...kronos_docs_particles.md.a4-BPTpH.lean.js} | 2 +- ...docs_subtabs-and-microtabs.md.B3i34UtK.js} | 2 +- ...subtabs-and-microtabs.md.B3i34UtK.lean.js} | 2 +- ...ees-and-tree-customization.md.bHBppIK5.js} | 2 +- ...nd-tree-customization.md.bHBppIK5.lean.js} | 2 +- ...ic_kronos_docs_updating-tmt.md.BxVzngxM.js | 1 + ...onos_docs_updating-tmt.md.BxVzngxM.lean.js | 1 + ...ic_kronos_docs_updating-tmt.md.yvj4vsSM.js | 1 - ...onos_docs_updating-tmt.md.yvj4vsSM.lean.js | 1 - ...ublic_kronos_docs_upgrades.md.D1pH3BI1.js} | 4 +- ..._kronos_docs_upgrades.md.D1pH3BI1.lean.js} | 2 +- ... Things_2.0-format-changes.md.BwaKJMKt.js} | 2 +- ...gs_2.0-format-changes.md.BwaKJMKt.lean.js} | 2 +- assets/public_lit_README.md.84-k6GVT.js | 1 + assets/public_lit_README.md.84-k6GVT.lean.js | 1 + assets/public_lit_README.md.Dp_XDgLr.js | 1 - assets/public_lit_README.md.Dp_XDgLr.lean.js | 1 - ...js => public_lit_changelog.md.BAnHXxRw.js} | 2 +- ... public_lit_changelog.md.BAnHXxRw.lean.js} | 2 +- ...lic_lit_docs_!general-info.md.D2rjMfl1.js} | 2 +- ...it_docs_!general-info.md.D2rjMfl1.lean.js} | 2 +- ...blic_lit_docs_achievements.md.D0gRoIWt.js} | 2 +- ...lit_docs_achievements.md.D0gRoIWt.lean.js} | 2 +- ...js => public_lit_docs_bars.md.DFEFprv8.js} | 2 +- ... public_lit_docs_bars.md.DFEFprv8.lean.js} | 2 +- ...docs_basic-layer-breakdown.md.DKkhjhoJ.js} | 4 +- ...basic-layer-breakdown.md.DKkhjhoJ.lean.js} | 2 +- ...> public_lit_docs_buyables.md.DrqS8H2k.js} | 2 +- ...lic_lit_docs_buyables.md.DrqS8H2k.lean.js} | 2 +- ...public_lit_docs_challenges.md.DtmSP6zf.js} | 2 +- ...c_lit_docs_challenges.md.DtmSP6zf.lean.js} | 2 +- ...public_lit_docs_clickables.md.CoIWXGHw.js} | 2 +- ...c_lit_docs_clickables.md.CoIWXGHw.lean.js} | 2 +- ...it_docs_custom-tab-layouts.md.C-TlZHYA.js} | 2 +- ...cs_custom-tab-layouts.md.C-TlZHYA.lean.js} | 2 +- ...ic_lit_docs_getting-started.md.BoU9JbJY.js | 1 - ...t_docs_getting-started.md.BoU9JbJY.lean.js | 1 - ...ic_lit_docs_getting-started.md.BxRLZ8_n.js | 1 + ...t_docs_getting-started.md.BxRLZ8_n.lean.js | 1 + ... public_lit_docs_infoboxes.md.C0nPRfky.js} | 2 +- ...ic_lit_docs_infoboxes.md.C0nPRfky.lean.js} | 2 +- ...ic_lit_docs_layer-features.md.DF81fjyw.js} | 2 +- ...t_docs_layer-features.md.DF81fjyw.lean.js} | 2 +- ...lic_lit_docs_main-mod-info.md.CcRWcMdS.js} | 2 +- ...it_docs_main-mod-info.md.CcRWcMdS.lean.js} | 2 +- ...public_lit_docs_milestones.md.CGwN80sv.js} | 2 +- ...c_lit_docs_milestones.md.CGwN80sv.lean.js} | 2 +- ...docs_subtabs-and-microtabs.md.BQEflp-r.js} | 4 +- ...subtabs-and-microtabs.md.BQEflp-r.lean.js} | 2 +- ...ees-and-tree-customization.md.C8iASWgy.js} | 2 +- ...nd-tree-customization.md.C8iASWgy.lean.js} | 2 +- ...ublic_lit_docs_updating-tmt.md.C3AjdOjF.js | 1 + ..._lit_docs_updating-tmt.md.C3AjdOjF.lean.js | 1 + ...ublic_lit_docs_updating-tmt.md.CjXsxPz8.js | 1 - ..._lit_docs_updating-tmt.md.CjXsxPz8.lean.js | 1 - ...> public_lit_docs_upgrades.md.D1Ns9VTR.js} | 2 +- ...lic_lit_docs_upgrades.md.D1Ns9VTR.lean.js} | 2 +- ...{style.BPlHIFta.css => style.ByNYS6_U.css} | 2 +- changelog/atom | 200 +- changelog/index.html | 14 +- changelog/json | 50 +- changelog/rss | 200 +- garden/activitypub/index.html | 16 +- garden/advent-incremental/index.html | 16 +- garden/artificial-intelligence/index.html | 16 +- garden/atproto/index.html | 16 +- garden/babble-buds/index.html | 16 +- garden/capture-the-citadel/index.html | 16 +- garden/chat-glue/index.html | 16 +- garden/chronological/index.html | 16 +- garden/cinny/index.html | 16 +- garden/command-palettes/index.html | 16 +- garden/commune/index.html | 16 +- garden/davey-wreden/index.html | 16 +- garden/decentralized/index.html | 16 +- garden/dice-armor/index.html | 16 +- garden/digital-gardens/index.html | 16 +- garden/federated-identity/index.html | 16 +- garden/fedi-v2/index.html | 16 +- garden/fediverse/index.html | 16 +- garden/forgejo/index.html | 16 +- .../index.html | 16 +- garden/freeform/index.html | 16 +- garden/game-dev-tree/index.html | 16 +- garden/garden-rss/index.html | 16 +- .../appeal-to-developers/index.html | 16 +- .../appeal-to-players/index.html | 16 +- .../defining-the-genre/index.html | 16 +- garden/guide-to-incrementals/index.html | 16 +- .../navigating-criticism/index.html | 16 +- .../what-is-content/index.html | 16 +- garden/incremental-social/index.html | 16 +- garden/ivy-road/index.html | 16 +- garden/kronos/index.html | 16 +- garden/life-is-strange/index.html | 16 +- garden/logseq/index.html | 16 +- garden/matrix/index.html | 16 +- garden/mbin/index.html | 16 +- garden/mtx/index.html | 16 +- garden/my-personal-website/index.html | 16 +- garden/my-projects/index.html | 16 +- garden/nostr/index.html | 16 +- garden/open-source/index.html | 16 +- garden/opti-speech/index.html | 16 +- garden/planar-pioneers/index.html | 16 +- garden/pre-order-bonuses/index.html | 16 +- garden/premium-currency/index.html | 16 +- garden/profectus/index.html | 16 +- garden/social-media/index.html | 16 +- garden/synapse/index.html | 16 +- garden/the-beginner-s-guide/index.html | 16 +- garden/the-cozy-web/index.html | 16 +- garden/the-indieweb/amplification/index.html | 16 +- .../the-indieweb/signature-blocks/index.html | 16 +- garden/the-small-web/index.html | 16 +- garden/this-knowledge-hub/index.html | 16 +- garden/v-ecs/index.html | 16 +- garden/video-game-monetization/index.html | 16 +- garden/vitepress/index.html | 16 +- garden/wanderstop/index.html | 16 +- garden/webrings/index.html | 16 +- garden/weird/index.html | 16 +- .../design/criticism/index.html | 16 +- guide-to-incrementals/index.html | 16 +- .../ludology/appeal-developers/index.html | 16 +- .../ludology/appeal-gamers/index.html | 16 +- .../ludology/content/index.html | 16 +- .../ludology/definition/index.html | 16 +- hashmap.json | 2 +- index.html | 14 +- now/index.html | 16 +- public/gamedevtree/2.0-format-changes.html | 14 +- public/gamedevtree/README.html | 14 +- public/gamedevtree/changelog.html | 14 +- public/gamedevtree/docs/!general-info.html | 14 +- public/gamedevtree/docs/achievements.html | 16 +- public/gamedevtree/docs/bars.html | 16 +- .../docs/basic-layer-breakdown.html | 16 +- public/gamedevtree/docs/buyables.html | 16 +- public/gamedevtree/docs/challenges.html | 16 +- public/gamedevtree/docs/clickables.html | 16 +- .../gamedevtree/docs/custom-tab-layouts.html | 16 +- public/gamedevtree/docs/getting-started.html | 14 +- public/gamedevtree/docs/infoboxes.html | 16 +- public/gamedevtree/docs/layer-features.html | 16 +- public/gamedevtree/docs/main-mod-info.html | 16 +- public/gamedevtree/docs/milestones.html | 16 +- .../docs/subtabs-and-microtabs.html | 16 +- public/gamedevtree/docs/updating-tmt.html | 14 +- public/gamedevtree/docs/upgrades.html | 16 +- .../kronos/Old Things/2.0-format-changes.html | 14 +- public/kronos/README.html | 14 +- public/kronos/changelog.html | 14 +- public/kronos/docs/!general-info.html | 14 +- public/kronos/docs/achievements.html | 16 +- public/kronos/docs/bars.html | 16 +- public/kronos/docs/basic-layer-breakdown.html | 16 +- public/kronos/docs/buyables.html | 16 +- public/kronos/docs/challenges.html | 16 +- public/kronos/docs/clickables.html | 16 +- public/kronos/docs/custom-tab-layouts.html | 16 +- public/kronos/docs/getting-started.html | 14 +- public/kronos/docs/grids.html | 16 +- public/kronos/docs/infoboxes.html | 16 +- public/kronos/docs/layer-features.html | 16 +- public/kronos/docs/main-mod-info.html | 16 +- public/kronos/docs/milestones.html | 16 +- public/kronos/docs/particles.html | 16 +- public/kronos/docs/subtabs-and-microtabs.html | 16 +- .../docs/trees-and-tree-customization.html | 16 +- public/kronos/docs/updating-tmt.html | 14 +- public/kronos/docs/upgrades.html | 16 +- public/lit/Old Things/2.0-format-changes.html | 14 +- public/lit/README.html | 14 +- public/lit/changelog.html | 14 +- public/lit/docs/!general-info.html | 14 +- public/lit/docs/achievements.html | 16 +- public/lit/docs/bars.html | 16 +- public/lit/docs/basic-layer-breakdown.html | 16 +- public/lit/docs/buyables.html | 16 +- public/lit/docs/challenges.html | 16 +- public/lit/docs/clickables.html | 16 +- public/lit/docs/custom-tab-layouts.html | 16 +- public/lit/docs/getting-started.html | 14 +- public/lit/docs/infoboxes.html | 16 +- public/lit/docs/layer-features.html | 16 +- public/lit/docs/main-mod-info.html | 16 +- public/lit/docs/milestones.html | 16 +- public/lit/docs/subtabs-and-microtabs.html | 16 +- .../docs/trees-and-tree-customization.html | 16 +- public/lit/docs/updating-tmt.html | 14 +- public/lit/docs/upgrades.html | 16 +- 458 files changed, 5583 insertions(+), 5473 deletions(-) rename assets/{about_index.md.p-omr8fP.js => about_index.md.DNEsxkhw.js} (90%) create mode 100644 assets/about_index.md.DNEsxkhw.lean.js delete mode 100644 assets/about_index.md.p-omr8fP.lean.js create mode 100644 assets/app.C2YOVlNw.js delete mode 100644 assets/app.JJhOCmj_.js rename assets/{changelog_index.md.BVGEmP78.js => changelog_index.md.DFC25qVi.js} (99%) rename assets/{changelog_index.md.BVGEmP78.lean.js => changelog_index.md.DFC25qVi.lean.js} (71%) rename assets/chunks/{VPLocalSearchBox.DMasLpNF.js => VPLocalSearchBox.hF612Jrh.js} (95%) create mode 100644 assets/chunks/framework.DvHfxfnp.js delete mode 100644 assets/chunks/framework.VBE0TPts.js create mode 100644 assets/chunks/theme.Bb5kJd_v.js delete mode 100644 assets/chunks/theme.Bc6XxFSB.js create mode 100644 assets/garden_activitypub_index.md.CWpyy_YP.js create mode 100644 assets/garden_activitypub_index.md.CWpyy_YP.lean.js delete mode 100644 assets/garden_activitypub_index.md.DLZvHPXj.js delete mode 100644 assets/garden_activitypub_index.md.DLZvHPXj.lean.js rename assets/{garden_advent-incremental_index.md.CbzLDkso.js => garden_advent-incremental_index.md.DJsWBIkL.js} (89%) rename assets/{garden_advent-incremental_index.md.CbzLDkso.lean.js => garden_advent-incremental_index.md.DJsWBIkL.lean.js} (77%) rename assets/{garden_artificial-intelligence_index.md.BevJsmT8.js => garden_artificial-intelligence_index.md.B-XBqRL_.js} (92%) rename assets/{garden_artificial-intelligence_index.md.BevJsmT8.lean.js => garden_artificial-intelligence_index.md.B-XBqRL_.lean.js} (77%) rename assets/{garden_atproto_index.md.DS2dsksJ.js => garden_atproto_index.md.DGb10zg_.js} (73%) rename assets/{garden_atproto_index.md.DS2dsksJ.lean.js => garden_atproto_index.md.DGb10zg_.lean.js} (59%) rename assets/{garden_babble-buds_index.md.D-MhN_8s.js => garden_babble-buds_index.md.Cdl6QJzR.js} (90%) rename assets/{garden_babble-buds_index.md.D-MhN_8s.lean.js => garden_babble-buds_index.md.Cdl6QJzR.lean.js} (75%) rename assets/{garden_capture-the-citadel_index.md.B81Zl3jT.js => garden_capture-the-citadel_index.md.BSzKEtwa.js} (69%) rename assets/{garden_capture-the-citadel_index.md.B81Zl3jT.lean.js => garden_capture-the-citadel_index.md.BSzKEtwa.lean.js} (69%) rename assets/{garden_chat-glue_index.md.DrB0BEZa.js => garden_chat-glue_index.md.BybR6u1O.js} (85%) rename assets/{garden_chat-glue_index.md.DrB0BEZa.lean.js => garden_chat-glue_index.md.BybR6u1O.lean.js} (85%) rename assets/{garden_chronological_index.md.Du31gSeZ.js => garden_chronological_index.md.CwbET-Cb.js} (88%) rename assets/{garden_chronological_index.md.Du31gSeZ.lean.js => garden_chronological_index.md.CwbET-Cb.lean.js} (75%) rename assets/{garden_cinny_index.md.Ch9QVly5.js => garden_cinny_index.md.ZTWxRUBw.js} (59%) rename assets/{garden_cinny_index.md.Ch9QVly5.lean.js => garden_cinny_index.md.ZTWxRUBw.lean.js} (59%) rename assets/{garden_command-palettes_index.md.Br8Wqkvv.js => garden_command-palettes_index.md.BrnpBbTf.js} (82%) rename assets/{garden_command-palettes_index.md.Br8Wqkvv.lean.js => garden_command-palettes_index.md.BrnpBbTf.lean.js} (59%) rename assets/{garden_commune_index.md.VBDo-SJ7.js => garden_commune_index.md.V0TqobbD.js} (89%) rename assets/{garden_commune_index.md.VBDo-SJ7.lean.js => garden_commune_index.md.V0TqobbD.lean.js} (56%) rename assets/{garden_davey-wreden_index.md.Bxj_Btrg.js => garden_davey-wreden_index.md.0Vgk25Ik.js} (86%) rename assets/{garden_davey-wreden_index.md.Bxj_Btrg.lean.js => garden_davey-wreden_index.md.0Vgk25Ik.lean.js} (66%) rename assets/{garden_decentralized_index.md.BThYPn4k.js => garden_decentralized_index.md.DYgiFscC.js} (90%) rename assets/{garden_decentralized_index.md.BThYPn4k.lean.js => garden_decentralized_index.md.DYgiFscC.lean.js} (75%) rename assets/{garden_dice-armor_index.md.CjnpEGDY.js => garden_dice-armor_index.md.BE5P-PMF.js} (98%) rename assets/{garden_dice-armor_index.md.CjnpEGDY.lean.js => garden_dice-armor_index.md.BE5P-PMF.lean.js} (84%) delete mode 100644 assets/garden_digital-gardens_index.md.BTOMV_DV.js delete mode 100644 assets/garden_digital-gardens_index.md.BTOMV_DV.lean.js create mode 100644 assets/garden_digital-gardens_index.md.CWPuJsJg.js create mode 100644 assets/garden_digital-gardens_index.md.CWPuJsJg.lean.js rename assets/{garden_federated-identity_index.md.Czr5VTIi.js => garden_federated-identity_index.md.-RBu4BIs.js} (84%) rename assets/{garden_federated-identity_index.md.Czr5VTIi.lean.js => garden_federated-identity_index.md.-RBu4BIs.lean.js} (63%) rename assets/{garden_fedi-v2_index.md.BJxh2Je6.js => garden_fedi-v2_index.md.BPYmNsKX.js} (98%) rename assets/{garden_fedi-v2_index.md.BJxh2Je6.lean.js => garden_fedi-v2_index.md.BPYmNsKX.lean.js} (73%) rename assets/{garden_fediverse_index.md.BoF29t1o.js => garden_fediverse_index.md.CexXroKb.js} (86%) rename assets/{garden_fediverse_index.md.BoF29t1o.lean.js => garden_fediverse_index.md.CexXroKb.lean.js} (68%) create mode 100644 assets/garden_forgejo_index.md.-Mf7Kiyr.js create mode 100644 assets/garden_forgejo_index.md.-Mf7Kiyr.lean.js delete mode 100644 assets/garden_forgejo_index.md.DjFZ67LJ.js delete mode 100644 assets/garden_forgejo_index.md.DjFZ67LJ.lean.js rename assets/{garden_freeform-vs-chronological-dichotomy_index.md.D64deYnh.js => garden_freeform-vs-chronological-dichotomy_index.md.PROF6kb-.js} (85%) rename assets/{garden_freeform-vs-chronological-dichotomy_index.md.D64deYnh.lean.js => garden_freeform-vs-chronological-dichotomy_index.md.PROF6kb-.lean.js} (85%) rename assets/{garden_freeform_index.md.Cm941aMp.js => garden_freeform_index.md.BGHRpas3.js} (78%) rename assets/{garden_freeform_index.md.Cm941aMp.lean.js => garden_freeform_index.md.BGHRpas3.lean.js} (56%) rename assets/{garden_game-dev-tree_index.md.DYS7_xxo.js => garden_game-dev-tree_index.md.NAi3ceZ1.js} (86%) rename assets/{garden_game-dev-tree_index.md.DYS7_xxo.lean.js => garden_game-dev-tree_index.md.NAi3ceZ1.lean.js} (75%) create mode 100644 assets/garden_garden-rss_index.md.DGe30PZV.js create mode 100644 assets/garden_garden-rss_index.md.DGe30PZV.lean.js delete mode 100644 assets/garden_garden-rss_index.md.FzV6pCp6.js delete mode 100644 assets/garden_garden-rss_index.md.FzV6pCp6.lean.js rename assets/{garden_guide-to-incrementals_appeal-to-developers_index.md.C9QEK0j6.js => garden_guide-to-incrementals_appeal-to-developers_index.md.BoP7bn3q.js} (96%) rename assets/{garden_guide-to-incrementals_appeal-to-developers_index.md.C9QEK0j6.lean.js => garden_guide-to-incrementals_appeal-to-developers_index.md.BoP7bn3q.lean.js} (80%) rename assets/{garden_guide-to-incrementals_appeal-to-players_index.md.tNU97J-Z.js => garden_guide-to-incrementals_appeal-to-players_index.md.CXnADb0-.js} (98%) rename assets/{garden_guide-to-incrementals_appeal-to-players_index.md.tNU97J-Z.lean.js => garden_guide-to-incrementals_appeal-to-players_index.md.CXnADb0-.lean.js} (80%) rename assets/{garden_guide-to-incrementals_defining-the-genre_index.md.CnpSquU9.js => garden_guide-to-incrementals_defining-the-genre_index.md.DwYrHYrF.js} (99%) rename assets/{garden_guide-to-incrementals_defining-the-genre_index.md.CnpSquU9.lean.js => garden_guide-to-incrementals_defining-the-genre_index.md.DwYrHYrF.lean.js} (80%) rename assets/{garden_guide-to-incrementals_index.md.DEblpv1O.js => garden_guide-to-incrementals_index.md.BQydin-1.js} (94%) rename assets/{garden_guide-to-incrementals_index.md.DEblpv1O.lean.js => garden_guide-to-incrementals_index.md.BQydin-1.lean.js} (76%) rename assets/{garden_guide-to-incrementals_navigating-criticism_index.md.CvIMd3Io.js => garden_guide-to-incrementals_navigating-criticism_index.md.Cma7NB5L.js} (97%) rename assets/{garden_guide-to-incrementals_navigating-criticism_index.md.CvIMd3Io.lean.js => garden_guide-to-incrementals_navigating-criticism_index.md.Cma7NB5L.lean.js} (80%) rename assets/{garden_guide-to-incrementals_what-is-content_index.md.BdP15SmB.js => garden_guide-to-incrementals_what-is-content_index.md.DXGnOHrD.js} (98%) rename assets/{garden_guide-to-incrementals_what-is-content_index.md.BdP15SmB.lean.js => garden_guide-to-incrementals_what-is-content_index.md.DXGnOHrD.lean.js} (79%) delete mode 100644 assets/garden_incremental-social_index.md.B1XcCjeN.js delete mode 100644 assets/garden_incremental-social_index.md.B1XcCjeN.lean.js create mode 100644 assets/garden_incremental-social_index.md.CsX_i8Lw.js create mode 100644 assets/garden_incremental-social_index.md.CsX_i8Lw.lean.js delete mode 100644 assets/garden_ivy-road_index.md.DEFjS1hP.js delete mode 100644 assets/garden_ivy-road_index.md.DEFjS1hP.lean.js create mode 100644 assets/garden_ivy-road_index.md.DcoTLA7N.js create mode 100644 assets/garden_ivy-road_index.md.DcoTLA7N.lean.js rename assets/{garden_kronos_index.md.DWmqXBaE.js => garden_kronos_index.md.Cu7rVJ0m.js} (77%) rename assets/{garden_kronos_index.md.DWmqXBaE.lean.js => garden_kronos_index.md.Cu7rVJ0m.lean.js} (59%) rename assets/{garden_life-is-strange_index.md.Cvu7AqjX.js => garden_life-is-strange_index.md.DZxs1spf.js} (98%) rename assets/{garden_life-is-strange_index.md.Cvu7AqjX.lean.js => garden_life-is-strange_index.md.DZxs1spf.lean.js} (83%) rename assets/{garden_logseq_index.md.CGpHVto-.js => garden_logseq_index.md.BtOsUfE8.js} (67%) create mode 100644 assets/garden_logseq_index.md.BtOsUfE8.lean.js delete mode 100644 assets/garden_logseq_index.md.CGpHVto-.lean.js delete mode 100644 assets/garden_matrix_index.md.BuCnqAik.js delete mode 100644 assets/garden_matrix_index.md.BuCnqAik.lean.js create mode 100644 assets/garden_matrix_index.md.DkFciSU3.js create mode 100644 assets/garden_matrix_index.md.DkFciSU3.lean.js rename assets/{garden_mbin_index.md.CsZu6UCI.js => garden_mbin_index.md.DL7RJU0g.js} (65%) rename assets/{garden_mbin_index.md.CsZu6UCI.lean.js => garden_mbin_index.md.DL7RJU0g.lean.js} (65%) delete mode 100644 assets/garden_mtx_index.md.BrTCy3ds.js delete mode 100644 assets/garden_mtx_index.md.BrTCy3ds.lean.js create mode 100644 assets/garden_mtx_index.md.BwWrNpeS.js create mode 100644 assets/garden_mtx_index.md.BwWrNpeS.lean.js rename assets/{garden_my-personal-website_index.md.B7pFBXsd.js => garden_my-personal-website_index.md.CGVQsQif.js} (93%) rename assets/{garden_my-personal-website_index.md.B7pFBXsd.lean.js => garden_my-personal-website_index.md.CGVQsQif.lean.js} (54%) delete mode 100644 assets/garden_my-projects_index.md.BTL4J3HO.lean.js rename assets/{garden_my-projects_index.md.BTL4J3HO.js => garden_my-projects_index.md.pIi7fe_T.js} (82%) create mode 100644 assets/garden_my-projects_index.md.pIi7fe_T.lean.js create mode 100644 assets/garden_nostr_index.md.DQgV1bMu.js create mode 100644 assets/garden_nostr_index.md.DQgV1bMu.lean.js delete mode 100644 assets/garden_nostr_index.md.DuRG5Z1P.js delete mode 100644 assets/garden_nostr_index.md.DuRG5Z1P.lean.js create mode 100644 assets/garden_open-source_index.md.D0998lGJ.js create mode 100644 assets/garden_open-source_index.md.D0998lGJ.lean.js delete mode 100644 assets/garden_open-source_index.md.D7bOPf6D.js delete mode 100644 assets/garden_open-source_index.md.D7bOPf6D.lean.js create mode 100644 assets/garden_opti-speech_index.md.CRwm6q2W.js create mode 100644 assets/garden_opti-speech_index.md.CRwm6q2W.lean.js delete mode 100644 assets/garden_opti-speech_index.md.VQVokYBw.js delete mode 100644 assets/garden_opti-speech_index.md.VQVokYBw.lean.js rename assets/{garden_planar-pioneers_index.md.CrWQHny8.js => garden_planar-pioneers_index.md.Bkbkl8EX.js} (77%) rename assets/{garden_planar-pioneers_index.md.CrWQHny8.lean.js => garden_planar-pioneers_index.md.Bkbkl8EX.lean.js} (61%) rename assets/{garden_pre-order-bonuses_index.md.CCGmxPHN.js => garden_pre-order-bonuses_index.md.shTakEi9.js} (89%) rename assets/{garden_pre-order-bonuses_index.md.CCGmxPHN.lean.js => garden_pre-order-bonuses_index.md.shTakEi9.lean.js} (76%) rename assets/{garden_premium-currency_index.md.DnHfK06C.js => garden_premium-currency_index.md.C5KciJ55.js} (86%) rename assets/{garden_premium-currency_index.md.DnHfK06C.lean.js => garden_premium-currency_index.md.C5KciJ55.lean.js} (75%) rename assets/{garden_profectus_index.md.BmLQh2zb.js => garden_profectus_index.md.upNDNXA9.js} (90%) rename assets/{garden_profectus_index.md.BmLQh2zb.lean.js => garden_profectus_index.md.upNDNXA9.lean.js} (74%) rename assets/{garden_social-media_index.md.DYnTYuzx.js => garden_social-media_index.md.BdEPqp0F.js} (82%) rename assets/{garden_social-media_index.md.DYnTYuzx.lean.js => garden_social-media_index.md.BdEPqp0F.lean.js} (59%) delete mode 100644 assets/garden_synapse_index.md.BkDI3Nqf.js delete mode 100644 assets/garden_synapse_index.md.BkDI3Nqf.lean.js create mode 100644 assets/garden_synapse_index.md.BvwgQk4N.js create mode 100644 assets/garden_synapse_index.md.BvwgQk4N.lean.js rename assets/{garden_the-beginner-s-guide_index.md.Bh4pwbi0.js => garden_the-beginner-s-guide_index.md.CaCS8ERA.js} (79%) rename assets/{garden_the-beginner-s-guide_index.md.Bh4pwbi0.lean.js => garden_the-beginner-s-guide_index.md.CaCS8ERA.lean.js} (54%) rename assets/{garden_the-cozy-web_index.md.Dphn0Ga1.js => garden_the-cozy-web_index.md.BlzW7dqM.js} (86%) rename assets/{garden_the-cozy-web_index.md.Dphn0Ga1.lean.js => garden_the-cozy-web_index.md.BlzW7dqM.lean.js} (86%) rename assets/{garden_the-indieweb_amplification_index.md.CdpguDI2.js => garden_the-indieweb_amplification_index.md.C7orSKJb.js} (89%) rename assets/{garden_the-indieweb_amplification_index.md.CdpguDI2.lean.js => garden_the-indieweb_amplification_index.md.C7orSKJb.lean.js} (77%) create mode 100644 assets/garden_the-indieweb_signature-blocks_index.md.Cb_LJurF.js create mode 100644 assets/garden_the-indieweb_signature-blocks_index.md.Cb_LJurF.lean.js delete mode 100644 assets/garden_the-indieweb_signature-blocks_index.md.ZTvTccur.js delete mode 100644 assets/garden_the-indieweb_signature-blocks_index.md.ZTvTccur.lean.js rename assets/{garden_the-small-web_index.md.C-NKW4Ch.js => garden_the-small-web_index.md.BXEnXP2C.js} (97%) rename assets/{garden_the-small-web_index.md.C-NKW4Ch.lean.js => garden_the-small-web_index.md.BXEnXP2C.lean.js} (61%) create mode 100644 assets/garden_this-knowledge-hub_index.md.BDMSkEmc.js create mode 100644 assets/garden_this-knowledge-hub_index.md.BDMSkEmc.lean.js delete mode 100644 assets/garden_this-knowledge-hub_index.md.BeloVRmr.js delete mode 100644 assets/garden_this-knowledge-hub_index.md.BeloVRmr.lean.js rename assets/{garden_v-ecs_index.md.DYGQYRv1.js => garden_v-ecs_index.md.Eos2Bywd.js} (94%) rename assets/{garden_v-ecs_index.md.DYGQYRv1.lean.js => garden_v-ecs_index.md.Eos2Bywd.lean.js} (83%) rename assets/{garden_video-game-monetization_index.md.ClgnBtf0.js => garden_video-game-monetization_index.md.CF0Gozbk.js} (94%) rename assets/{garden_video-game-monetization_index.md.ClgnBtf0.lean.js => garden_video-game-monetization_index.md.CF0Gozbk.lean.js} (77%) rename assets/{garden_vitepress_index.md.BwIztJxS.js => garden_vitepress_index.md.Jhyyyy8E.js} (72%) rename assets/{garden_vitepress_index.md.BwIztJxS.lean.js => garden_vitepress_index.md.Jhyyyy8E.lean.js} (72%) delete mode 100644 assets/garden_wanderstop_index.md.-GaIeUe_.js delete mode 100644 assets/garden_wanderstop_index.md.-GaIeUe_.lean.js create mode 100644 assets/garden_wanderstop_index.md.DAn8eZ1Y.js create mode 100644 assets/garden_wanderstop_index.md.DAn8eZ1Y.lean.js create mode 100644 assets/garden_webrings_index.md.CopTyfrh.js create mode 100644 assets/garden_webrings_index.md.CopTyfrh.lean.js delete mode 100644 assets/garden_webrings_index.md.D5KgyhV9.js delete mode 100644 assets/garden_webrings_index.md.D5KgyhV9.lean.js delete mode 100644 assets/garden_weird_index.md.CVpFc8I8.js delete mode 100644 assets/garden_weird_index.md.CVpFc8I8.lean.js create mode 100644 assets/garden_weird_index.md.H-M1_Y4d.js create mode 100644 assets/garden_weird_index.md.H-M1_Y4d.lean.js rename assets/{guide-to-incrementals_design_criticism_index.md.B84_a_FO.js => guide-to-incrementals_design_criticism_index.md.BSUq6GVs.js} (97%) rename assets/{guide-to-incrementals_design_criticism_index.md.B84_a_FO.lean.js => guide-to-incrementals_design_criticism_index.md.BSUq6GVs.lean.js} (79%) rename assets/{guide-to-incrementals_index.md.BcJvnxZ-.js => guide-to-incrementals_index.md.D0no5q0d.js} (94%) rename assets/{guide-to-incrementals_index.md.BcJvnxZ-.lean.js => guide-to-incrementals_index.md.D0no5q0d.lean.js} (76%) rename assets/{guide-to-incrementals_ludology_appeal-developers_index.md.CIgpgpNd.js => guide-to-incrementals_ludology_appeal-developers_index.md.BdUXpm07.js} (96%) rename assets/{guide-to-incrementals_ludology_appeal-developers_index.md.CIgpgpNd.lean.js => guide-to-incrementals_ludology_appeal-developers_index.md.BdUXpm07.lean.js} (80%) rename assets/{guide-to-incrementals_ludology_appeal-gamers_index.md.KF6NxDNl.js => guide-to-incrementals_ludology_appeal-gamers_index.md.DIzXBzVM.js} (98%) rename assets/{guide-to-incrementals_ludology_appeal-gamers_index.md.KF6NxDNl.lean.js => guide-to-incrementals_ludology_appeal-gamers_index.md.DIzXBzVM.lean.js} (79%) rename assets/{guide-to-incrementals_ludology_content_index.md.CIJoP_r0.js => guide-to-incrementals_ludology_content_index.md.BFqVGpC-.js} (98%) rename assets/{guide-to-incrementals_ludology_content_index.md.CIJoP_r0.lean.js => guide-to-incrementals_ludology_content_index.md.BFqVGpC-.lean.js} (79%) rename assets/{guide-to-incrementals_ludology_definition_index.md.CmTVBDoy.js => guide-to-incrementals_ludology_definition_index.md.NOaZSuDh.js} (99%) rename assets/{guide-to-incrementals_ludology_definition_index.md.CmTVBDoy.lean.js => guide-to-incrementals_ludology_definition_index.md.NOaZSuDh.lean.js} (79%) delete mode 100644 assets/index.md.BanIo7zz.js delete mode 100644 assets/index.md.BanIo7zz.lean.js create mode 100644 assets/index.md.DTY4Urhb.js create mode 100644 assets/index.md.DTY4Urhb.lean.js rename assets/{now_index.md.CdesjOn4.js => now_index.md.BMPjLpxb.js} (93%) rename assets/{now_index.md.CdesjOn4.lean.js => now_index.md.BMPjLpxb.lean.js} (72%) rename assets/{public_gamedevtree_2.0-format-changes.md.DWZ5VgEH.js => public_gamedevtree_2.0-format-changes.md.DRd3bhvM.js} (82%) create mode 100644 assets/public_gamedevtree_2.0-format-changes.md.DRd3bhvM.lean.js delete mode 100644 assets/public_gamedevtree_2.0-format-changes.md.DWZ5VgEH.lean.js rename assets/{public_gamedevtree_README.md.B6IoVQ-I.js => public_gamedevtree_README.md.DVS2_5Qr.js} (83%) rename assets/{public_gamedevtree_README.md.B6IoVQ-I.lean.js => public_gamedevtree_README.md.DVS2_5Qr.lean.js} (83%) rename assets/{public_gamedevtree_changelog.md.BFpQdU6f.js => public_gamedevtree_changelog.md.Bp63oq83.js} (97%) rename assets/{public_gamedevtree_changelog.md.BFpQdU6f.lean.js => public_gamedevtree_changelog.md.Bp63oq83.lean.js} (71%) rename assets/{public_gamedevtree_docs_!general-info.md.B4kcWpV-.js => public_gamedevtree_docs_!general-info.md.DK2xr3yI.js} (97%) rename assets/{public_gamedevtree_docs_!general-info.md.B4kcWpV-.lean.js => public_gamedevtree_docs_!general-info.md.DK2xr3yI.lean.js} (72%) rename assets/{public_gamedevtree_docs_achievements.md.C6gZOG4E.js => public_gamedevtree_docs_achievements.md.jhkjuzaR.js} (97%) rename assets/{public_gamedevtree_docs_achievements.md.C6gZOG4E.lean.js => public_gamedevtree_docs_achievements.md.jhkjuzaR.lean.js} (72%) rename assets/{public_gamedevtree_docs_bars.md.1NZ3Fz1N.js => public_gamedevtree_docs_bars.md.CBtj98pG.js} (96%) rename assets/{public_gamedevtree_docs_bars.md.1NZ3Fz1N.lean.js => public_gamedevtree_docs_bars.md.CBtj98pG.lean.js} (70%) rename assets/{public_gamedevtree_docs_basic-layer-breakdown.md.DG6Q9mdT.js => public_gamedevtree_docs_basic-layer-breakdown.md.Ykqytlzk.js} (98%) rename assets/{public_gamedevtree_docs_basic-layer-breakdown.md.DG6Q9mdT.lean.js => public_gamedevtree_docs_basic-layer-breakdown.md.Ykqytlzk.lean.js} (74%) rename assets/{public_gamedevtree_docs_buyables.md.BWSB6neR.js => public_gamedevtree_docs_buyables.md.C7aL_4eK.js} (98%) rename assets/{public_gamedevtree_docs_buyables.md.BWSB6neR.lean.js => public_gamedevtree_docs_buyables.md.C7aL_4eK.lean.js} (71%) rename assets/{public_gamedevtree_docs_challenges.md.DJU5H6Rk.js => public_gamedevtree_docs_challenges.md.cvYq35wY.js} (98%) rename assets/{public_gamedevtree_docs_challenges.md.DJU5H6Rk.lean.js => public_gamedevtree_docs_challenges.md.cvYq35wY.lean.js} (71%) rename assets/{public_gamedevtree_docs_clickables.md.DlF0g6fO.js => public_gamedevtree_docs_clickables.md.CwLsimiU.js} (97%) rename assets/{public_gamedevtree_docs_clickables.md.DlF0g6fO.lean.js => public_gamedevtree_docs_clickables.md.CwLsimiU.lean.js} (71%) rename assets/{public_gamedevtree_docs_custom-tab-layouts.md.oOQumDgW.js => public_gamedevtree_docs_custom-tab-layouts.md.DIYFlfWc.js} (98%) rename assets/{public_gamedevtree_docs_custom-tab-layouts.md.oOQumDgW.lean.js => public_gamedevtree_docs_custom-tab-layouts.md.DIYFlfWc.lean.js} (73%) create mode 100644 assets/public_gamedevtree_docs_getting-started.md.CyNrXhyL.js create mode 100644 assets/public_gamedevtree_docs_getting-started.md.CyNrXhyL.lean.js delete mode 100644 assets/public_gamedevtree_docs_getting-started.md.DZiPQZAv.js delete mode 100644 assets/public_gamedevtree_docs_getting-started.md.DZiPQZAv.lean.js rename assets/{public_gamedevtree_docs_infoboxes.md.BtrpL17l.js => public_gamedevtree_docs_infoboxes.md.B4DD8BvC.js} (96%) rename assets/{public_gamedevtree_docs_infoboxes.md.BtrpL17l.lean.js => public_gamedevtree_docs_infoboxes.md.B4DD8BvC.lean.js} (71%) rename assets/{public_gamedevtree_docs_layer-features.md.DAMp8TY6.js => public_gamedevtree_docs_layer-features.md.I54r8Buk.js} (99%) rename assets/{public_gamedevtree_docs_layer-features.md.DAMp8TY6.lean.js => public_gamedevtree_docs_layer-features.md.I54r8Buk.lean.js} (72%) rename assets/{public_gamedevtree_docs_main-mod-info.md.DGfpmFPw.js => public_gamedevtree_docs_main-mod-info.md.SBsEn9C7.js} (98%) rename assets/{public_gamedevtree_docs_main-mod-info.md.DGfpmFPw.lean.js => public_gamedevtree_docs_main-mod-info.md.SBsEn9C7.lean.js} (72%) rename assets/{public_gamedevtree_docs_milestones.md.C9u7zdbl.js => public_gamedevtree_docs_milestones.md.Idyk5tE3.js} (96%) rename assets/{public_gamedevtree_docs_milestones.md.C9u7zdbl.lean.js => public_gamedevtree_docs_milestones.md.Idyk5tE3.lean.js} (71%) rename assets/{public_gamedevtree_docs_subtabs-and-microtabs.md.BUkbEA-K.js => public_gamedevtree_docs_subtabs-and-microtabs.md.BhlicLTn.js} (97%) rename assets/{public_gamedevtree_docs_subtabs-and-microtabs.md.BUkbEA-K.lean.js => public_gamedevtree_docs_subtabs-and-microtabs.md.BhlicLTn.lean.js} (74%) rename assets/{public_gamedevtree_docs_updating-tmt.md.B1_CRXZy.js => public_gamedevtree_docs_updating-tmt.md.Clk0TMnI.js} (94%) rename assets/{public_gamedevtree_docs_updating-tmt.md.B1_CRXZy.lean.js => public_gamedevtree_docs_updating-tmt.md.Clk0TMnI.lean.js} (72%) rename assets/{public_gamedevtree_docs_upgrades.md.DuL26i8s.js => public_gamedevtree_docs_upgrades.md.BspSzPzA.js} (97%) rename assets/{public_gamedevtree_docs_upgrades.md.DuL26i8s.lean.js => public_gamedevtree_docs_upgrades.md.BspSzPzA.lean.js} (71%) rename assets/{public_kronos_Old Things_2.0-format-changes.md.DAyzd7AX.js => public_kronos_Old Things_2.0-format-changes.md.BM0FXptY.js} (90%) rename assets/{public_kronos_Old Things_2.0-format-changes.md.DAyzd7AX.lean.js => public_kronos_Old Things_2.0-format-changes.md.BM0FXptY.lean.js} (60%) rename assets/{public_kronos_README.md.DR8w07T9.js => public_kronos_README.md.zcQPLTsl.js} (85%) rename assets/{public_kronos_README.md.DR8w07T9.lean.js => public_kronos_README.md.zcQPLTsl.lean.js} (68%) rename assets/{public_kronos_changelog.md._RxA7rHJ.js => public_kronos_changelog.md.BB6U1JML.js} (99%) rename assets/{public_kronos_changelog.md._RxA7rHJ.lean.js => public_kronos_changelog.md.BB6U1JML.lean.js} (70%) rename assets/{public_kronos_docs_!general-info.md.Dr4UpP6q.js => public_kronos_docs_!general-info.md.jKiOCSlr.js} (98%) rename assets/{public_kronos_docs_!general-info.md.Dr4UpP6q.lean.js => public_kronos_docs_!general-info.md.jKiOCSlr.lean.js} (71%) rename assets/{public_kronos_docs_achievements.md.BQdSRHBr.js => public_kronos_docs_achievements.md.CWA5xmwG.js} (97%) rename assets/{public_kronos_docs_achievements.md.BQdSRHBr.lean.js => public_kronos_docs_achievements.md.CWA5xmwG.lean.js} (71%) rename assets/{public_kronos_docs_bars.md.DLIjHzcw.js => public_kronos_docs_bars.md.DU3nCdnU.js} (95%) rename assets/{public_kronos_docs_bars.md.DLIjHzcw.lean.js => public_kronos_docs_bars.md.DU3nCdnU.lean.js} (53%) rename assets/{public_kronos_docs_basic-layer-breakdown.md.DHJLymK0.js => public_kronos_docs_basic-layer-breakdown.md.BZhX1dEF.js} (98%) rename assets/{public_kronos_docs_basic-layer-breakdown.md.DHJLymK0.lean.js => public_kronos_docs_basic-layer-breakdown.md.BZhX1dEF.lean.js} (73%) rename assets/{public_kronos_docs_buyables.md.CZOwuPEI.js => public_kronos_docs_buyables.md.0zoux8fQ.js} (98%) rename assets/{public_kronos_docs_buyables.md.CZOwuPEI.lean.js => public_kronos_docs_buyables.md.0zoux8fQ.lean.js} (70%) rename assets/{public_kronos_docs_challenges.md.C8-cN764.js => public_kronos_docs_challenges.md.DvQ_P73q.js} (98%) rename assets/{public_kronos_docs_challenges.md.C8-cN764.lean.js => public_kronos_docs_challenges.md.DvQ_P73q.lean.js} (70%) rename assets/{public_kronos_docs_clickables.md.Dpdgv1J5.js => public_kronos_docs_clickables.md.C1ENZgWW.js} (97%) rename assets/{public_kronos_docs_clickables.md.Dpdgv1J5.lean.js => public_kronos_docs_clickables.md.C1ENZgWW.lean.js} (70%) rename assets/{public_kronos_docs_custom-tab-layouts.md.B34ACqtp.js => public_kronos_docs_custom-tab-layouts.md.D4DCXZo7.js} (98%) rename assets/{public_kronos_docs_custom-tab-layouts.md.B34ACqtp.lean.js => public_kronos_docs_custom-tab-layouts.md.D4DCXZo7.lean.js} (72%) create mode 100644 assets/public_kronos_docs_getting-started.md.N-haPVCK.js create mode 100644 assets/public_kronos_docs_getting-started.md.N-haPVCK.lean.js delete mode 100644 assets/public_kronos_docs_getting-started.md.qT4YQHFa.js delete mode 100644 assets/public_kronos_docs_getting-started.md.qT4YQHFa.lean.js rename assets/{public_kronos_docs_grids.md.dbyCMqJD.js => public_kronos_docs_grids.md.DGDenQsi.js} (98%) rename assets/{public_kronos_docs_grids.md.dbyCMqJD.lean.js => public_kronos_docs_grids.md.DGDenQsi.lean.js} (69%) rename assets/{public_kronos_docs_infoboxes.md.Bc-XXHMa.js => public_kronos_docs_infoboxes.md.BXXHzXvY.js} (96%) rename assets/{public_kronos_docs_infoboxes.md.Bc-XXHMa.lean.js => public_kronos_docs_infoboxes.md.BXXHzXvY.lean.js} (70%) rename assets/{public_kronos_docs_layer-features.md.DJjusT4t.js => public_kronos_docs_layer-features.md.C1uOzCZ-.js} (99%) rename assets/{public_kronos_docs_layer-features.md.DJjusT4t.lean.js => public_kronos_docs_layer-features.md.C1uOzCZ-.lean.js} (71%) rename assets/{public_kronos_docs_main-mod-info.md.DYKIKxsS.js => public_kronos_docs_main-mod-info.md.TWb3xDwG.js} (98%) rename assets/{public_kronos_docs_main-mod-info.md.DYKIKxsS.lean.js => public_kronos_docs_main-mod-info.md.TWb3xDwG.lean.js} (71%) rename assets/{public_kronos_docs_milestones.md.Ce7tGr8C.js => public_kronos_docs_milestones.md.BqiEbWx4.js} (97%) rename assets/{public_kronos_docs_milestones.md.Ce7tGr8C.lean.js => public_kronos_docs_milestones.md.BqiEbWx4.lean.js} (70%) rename assets/{public_kronos_docs_particles.md.CgdBAXsD.js => public_kronos_docs_particles.md.a4-BPTpH.js} (98%) rename assets/{public_kronos_docs_particles.md.CgdBAXsD.lean.js => public_kronos_docs_particles.md.a4-BPTpH.lean.js} (70%) rename assets/{public_kronos_docs_subtabs-and-microtabs.md.BSv4TpNt.js => public_kronos_docs_subtabs-and-microtabs.md.B3i34UtK.js} (98%) rename assets/{public_kronos_docs_subtabs-and-microtabs.md.BSv4TpNt.lean.js => public_kronos_docs_subtabs-and-microtabs.md.B3i34UtK.lean.js} (73%) rename assets/{public_kronos_docs_trees-and-tree-customization.md.C6vJ-bgs.js => public_kronos_docs_trees-and-tree-customization.md.bHBppIK5.js} (97%) rename assets/{public_kronos_docs_trees-and-tree-customization.md.C6vJ-bgs.lean.js => public_kronos_docs_trees-and-tree-customization.md.bHBppIK5.lean.js} (74%) create mode 100644 assets/public_kronos_docs_updating-tmt.md.BxVzngxM.js create mode 100644 assets/public_kronos_docs_updating-tmt.md.BxVzngxM.lean.js delete mode 100644 assets/public_kronos_docs_updating-tmt.md.yvj4vsSM.js delete mode 100644 assets/public_kronos_docs_updating-tmt.md.yvj4vsSM.lean.js rename assets/{public_kronos_docs_upgrades.md.BY_E6naZ.js => public_kronos_docs_upgrades.md.D1pH3BI1.js} (96%) rename assets/{public_kronos_docs_upgrades.md.BY_E6naZ.lean.js => public_kronos_docs_upgrades.md.D1pH3BI1.lean.js} (55%) rename assets/{public_lit_Old Things_2.0-format-changes.md.aA7GK9Ns.js => public_lit_Old Things_2.0-format-changes.md.BwaKJMKt.js} (90%) rename assets/{public_lit_Old Things_2.0-format-changes.md.aA7GK9Ns.lean.js => public_lit_Old Things_2.0-format-changes.md.BwaKJMKt.lean.js} (59%) create mode 100644 assets/public_lit_README.md.84-k6GVT.js create mode 100644 assets/public_lit_README.md.84-k6GVT.lean.js delete mode 100644 assets/public_lit_README.md.Dp_XDgLr.js delete mode 100644 assets/public_lit_README.md.Dp_XDgLr.lean.js rename assets/{public_lit_changelog.md.D7wPxHZ1.js => public_lit_changelog.md.BAnHXxRw.js} (99%) rename assets/{public_lit_changelog.md.D7wPxHZ1.lean.js => public_lit_changelog.md.BAnHXxRw.lean.js} (70%) rename assets/{public_lit_docs_!general-info.md.DwyPmy7N.js => public_lit_docs_!general-info.md.D2rjMfl1.js} (98%) rename assets/{public_lit_docs_!general-info.md.DwyPmy7N.lean.js => public_lit_docs_!general-info.md.D2rjMfl1.lean.js} (71%) rename assets/{public_lit_docs_achievements.md.DaBdzZ0g.js => public_lit_docs_achievements.md.D0gRoIWt.js} (97%) rename assets/{public_lit_docs_achievements.md.DaBdzZ0g.lean.js => public_lit_docs_achievements.md.D0gRoIWt.lean.js} (70%) rename assets/{public_lit_docs_bars.md.CnS5IMvm.js => public_lit_docs_bars.md.DFEFprv8.js} (97%) rename assets/{public_lit_docs_bars.md.CnS5IMvm.lean.js => public_lit_docs_bars.md.DFEFprv8.lean.js} (68%) rename assets/{public_lit_docs_basic-layer-breakdown.md.B_DwLl-5.js => public_lit_docs_basic-layer-breakdown.md.DKkhjhoJ.js} (97%) rename assets/{public_lit_docs_basic-layer-breakdown.md.B_DwLl-5.lean.js => public_lit_docs_basic-layer-breakdown.md.DKkhjhoJ.lean.js} (59%) rename assets/{public_lit_docs_buyables.md.Cr6AwZWn.js => public_lit_docs_buyables.md.DrqS8H2k.js} (98%) rename assets/{public_lit_docs_buyables.md.Cr6AwZWn.lean.js => public_lit_docs_buyables.md.DrqS8H2k.lean.js} (69%) rename assets/{public_lit_docs_challenges.md.BXbZcSAe.js => public_lit_docs_challenges.md.DtmSP6zf.js} (98%) rename assets/{public_lit_docs_challenges.md.BXbZcSAe.lean.js => public_lit_docs_challenges.md.DtmSP6zf.lean.js} (70%) rename assets/{public_lit_docs_clickables.md.DQD4wzqI.js => public_lit_docs_clickables.md.CoIWXGHw.js} (97%) rename assets/{public_lit_docs_clickables.md.DQD4wzqI.lean.js => public_lit_docs_clickables.md.CoIWXGHw.lean.js} (70%) rename assets/{public_lit_docs_custom-tab-layouts.md.CHYKKeeX.js => public_lit_docs_custom-tab-layouts.md.C-TlZHYA.js} (98%) rename assets/{public_lit_docs_custom-tab-layouts.md.CHYKKeeX.lean.js => public_lit_docs_custom-tab-layouts.md.C-TlZHYA.lean.js} (72%) delete mode 100644 assets/public_lit_docs_getting-started.md.BoU9JbJY.js delete mode 100644 assets/public_lit_docs_getting-started.md.BoU9JbJY.lean.js create mode 100644 assets/public_lit_docs_getting-started.md.BxRLZ8_n.js create mode 100644 assets/public_lit_docs_getting-started.md.BxRLZ8_n.lean.js rename assets/{public_lit_docs_infoboxes.md.71lto7Te.js => public_lit_docs_infoboxes.md.C0nPRfky.js} (96%) rename assets/{public_lit_docs_infoboxes.md.71lto7Te.lean.js => public_lit_docs_infoboxes.md.C0nPRfky.lean.js} (69%) rename assets/{public_lit_docs_layer-features.md.FrysJ_Sk.js => public_lit_docs_layer-features.md.DF81fjyw.js} (99%) rename assets/{public_lit_docs_layer-features.md.FrysJ_Sk.lean.js => public_lit_docs_layer-features.md.DF81fjyw.lean.js} (71%) rename assets/{public_lit_docs_main-mod-info.md.B2Wd3G2L.js => public_lit_docs_main-mod-info.md.CcRWcMdS.js} (98%) rename assets/{public_lit_docs_main-mod-info.md.B2Wd3G2L.lean.js => public_lit_docs_main-mod-info.md.CcRWcMdS.lean.js} (70%) rename assets/{public_lit_docs_milestones.md.CKbDaByO.js => public_lit_docs_milestones.md.CGwN80sv.js} (97%) rename assets/{public_lit_docs_milestones.md.CKbDaByO.lean.js => public_lit_docs_milestones.md.CGwN80sv.lean.js} (70%) rename assets/{public_lit_docs_subtabs-and-microtabs.md.DkrjReOt.js => public_lit_docs_subtabs-and-microtabs.md.BQEflp-r.js} (97%) rename assets/{public_lit_docs_subtabs-and-microtabs.md.DkrjReOt.lean.js => public_lit_docs_subtabs-and-microtabs.md.BQEflp-r.lean.js} (59%) rename assets/{public_lit_docs_trees-and-tree-customization.md.D-rEc1nB.js => public_lit_docs_trees-and-tree-customization.md.C8iASWgy.js} (97%) rename assets/{public_lit_docs_trees-and-tree-customization.md.D-rEc1nB.lean.js => public_lit_docs_trees-and-tree-customization.md.C8iASWgy.lean.js} (74%) create mode 100644 assets/public_lit_docs_updating-tmt.md.C3AjdOjF.js create mode 100644 assets/public_lit_docs_updating-tmt.md.C3AjdOjF.lean.js delete mode 100644 assets/public_lit_docs_updating-tmt.md.CjXsxPz8.js delete mode 100644 assets/public_lit_docs_updating-tmt.md.CjXsxPz8.lean.js rename assets/{public_lit_docs_upgrades.md.DCCBwvKJ.js => public_lit_docs_upgrades.md.D1Ns9VTR.js} (98%) rename assets/{public_lit_docs_upgrades.md.DCCBwvKJ.lean.js => public_lit_docs_upgrades.md.D1Ns9VTR.lean.js} (69%) rename assets/{style.BPlHIFta.css => style.ByNYS6_U.css} (96%) diff --git a/404.html b/404.html index 84bba4f3..332ffaf1 100644 --- a/404.html +++ b/404.html @@ -6,9 +6,9 @@ 404 | The Paper Pilot - + - + @@ -32,7 +32,7 @@
- + \ No newline at end of file diff --git a/about/index.html b/about/index.html index 646d7e1f..03b8a141 100644 --- a/about/index.html +++ b/about/index.html @@ -6,13 +6,13 @@ About Me | The Paper Pilot - + - + - - - + + + @@ -34,8 +34,8 @@ -
Skip to content

About Me

I'm a software developer who likes making games and tools! I have a variety of interests, from game development to the fediverse to digital gardens.

I live in Dallas, Texas, USA with my wife and baby son. I work at Topaz Labs LLC as a Product Engineer. I develop their flagship product Topaz Photo AI.

Reach out to me:

These are old accounts I don't use anymore, but they are me:

- +
Skip to content

About Me

I'm a software developer who likes making games and tools! I have a variety of interests, from game development to the fediverse to digital gardens.

I live in Dallas, Texas, USA with my wife and baby son. I work at Topaz Labs LLC as a Product Engineer. I develop their flagship product Topaz Photo AI.

Reach out to me:

These are old accounts I don't use anymore, but they are me:

+ \ No newline at end of file diff --git a/assets/about_index.md.p-omr8fP.js b/assets/about_index.md.DNEsxkhw.js similarity index 90% rename from assets/about_index.md.p-omr8fP.js rename to assets/about_index.md.DNEsxkhw.js index 6018c9f2..c22fb0ec 100644 --- a/assets/about_index.md.p-omr8fP.js +++ b/assets/about_index.md.DNEsxkhw.js @@ -1 +1 @@ -import{_ as e,c as a,o as t,ag as l,af as s}from"./chunks/framework.VBE0TPts.js";const _=JSON.parse('{"title":"About Me","description":"","frontmatter":{"title":"About Me","prev":false,"next":false},"headers":[],"relativePath":"about/index.md","filePath":"about/index.md"}'),r={name:"about/index.md"},i=l('

About Me

I'm a software developer who likes making games and tools! I have a variety of interests, from game development to the fediverse to digital gardens.

I live in Dallas, Texas, USA with my wife and baby son. I work at Topaz Labs LLC as a Product Engineer. I develop their flagship product Topaz Photo AI.

Reach out to me:

These are old accounts I don't use anymore, but they are me:

',2),o=[i];function p(n,c,h,m,d,u){return t(),a("div",null,o)}const g=e(r,[["render",p]]);export{_ as __pageData,g as default}; +import{_ as e,q as a,p as t,ag as l,af as s}from"./chunks/framework.DvHfxfnp.js";const _=JSON.parse('{"title":"About Me","description":"","frontmatter":{"title":"About Me","prev":false,"next":false},"headers":[],"relativePath":"about/index.md","filePath":"about/index.md"}'),r={name:"about/index.md"},i=l('

About Me

I'm a software developer who likes making games and tools! I have a variety of interests, from game development to the fediverse to digital gardens.

I live in Dallas, Texas, USA with my wife and baby son. I work at Topaz Labs LLC as a Product Engineer. I develop their flagship product Topaz Photo AI.

Reach out to me:

These are old accounts I don't use anymore, but they are me:

',2),p=[i];function o(n,c,h,m,d,u){return t(),a("div",null,p)}const g=e(r,[["render",o]]);export{_ as __pageData,g as default}; diff --git a/assets/about_index.md.DNEsxkhw.lean.js b/assets/about_index.md.DNEsxkhw.lean.js new file mode 100644 index 00000000..97be2fab --- /dev/null +++ b/assets/about_index.md.DNEsxkhw.lean.js @@ -0,0 +1 @@ +import{_ as e,q as a,p as t,ag as l,af as s}from"./chunks/framework.DvHfxfnp.js";const _=JSON.parse('{"title":"About Me","description":"","frontmatter":{"title":"About Me","prev":false,"next":false},"headers":[],"relativePath":"about/index.md","filePath":"about/index.md"}'),r={name:"about/index.md"},i=l("",2),p=[i];function o(n,c,h,m,d,u){return t(),a("div",null,p)}const g=e(r,[["render",o]]);export{_ as __pageData,g as default}; diff --git a/assets/about_index.md.p-omr8fP.lean.js b/assets/about_index.md.p-omr8fP.lean.js deleted file mode 100644 index 7bb3be41..00000000 --- a/assets/about_index.md.p-omr8fP.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as e,c as a,o as t,ag as l,af as s}from"./chunks/framework.VBE0TPts.js";const _=JSON.parse('{"title":"About Me","description":"","frontmatter":{"title":"About Me","prev":false,"next":false},"headers":[],"relativePath":"about/index.md","filePath":"about/index.md"}'),r={name:"about/index.md"},i=l("",2),o=[i];function p(n,c,h,m,d,u){return t(),a("div",null,o)}const g=e(r,[["render",p]]);export{_ as __pageData,g as default}; diff --git a/assets/app.C2YOVlNw.js b/assets/app.C2YOVlNw.js new file mode 100644 index 00000000..b7480543 --- /dev/null +++ b/assets/app.C2YOVlNw.js @@ -0,0 +1 @@ +import{a6 as o,aB as p,aC as u,aD as l,aE as c,aF as f,aG as d,aH as m,aI as h,aJ as A,aK as g,k as P,M as v,o as C,f as w,aL as y,aM as E,aN as R,A as b}from"./chunks/framework.DvHfxfnp.js";import{a as S}from"./chunks/theme.Bb5kJd_v.js";function i(e){if(e.extends){const a=i(e.extends);return{...a,...e,async enhanceApp(t){a.enhanceApp&&await a.enhanceApp(t),e.enhanceApp&&await e.enhanceApp(t)}}}return e}const s=i(S),T=P({name:"VitePressApp",setup(){const{site:e,lang:a,dir:t}=v();return C(()=>{w(()=>{document.documentElement.lang=a.value,document.documentElement.dir=t.value})}),e.value.router.prefetchLinks&&y(),E(),R(),s.setup&&s.setup(),()=>b(s.Layout)}});async function _(){globalThis.__VITEPRESS__=!0;const e=F(),a=D();a.provide(u,e);const t=l(e.route);return a.provide(c,t),a.component("Content",f),a.component("ClientOnly",d),Object.defineProperties(a.config.globalProperties,{$frontmatter:{get(){return t.frontmatter.value}},$params:{get(){return t.page.value.params}}}),s.enhanceApp&&await s.enhanceApp({app:a,router:e,siteData:m}),{app:a,router:e,data:t}}function D(){return h(T)}function F(){let e=o,a;return A(t=>{let n=g(t),r=null;return n&&(e&&(a=n),(e||a===n)&&(n=n.replace(/\.js$/,".lean.js")),r=import(n)),o&&(e=!1),r},s.NotFound)}o&&_().then(({app:e,router:a,data:t})=>{a.go().then(()=>{p(a.route,t.site),e.mount("#app")})});export{_ as createApp}; diff --git a/assets/app.JJhOCmj_.js b/assets/app.JJhOCmj_.js deleted file mode 100644 index 5bf4db8c..00000000 --- a/assets/app.JJhOCmj_.js +++ /dev/null @@ -1 +0,0 @@ -import{U as o,aB as p,aC as u,aD as l,aE as c,aF as f,aG as d,aH as m,aI as h,aJ as g,aK as A,d as P,u as v,y,x as C,aL as w,aM as R,aN as E,ac as b}from"./chunks/framework.VBE0TPts.js";import{R as S}from"./chunks/theme.Bc6XxFSB.js";function i(e){if(e.extends){const a=i(e.extends);return{...a,...e,async enhanceApp(t){a.enhanceApp&&await a.enhanceApp(t),e.enhanceApp&&await e.enhanceApp(t)}}}return e}const s=i(S),T=P({name:"VitePressApp",setup(){const{site:e,lang:a,dir:t}=v();return y(()=>{C(()=>{document.documentElement.lang=a.value,document.documentElement.dir=t.value})}),e.value.router.prefetchLinks&&w(),R(),E(),s.setup&&s.setup(),()=>b(s.Layout)}});async function _(){globalThis.__VITEPRESS__=!0;const e=x(),a=D();a.provide(u,e);const t=l(e.route);return a.provide(c,t),a.component("Content",f),a.component("ClientOnly",d),Object.defineProperties(a.config.globalProperties,{$frontmatter:{get(){return t.frontmatter.value}},$params:{get(){return t.page.value.params}}}),s.enhanceApp&&await s.enhanceApp({app:a,router:e,siteData:m}),{app:a,router:e,data:t}}function D(){return h(T)}function x(){let e=o,a;return g(t=>{let n=A(t),r=null;return n&&(e&&(a=n),(e||a===n)&&(n=n.replace(/\.js$/,".lean.js")),r=import(n)),o&&(e=!1),r},s.NotFound)}o&&_().then(({app:e,router:a,data:t})=>{a.go().then(()=>{p(a.route,t.site),e.mount("#app")})});export{_ as createApp}; diff --git a/assets/changelog_index.md.BVGEmP78.js b/assets/changelog_index.md.DFC25qVi.js similarity index 99% rename from assets/changelog_index.md.BVGEmP78.js rename to assets/changelog_index.md.DFC25qVi.js index 209bec82..38d83b75 100644 --- a/assets/changelog_index.md.BVGEmP78.js +++ b/assets/changelog_index.md.DFC25qVi.js @@ -1 +1 @@ -import{_ as t,c as e,o as a,ag as s}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"Site Changelog","description":"","frontmatter":{"title":"Site Changelog","prev":false,"next":false},"headers":[],"relativePath":"changelog/index.md","filePath":"changelog/index.md"}'),n={name:"changelog/index.md"},o=s('

Site Changelog

This feed starts when I formatted the site to be a Digital Garden. If you'd like to look further into this site's history, check here!

58 files changed, 79 insertions(+), 79 deletions(-)

16 files changed, 24 insertions(+), 8 deletions(-)

60 files changed, 513 insertions(+), 93 deletions(-)

Pushed on
PageChanges
activitypub9 +++++++-
advent-incremental9 +++++++-
artificial-intelligence9 +++++++-
atproto9 +++++++-
babble-buds9 +++++++-
capture-the-citadel11 +++++++--
chat-glue9 +++++++-
chronological9 +++++++-
cinny9 +++++++-
command-palettes9 +++++++-
commune9 +++++++-
davey-wreden9 +++++++-
decentralized9 +++++++-
dice-armor27 ++++++++++++++--------
digital-gardens9 +++++++-
federated-identity9 +++++++-
fedi-v29 +++++++-
fediverse9 +++++++-
forgejo9 +++++++-
freeform-vs-chronological-dichotomy9 +++++++-
freeform9 +++++++-
game-dev-tree9 +++++++-
garden-rss9 +++++++-
.../appeal-to-developers13 ++++++++---
guide-to-incrementals/appeal-to-players13 ++++++++---
guide-to-incrementals/defining-the-genre13 ++++++++---
guide-to-incrementals9 +++++++-
.../navigating-criticism13 ++++++++---
guide-to-incrementals/what-is-content13 ++++++++---
incremental-social9 +++++++-
ivy-road9 +++++++-
kronos9 +++++++-
life-is-strange13 ++++++++---
logseq9 +++++++-
matrix9 +++++++-
mbin9 +++++++-
mtx9 +++++++-
my-personal-website9 +++++++-
my-projects9 +++++++-
nostr9 +++++++-
open-source9 +++++++-
opti-speech17 ++++++++++----
planar-pioneers9 +++++++-
pre-order-bonuses9 +++++++-
premium-currency9 +++++++-
profectus9 +++++++-
social-media9 +++++++-
synapse9 +++++++-
the-beginner-s-guide9 +++++++-
the-cozy-web9 +++++++-
the-indieweb/amplification13 ++++++++---
the-indieweb/signature-blocks13 ++++++++---
the-small-web9 +++++++-
this-knowledge-hub9 +++++++-
v-ecs15 ++++++++----
video-game-monetization9 +++++++-
vitepress9 +++++++-
wanderstop9 +++++++-
webrings9 +++++++-
weird9 +++++++-

20 files changed, 274 insertions(+), 16 deletions(-)

Pushed on
PageChanges
artificial-intelligence28 ++++++++++++++++
command-palettes25 ++++++++++++++
fedi-v215 +++++----
fediverse2 +-
guide-to-incrementals2 ++
incremental-social2 +-
life-is-strange60 ++++++++++++++++++++++++++++++++++
logseq2 +-
mtx13 ++++++++
my-personal-website2 +-
my-projects2 ++
pre-order-bonuses28 ++++++++++++++++
premium-currency19 +++++++++++
social-media2 +-
the-beginner-s-guide2 +-
the-indieweb/amplification14 ++++++++
the-indieweb/signature-blocks10 ++++++
the-small-web8 +++--
video-game-monetization43 ++++++++++++++++++++++++
weird11 +++++--

47 files changed, 124 insertions(+), 13 deletions(-)

47 files changed, 1226 insertions(+)

',1),r=[o];function l(p,d,c,i,y,f){return a(),e("div",null,r)}const w=t(n,[["render",l]]);export{m as __pageData,w as default}; +import{_ as t,q as e,p as a,ag as s}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"Site Changelog","description":"","frontmatter":{"title":"Site Changelog","prev":false,"next":false},"headers":[],"relativePath":"changelog/index.md","filePath":"changelog/index.md"}'),n={name:"changelog/index.md"},o=s('

Site Changelog

This feed starts when I formatted the site to be a Digital Garden. If you'd like to look further into this site's history, check here!

58 files changed, 79 insertions(+), 79 deletions(-)

16 files changed, 24 insertions(+), 8 deletions(-)

60 files changed, 513 insertions(+), 93 deletions(-)

Pushed on
PageChanges
activitypub9 +++++++-
advent-incremental9 +++++++-
artificial-intelligence9 +++++++-
atproto9 +++++++-
babble-buds9 +++++++-
capture-the-citadel11 +++++++--
chat-glue9 +++++++-
chronological9 +++++++-
cinny9 +++++++-
command-palettes9 +++++++-
commune9 +++++++-
davey-wreden9 +++++++-
decentralized9 +++++++-
dice-armor27 ++++++++++++++--------
digital-gardens9 +++++++-
federated-identity9 +++++++-
fedi-v29 +++++++-
fediverse9 +++++++-
forgejo9 +++++++-
freeform-vs-chronological-dichotomy9 +++++++-
freeform9 +++++++-
game-dev-tree9 +++++++-
garden-rss9 +++++++-
.../appeal-to-developers13 ++++++++---
guide-to-incrementals/appeal-to-players13 ++++++++---
guide-to-incrementals/defining-the-genre13 ++++++++---
guide-to-incrementals9 +++++++-
.../navigating-criticism13 ++++++++---
guide-to-incrementals/what-is-content13 ++++++++---
incremental-social9 +++++++-
ivy-road9 +++++++-
kronos9 +++++++-
life-is-strange13 ++++++++---
logseq9 +++++++-
matrix9 +++++++-
mbin9 +++++++-
mtx9 +++++++-
my-personal-website9 +++++++-
my-projects9 +++++++-
nostr9 +++++++-
open-source9 +++++++-
opti-speech17 ++++++++++----
planar-pioneers9 +++++++-
pre-order-bonuses9 +++++++-
premium-currency9 +++++++-
profectus9 +++++++-
social-media9 +++++++-
synapse9 +++++++-
the-beginner-s-guide9 +++++++-
the-cozy-web9 +++++++-
the-indieweb/amplification13 ++++++++---
the-indieweb/signature-blocks13 ++++++++---
the-small-web9 +++++++-
this-knowledge-hub9 +++++++-
v-ecs15 ++++++++----
video-game-monetization9 +++++++-
vitepress9 +++++++-
wanderstop9 +++++++-
webrings9 +++++++-
weird9 +++++++-

20 files changed, 274 insertions(+), 16 deletions(-)

Pushed on
PageChanges
artificial-intelligence28 ++++++++++++++++
command-palettes25 ++++++++++++++
fedi-v215 +++++----
fediverse2 +-
guide-to-incrementals2 ++
incremental-social2 +-
life-is-strange60 ++++++++++++++++++++++++++++++++++
logseq2 +-
mtx13 ++++++++
my-personal-website2 +-
my-projects2 ++
pre-order-bonuses28 ++++++++++++++++
premium-currency19 +++++++++++
social-media2 +-
the-beginner-s-guide2 +-
the-indieweb/amplification14 ++++++++
the-indieweb/signature-blocks10 ++++++
the-small-web8 +++--
video-game-monetization43 ++++++++++++++++++++++++
weird11 +++++--

47 files changed, 124 insertions(+), 13 deletions(-)

47 files changed, 1226 insertions(+)

',1),r=[o];function l(p,d,c,i,y,f){return a(),e("div",null,r)}const w=t(n,[["render",l]]);export{m as __pageData,w as default}; diff --git a/assets/changelog_index.md.BVGEmP78.lean.js b/assets/changelog_index.md.DFC25qVi.lean.js similarity index 71% rename from assets/changelog_index.md.BVGEmP78.lean.js rename to assets/changelog_index.md.DFC25qVi.lean.js index 4127d2c9..a356b33c 100644 --- a/assets/changelog_index.md.BVGEmP78.lean.js +++ b/assets/changelog_index.md.DFC25qVi.lean.js @@ -1 +1 @@ -import{_ as t,c as e,o as a,ag as s}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"Site Changelog","description":"","frontmatter":{"title":"Site Changelog","prev":false,"next":false},"headers":[],"relativePath":"changelog/index.md","filePath":"changelog/index.md"}'),n={name:"changelog/index.md"},o=s("",1),r=[o];function l(p,d,c,i,y,f){return a(),e("div",null,r)}const w=t(n,[["render",l]]);export{m as __pageData,w as default}; +import{_ as t,q as e,p as a,ag as s}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"Site Changelog","description":"","frontmatter":{"title":"Site Changelog","prev":false,"next":false},"headers":[],"relativePath":"changelog/index.md","filePath":"changelog/index.md"}'),n={name:"changelog/index.md"},o=s("",1),r=[o];function l(p,d,c,i,y,f){return a(),e("div",null,r)}const w=t(n,[["render",l]]);export{m as __pageData,w as default}; diff --git a/assets/chunks/VPLocalSearchBox.DMasLpNF.js b/assets/chunks/VPLocalSearchBox.hF612Jrh.js similarity index 95% rename from assets/chunks/VPLocalSearchBox.DMasLpNF.js rename to assets/chunks/VPLocalSearchBox.hF612Jrh.js index 3329772e..e2c45f33 100644 --- a/assets/chunks/VPLocalSearchBox.DMasLpNF.js +++ b/assets/chunks/VPLocalSearchBox.hF612Jrh.js @@ -1,7 +1,7 @@ -var Nt=Object.defineProperty;var Ct=(o,e,t)=>e in o?Nt(o,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[e]=t;var ke=(o,e,t)=>(Ct(o,typeof e!="symbol"?e+"":e,t),t);import{X as It,s as ie,v as Be,aO as Dt,aP as kt,d as Ot,G as we,aQ as et,h as xe,aR as Rt,aS as _t,x as Mt,aT as Lt,y as Oe,R as he,Q as Fe,aU as Pt,a3 as zt,Y as Vt,U as Bt,aV as $t,o as X,b as Wt,j as k,a1 as Kt,k as G,aW as Ut,aX as Jt,a4 as jt,c as te,n as tt,e as Ee,E as rt,F as at,a as de,t as ve,aY as Gt,p as Qt,l as Ht,aZ as nt,a_ as qt,aE as Yt,aK as Zt,a$ as Xt,_ as er}from"./framework.VBE0TPts.js";import{u as tr,c as rr}from"./theme.Bc6XxFSB.js";const ar={root:()=>It(()=>import("./@localSearchIndexroot.BqI_0TuC.js"),[])};/*! +var Nt=Object.defineProperty;var Ct=(o,e,t)=>e in o?Nt(o,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[e]=t;var ke=(o,e,t)=>(Ct(o,typeof e!="symbol"?e+"":e,t),t);import{a8 as It,r as ie,w as Be,aO as Dt,aP as kt,k as Ot,s as we,aQ as et,e as xe,aR as Rt,aS as _t,f as Mt,aT as Lt,o as Oe,n as he,a4 as Fe,aU as Pt,ad as zt,a9 as Vt,a6 as Bt,aV as $t,p as X,D as Wt,Q as k,ac as Kt,u as G,aW as Jt,aX as Ut,i as jt,q as te,v as tt,H as Ee,G as rt,F as at,K as de,L as ve,aY as Gt,R as Qt,S as Ht,aZ as nt,a_ as qt,aE as Yt,aK as Zt,a$ as Xt,_ as er}from"./framework.DvHfxfnp.js";import{u as tr,c as rr}from"./theme.Bb5kJd_v.js";const ar={root:()=>It(()=>import("./@localSearchIndexroot.BqI_0TuC.js"),[])};/*! * tabbable 6.2.0 * @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE */var pt=["input:not([inert])","select:not([inert])","textarea:not([inert])","a[href]:not([inert])","button:not([inert])","[tabindex]:not(slot):not([inert])","audio[controls]:not([inert])","video[controls]:not([inert])",'[contenteditable]:not([contenteditable="false"]):not([inert])',"details>summary:first-of-type:not([inert])","details:not([inert])"],Te=pt.join(","),yt=typeof Element>"u",se=yt?function(){}:Element.prototype.matches||Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector,Ne=!yt&&Element.prototype.getRootNode?function(o){var e;return o==null||(e=o.getRootNode)===null||e===void 0?void 0:e.call(o)}:function(o){return o==null?void 0:o.ownerDocument},Ce=function o(e,t){var r;t===void 0&&(t=!0);var n=e==null||(r=e.getAttribute)===null||r===void 0?void 0:r.call(e,"inert"),a=n===""||n==="true",i=a||t&&e&&o(e.parentNode);return i},nr=function(e){var t,r=e==null||(t=e.getAttribute)===null||t===void 0?void 0:t.call(e,"contenteditable");return r===""||r==="true"},mt=function(e,t,r){if(Ce(e))return[];var n=Array.prototype.slice.apply(e.querySelectorAll(Te));return t&&se.call(e,Te)&&n.unshift(e),n=n.filter(r),n},gt=function o(e,t,r){for(var n=[],a=Array.from(e);a.length;){var i=a.shift();if(!Ce(i,!1))if(i.tagName==="SLOT"){var s=i.assignedElements(),u=s.length?s:i.children,l=o(u,!0,r);r.flatten?n.push.apply(n,l):n.push({scopeParent:i,candidates:l})}else{var d=se.call(i,Te);d&&r.filter(i)&&(t||!e.includes(i))&&n.push(i);var h=i.shadowRoot||typeof r.getShadowRoot=="function"&&r.getShadowRoot(i),v=!Ce(h,!1)&&(!r.shadowRootFilter||r.shadowRootFilter(i));if(h&&v){var m=o(h===!0?i.children:h.children,!0,r);r.flatten?n.push.apply(n,m):n.push({scopeParent:i,candidates:m})}else a.unshift.apply(a,i.children)}}return n},bt=function(e){return!isNaN(parseInt(e.getAttribute("tabindex"),10))},oe=function(e){if(!e)throw new Error("No node provided");return e.tabIndex<0&&(/^(AUDIO|VIDEO|DETAILS)$/.test(e.tagName)||nr(e))&&!bt(e)?0:e.tabIndex},ir=function(e,t){var r=oe(e);return r<0&&t&&!bt(e)?0:r},or=function(e,t){return e.tabIndex===t.tabIndex?e.documentOrder-t.documentOrder:e.tabIndex-t.tabIndex},wt=function(e){return e.tagName==="INPUT"},sr=function(e){return wt(e)&&e.type==="hidden"},ur=function(e){var t=e.tagName==="DETAILS"&&Array.prototype.slice.apply(e.children).some(function(r){return r.tagName==="SUMMARY"});return t},lr=function(e,t){for(var r=0;rsummary:first-of-type"),i=a?e.parentElement:e;if(se.call(i,"details:not([open]) *"))return!0;if(!r||r==="full"||r==="legacy-full"){if(typeof n=="function"){for(var s=e;e;){var u=e.parentElement,l=Ne(e);if(u&&!u.shadowRoot&&n(u)===!0)return it(e);e.assignedSlot?e=e.assignedSlot:!u&&l!==e.ownerDocument?e=l.host:e=u}e=s}if(dr(e))return!e.getClientRects().length;if(r!=="legacy-full")return!0}else if(r==="non-zero-area")return it(e);return!1},pr=function(e){if(/^(INPUT|BUTTON|SELECT|TEXTAREA)$/.test(e.tagName))for(var t=e.parentElement;t;){if(t.tagName==="FIELDSET"&&t.disabled){for(var r=0;r=0)},mr=function o(e){var t=[],r=[];return e.forEach(function(n,a){var i=!!n.scopeParent,s=i?n.scopeParent:n,u=ir(s,i),l=i?o(n.candidates):s;u===0?i?t.push.apply(t,l):t.push(s):r.push({documentOrder:a,tabIndex:u,item:n,isScope:i,content:l})}),r.sort(or).reduce(function(n,a){return a.isScope?n.push.apply(n,a.content):n.push(a.content),n},[]).concat(t)},gr=function(e,t){t=t||{};var r;return t.getShadowRoot?r=gt([e],t.includeContainer,{filter:$e.bind(null,t),flatten:!1,getShadowRoot:t.getShadowRoot,shadowRootFilter:yr}):r=mt(e,t.includeContainer,$e.bind(null,t)),mr(r)},br=function(e,t){t=t||{};var r;return t.getShadowRoot?r=gt([e],t.includeContainer,{filter:Ie.bind(null,t),flatten:!0,getShadowRoot:t.getShadowRoot}):r=mt(e,t.includeContainer,Ie.bind(null,t)),r},ue=function(e,t){if(t=t||{},!e)throw new Error("No node provided");return se.call(e,Te)===!1?!1:$e(t,e)},wr=pt.concat("iframe").join(","),Re=function(e,t){if(t=t||{},!e)throw new Error("No node provided");return se.call(e,wr)===!1?!1:Ie(t,e)};/*! * focus-trap 7.5.4 * @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE -*/function ot(o,e){var t=Object.keys(o);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(o);e&&(r=r.filter(function(n){return Object.getOwnPropertyDescriptor(o,n).enumerable})),t.push.apply(t,r)}return t}function st(o){for(var e=1;e0){var r=e[e.length-1];r!==t&&r.pause()}var n=e.indexOf(t);n===-1||e.splice(n,1),e.push(t)},deactivateTrap:function(e,t){var r=e.indexOf(t);r!==-1&&e.splice(r,1),e.length>0&&e[e.length-1].unpause()}},Sr=function(e){return e.tagName&&e.tagName.toLowerCase()==="input"&&typeof e.select=="function"},Ar=function(e){return(e==null?void 0:e.key)==="Escape"||(e==null?void 0:e.key)==="Esc"||(e==null?void 0:e.keyCode)===27},me=function(e){return(e==null?void 0:e.key)==="Tab"||(e==null?void 0:e.keyCode)===9},Tr=function(e){return me(e)&&!e.shiftKey},Nr=function(e){return me(e)&&e.shiftKey},lt=function(e){return setTimeout(e,0)},ct=function(e,t){var r=-1;return e.every(function(n,a){return t(n)?(r=a,!1):!0}),r},pe=function(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),n=1;n1?p-1:0),N=1;N=0)f=r.activeElement;else{var c=i.tabbableGroups[0],p=c&&c.firstTabbableNode;f=p||d("fallbackFocus")}if(!f)throw new Error("Your focus-trap needs to have at least one focusable element");return f},v=function(){if(i.containerGroups=i.containers.map(function(f){var c=gr(f,a.tabbableOptions),p=br(f,a.tabbableOptions),C=c.length>0?c[0]:void 0,N=c.length>0?c[c.length-1]:void 0,M=p.find(function(w){return ue(w)}),z=p.slice().reverse().find(function(w){return ue(w)}),y=!!c.find(function(w){return oe(w)>0});return{container:f,tabbableNodes:c,focusableNodes:p,posTabIndexesFound:y,firstTabbableNode:C,lastTabbableNode:N,firstDomTabbableNode:M,lastDomTabbableNode:z,nextTabbableNode:function(V){var J=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0,K=c.indexOf(V);return K<0?J?p.slice(p.indexOf(V)+1).find(function(U){return ue(U)}):p.slice(0,p.indexOf(V)).reverse().find(function(U){return ue(U)}):c[K+(J?1:-1)]}}}),i.tabbableGroups=i.containerGroups.filter(function(f){return f.tabbableNodes.length>0}),i.tabbableGroups.length<=0&&!d("fallbackFocus"))throw new Error("Your focus-trap must have at least one container with at least one tabbable node in it at all times");if(i.containerGroups.find(function(f){return f.posTabIndexesFound})&&i.containerGroups.length>1)throw new Error("At least one node with a positive tabindex was found in one of your focus-trap's multiple containers. Positive tabindexes are only supported in single-container focus-traps.")},m=function F(f){var c=f.activeElement;if(c)return c.shadowRoot&&c.shadowRoot.activeElement!==null?F(c.shadowRoot):c},g=function F(f){if(f!==!1&&f!==m(document)){if(!f||!f.focus){F(h());return}f.focus({preventScroll:!!a.preventScroll}),i.mostRecentlyFocusedNode=f,Sr(f)&&f.select()}},b=function(f){var c=d("setReturnFocus",f);return c||(c===!1?!1:f)},x=function(f){var c=f.target,p=f.event,C=f.isBackward,N=C===void 0?!1:C;c=c||Se(p),v();var M=null;if(i.tabbableGroups.length>0){var z=l(c,p),y=z>=0?i.containerGroups[z]:void 0;if(z<0)N?M=i.tabbableGroups[i.tabbableGroups.length-1].lastTabbableNode:M=i.tabbableGroups[0].firstTabbableNode;else if(N){var w=ct(i.tabbableGroups,function(j){var H=j.firstTabbableNode;return c===H});if(w<0&&(y.container===c||Re(c,a.tabbableOptions)&&!ue(c,a.tabbableOptions)&&!y.nextTabbableNode(c,!1))&&(w=z),w>=0){var V=w===0?i.tabbableGroups.length-1:w-1,J=i.tabbableGroups[V];M=oe(c)>=0?J.lastTabbableNode:J.lastDomTabbableNode}else me(p)||(M=y.nextTabbableNode(c,!1))}else{var K=ct(i.tabbableGroups,function(j){var H=j.lastTabbableNode;return c===H});if(K<0&&(y.container===c||Re(c,a.tabbableOptions)&&!ue(c,a.tabbableOptions)&&!y.nextTabbableNode(c))&&(K=z),K>=0){var U=K===i.tabbableGroups.length-1?0:K+1,B=i.tabbableGroups[U];M=oe(c)>=0?B.firstTabbableNode:B.firstDomTabbableNode}else me(p)||(M=y.nextTabbableNode(c))}}else M=d("fallbackFocus");return M},S=function(f){var c=Se(f);if(!(l(c,f)>=0)){if(pe(a.clickOutsideDeactivates,f)){s.deactivate({returnFocus:a.returnFocusOnDeactivate});return}pe(a.allowOutsideClick,f)||f.preventDefault()}},T=function(f){var c=Se(f),p=l(c,f)>=0;if(p||c instanceof Document)p&&(i.mostRecentlyFocusedNode=c);else{f.stopImmediatePropagation();var C,N=!0;if(i.mostRecentlyFocusedNode)if(oe(i.mostRecentlyFocusedNode)>0){var M=l(i.mostRecentlyFocusedNode),z=i.containerGroups[M].tabbableNodes;if(z.length>0){var y=z.findIndex(function(w){return w===i.mostRecentlyFocusedNode});y>=0&&(a.isKeyForward(i.recentNavEvent)?y+1=0&&(C=z[y-1],N=!1))}}else i.containerGroups.some(function(w){return w.tabbableNodes.some(function(V){return oe(V)>0})})||(N=!1);else N=!1;N&&(C=x({target:i.mostRecentlyFocusedNode,isBackward:a.isKeyBackward(i.recentNavEvent)})),g(C||i.mostRecentlyFocusedNode||h())}i.recentNavEvent=void 0},A=function(f){var c=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1;i.recentNavEvent=f;var p=x({event:f,isBackward:c});p&&(me(f)&&f.preventDefault(),g(p))},_=function(f){if(Ar(f)&&pe(a.escapeDeactivates,f)!==!1){f.preventDefault(),s.deactivate();return}(a.isKeyForward(f)||a.isKeyBackward(f))&&A(f,a.isKeyBackward(f))},L=function(f){var c=Se(f);l(c,f)>=0||pe(a.clickOutsideDeactivates,f)||pe(a.allowOutsideClick,f)||(f.preventDefault(),f.stopImmediatePropagation())},P=function(){if(i.active)return ut.activateTrap(n,s),i.delayInitialFocusTimer=a.delayInitialFocus?lt(function(){g(h())}):g(h()),r.addEventListener("focusin",T,!0),r.addEventListener("mousedown",S,{capture:!0,passive:!1}),r.addEventListener("touchstart",S,{capture:!0,passive:!1}),r.addEventListener("click",L,{capture:!0,passive:!1}),r.addEventListener("keydown",_,{capture:!0,passive:!1}),s},I=function(){if(i.active)return r.removeEventListener("focusin",T,!0),r.removeEventListener("mousedown",S,!0),r.removeEventListener("touchstart",S,!0),r.removeEventListener("click",L,!0),r.removeEventListener("keydown",_,!0),s},E=function(f){var c=f.some(function(p){var C=Array.from(p.removedNodes);return C.some(function(N){return N===i.mostRecentlyFocusedNode})});c&&g(h())},O=typeof window<"u"&&"MutationObserver"in window?new MutationObserver(E):void 0,R=function(){O&&(O.disconnect(),i.active&&!i.paused&&i.containers.map(function(f){O.observe(f,{subtree:!0,childList:!0})}))};return s={get active(){return i.active},get paused(){return i.paused},activate:function(f){if(i.active)return this;var c=u(f,"onActivate"),p=u(f,"onPostActivate"),C=u(f,"checkCanFocusTrap");C||v(),i.active=!0,i.paused=!1,i.nodeFocusedBeforeActivation=r.activeElement,c==null||c();var N=function(){C&&v(),P(),R(),p==null||p()};return C?(C(i.containers.concat()).then(N,N),this):(N(),this)},deactivate:function(f){if(!i.active)return this;var c=st({onDeactivate:a.onDeactivate,onPostDeactivate:a.onPostDeactivate,checkCanReturnFocus:a.checkCanReturnFocus},f);clearTimeout(i.delayInitialFocusTimer),i.delayInitialFocusTimer=void 0,I(),i.active=!1,i.paused=!1,R(),ut.deactivateTrap(n,s);var p=u(c,"onDeactivate"),C=u(c,"onPostDeactivate"),N=u(c,"checkCanReturnFocus"),M=u(c,"returnFocus","returnFocusOnDeactivate");p==null||p();var z=function(){lt(function(){M&&g(b(i.nodeFocusedBeforeActivation)),C==null||C()})};return M&&N?(N(b(i.nodeFocusedBeforeActivation)).then(z,z),this):(z(),this)},pause:function(f){if(i.paused||!i.active)return this;var c=u(f,"onPause"),p=u(f,"onPostPause");return i.paused=!0,c==null||c(),I(),R(),p==null||p(),this},unpause:function(f){if(!i.paused||!i.active)return this;var c=u(f,"onUnpause"),p=u(f,"onPostUnpause");return i.paused=!1,c==null||c(),v(),P(),R(),p==null||p(),this},updateContainerElements:function(f){var c=[].concat(f).filter(Boolean);return i.containers=c.map(function(p){return typeof p=="string"?r.querySelector(p):p}),i.active&&v(),R(),this}},s.updateContainerElements(e),s};function Dr(o,e={}){let t;const{immediate:r,...n}=e,a=ie(!1),i=ie(!1),s=h=>t&&t.activate(h),u=h=>t&&t.deactivate(h),l=()=>{t&&(t.pause(),i.value=!0)},d=()=>{t&&(t.unpause(),i.value=!1)};return Be(()=>Dt(o),h=>{h&&(t=Ir(h,{...n,onActivate(){a.value=!0,e.onActivate&&e.onActivate()},onDeactivate(){a.value=!1,e.onDeactivate&&e.onDeactivate()}}),r&&s())},{flush:"post"}),kt(()=>u()),{hasFocus:a,isPaused:i,activate:s,deactivate:u,pause:l,unpause:d}}class ce{constructor(e,t=!0,r=[],n=5e3){this.ctx=e,this.iframes=t,this.exclude=r,this.iframesTimeout=n}static matches(e,t){const r=typeof t=="string"?[t]:t,n=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector;if(n){let a=!1;return r.every(i=>n.call(e,i)?(a=!0,!1):!0),a}else return!1}getContexts(){let e,t=[];return typeof this.ctx>"u"||!this.ctx?e=[]:NodeList.prototype.isPrototypeOf(this.ctx)?e=Array.prototype.slice.call(this.ctx):Array.isArray(this.ctx)?e=this.ctx:typeof this.ctx=="string"?e=Array.prototype.slice.call(document.querySelectorAll(this.ctx)):e=[this.ctx],e.forEach(r=>{const n=t.filter(a=>a.contains(r)).length>0;t.indexOf(r)===-1&&!n&&t.push(r)}),t}getIframeContents(e,t,r=()=>{}){let n;try{const a=e.contentWindow;if(n=a.document,!a||!n)throw new Error("iframe inaccessible")}catch{r()}n&&t(n)}isIframeBlank(e){const t="about:blank",r=e.getAttribute("src").trim();return e.contentWindow.location.href===t&&r!==t&&r}observeIframeLoad(e,t,r){let n=!1,a=null;const i=()=>{if(!n){n=!0,clearTimeout(a);try{this.isIframeBlank(e)||(e.removeEventListener("load",i),this.getIframeContents(e,t,r))}catch{r()}}};e.addEventListener("load",i),a=setTimeout(i,this.iframesTimeout)}onIframeReady(e,t,r){try{e.contentWindow.document.readyState==="complete"?this.isIframeBlank(e)?this.observeIframeLoad(e,t,r):this.getIframeContents(e,t,r):this.observeIframeLoad(e,t,r)}catch{r()}}waitForIframes(e,t){let r=0;this.forEachIframe(e,()=>!0,n=>{r++,this.waitForIframes(n.querySelector("html"),()=>{--r||t()})},n=>{n||t()})}forEachIframe(e,t,r,n=()=>{}){let a=e.querySelectorAll("iframe"),i=a.length,s=0;a=Array.prototype.slice.call(a);const u=()=>{--i<=0&&n(s)};i||u(),a.forEach(l=>{ce.matches(l,this.exclude)?u():this.onIframeReady(l,d=>{t(l)&&(s++,r(d)),u()},u)})}createIterator(e,t,r){return document.createNodeIterator(e,t,r,!1)}createInstanceOnIframe(e){return new ce(e.querySelector("html"),this.iframes)}compareNodeIframe(e,t,r){const n=e.compareDocumentPosition(r),a=Node.DOCUMENT_POSITION_PRECEDING;if(n&a)if(t!==null){const i=t.compareDocumentPosition(r),s=Node.DOCUMENT_POSITION_FOLLOWING;if(i&s)return!0}else return!0;return!1}getIteratorNode(e){const t=e.previousNode();let r;return t===null?r=e.nextNode():r=e.nextNode()&&e.nextNode(),{prevNode:t,node:r}}checkIframeFilter(e,t,r,n){let a=!1,i=!1;return n.forEach((s,u)=>{s.val===r&&(a=u,i=s.handled)}),this.compareNodeIframe(e,t,r)?(a===!1&&!i?n.push({val:r,handled:!0}):a!==!1&&!i&&(n[a].handled=!0),!0):(a===!1&&n.push({val:r,handled:!1}),!1)}handleOpenIframes(e,t,r,n){e.forEach(a=>{a.handled||this.getIframeContents(a.val,i=>{this.createInstanceOnIframe(i).forEachNode(t,r,n)})})}iterateThroughNodes(e,t,r,n,a){const i=this.createIterator(t,e,n);let s=[],u=[],l,d,h=()=>({prevNode:d,node:l}=this.getIteratorNode(i),l);for(;h();)this.iframes&&this.forEachIframe(t,v=>this.checkIframeFilter(l,d,v,s),v=>{this.createInstanceOnIframe(v).forEachNode(e,m=>u.push(m),n)}),u.push(l);u.forEach(v=>{r(v)}),this.iframes&&this.handleOpenIframes(s,e,r,n),a()}forEachNode(e,t,r,n=()=>{}){const a=this.getContexts();let i=a.length;i||n(),a.forEach(s=>{const u=()=>{this.iterateThroughNodes(e,s,t,r,()=>{--i<=0&&n()})};this.iframes?this.waitForIframes(s,u):u()})}}let kr=class{constructor(e){this.ctx=e,this.ie=!1;const t=window.navigator.userAgent;(t.indexOf("MSIE")>-1||t.indexOf("Trident")>-1)&&(this.ie=!0)}set opt(e){this._opt=Object.assign({},{element:"",className:"",exclude:[],iframes:!1,iframesTimeout:5e3,separateWordSearch:!0,diacritics:!0,synonyms:{},accuracy:"partially",acrossElements:!1,caseSensitive:!1,ignoreJoiners:!1,ignoreGroups:0,ignorePunctuation:[],wildcards:"disabled",each:()=>{},noMatch:()=>{},filter:()=>!0,done:()=>{},debug:!1,log:window.console},e)}get opt(){return this._opt}get iterator(){return new ce(this.ctx,this.opt.iframes,this.opt.exclude,this.opt.iframesTimeout)}log(e,t="debug"){const r=this.opt.log;this.opt.debug&&typeof r=="object"&&typeof r[t]=="function"&&r[t](`mark.js: ${e}`)}escapeStr(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}createRegExp(e){return this.opt.wildcards!=="disabled"&&(e=this.setupWildcardsRegExp(e)),e=this.escapeStr(e),Object.keys(this.opt.synonyms).length&&(e=this.createSynonymsRegExp(e)),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),this.opt.diacritics&&(e=this.createDiacriticsRegExp(e)),e=this.createMergedBlanksRegExp(e),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.createJoinersRegExp(e)),this.opt.wildcards!=="disabled"&&(e=this.createWildcardsRegExp(e)),e=this.createAccuracyRegExp(e),e}createSynonymsRegExp(e){const t=this.opt.synonyms,r=this.opt.caseSensitive?"":"i",n=this.opt.ignoreJoiners||this.opt.ignorePunctuation.length?"\0":"";for(let a in t)if(t.hasOwnProperty(a)){const i=t[a],s=this.opt.wildcards!=="disabled"?this.setupWildcardsRegExp(a):this.escapeStr(a),u=this.opt.wildcards!=="disabled"?this.setupWildcardsRegExp(i):this.escapeStr(i);s!==""&&u!==""&&(e=e.replace(new RegExp(`(${this.escapeStr(s)}|${this.escapeStr(u)})`,`gm${r}`),n+`(${this.processSynomyms(s)}|${this.processSynomyms(u)})`+n))}return e}processSynomyms(e){return(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),e}setupWildcardsRegExp(e){return e=e.replace(/(?:\\)*\?/g,t=>t.charAt(0)==="\\"?"?":""),e.replace(/(?:\\)*\*/g,t=>t.charAt(0)==="\\"?"*":"")}createWildcardsRegExp(e){let t=this.opt.wildcards==="withSpaces";return e.replace(/\u0001/g,t?"[\\S\\s]?":"\\S?").replace(/\u0002/g,t?"[\\S\\s]*?":"\\S*")}setupIgnoreJoinersRegExp(e){return e.replace(/[^(|)\\]/g,(t,r,n)=>{let a=n.charAt(r+1);return/[(|)\\]/.test(a)||a===""?t:t+"\0"})}createJoinersRegExp(e){let t=[];const r=this.opt.ignorePunctuation;return Array.isArray(r)&&r.length&&t.push(this.escapeStr(r.join(""))),this.opt.ignoreJoiners&&t.push("\\u00ad\\u200b\\u200c\\u200d"),t.length?e.split(/\u0000+/).join(`[${t.join("")}]*`):e}createDiacriticsRegExp(e){const t=this.opt.caseSensitive?"":"i",r=this.opt.caseSensitive?["aàáảãạăằắẳẵặâầấẩẫậäåāą","AÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćč","CÇĆČ","dđď","DĐĎ","eèéẻẽẹêềếểễệëěēę","EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïī","IÌÍỈĨỊÎÏĪ","lł","LŁ","nñňń","NÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøō","OÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rř","RŘ","sšśșş","SŠŚȘŞ","tťțţ","TŤȚŢ","uùúủũụưừứửữựûüůū","UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿ","YÝỲỶỸỴŸ","zžżź","ZŽŻŹ"]:["aàáảãạăằắẳẵặâầấẩẫậäåāąAÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćčCÇĆČ","dđďDĐĎ","eèéẻẽẹêềếểễệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïīIÌÍỈĨỊÎÏĪ","lłLŁ","nñňńNÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøōOÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rřRŘ","sšśșşSŠŚȘŞ","tťțţTŤȚŢ","uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿYÝỲỶỸỴŸ","zžżźZŽŻŹ"];let n=[];return e.split("").forEach(a=>{r.every(i=>{if(i.indexOf(a)!==-1){if(n.indexOf(i)>-1)return!1;e=e.replace(new RegExp(`[${i}]`,`gm${t}`),`[${i}]`),n.push(i)}return!0})}),e}createMergedBlanksRegExp(e){return e.replace(/[\s]+/gmi,"[\\s]+")}createAccuracyRegExp(e){const t="!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~¡¿";let r=this.opt.accuracy,n=typeof r=="string"?r:r.value,a=typeof r=="string"?[]:r.limiters,i="";switch(a.forEach(s=>{i+=`|${this.escapeStr(s)}`}),n){case"partially":default:return`()(${e})`;case"complementary":return i="\\s"+(i||this.escapeStr(t)),`()([^${i}]*${e}[^${i}]*)`;case"exactly":return`(^|\\s${i})(${e})(?=$|\\s${i})`}}getSeparatedKeywords(e){let t=[];return e.forEach(r=>{this.opt.separateWordSearch?r.split(" ").forEach(n=>{n.trim()&&t.indexOf(n)===-1&&t.push(n)}):r.trim()&&t.indexOf(r)===-1&&t.push(r)}),{keywords:t.sort((r,n)=>n.length-r.length),length:t.length}}isNumeric(e){return Number(parseFloat(e))==e}checkRanges(e){if(!Array.isArray(e)||Object.prototype.toString.call(e[0])!=="[object Object]")return this.log("markRanges() will only accept an array of objects"),this.opt.noMatch(e),[];const t=[];let r=0;return e.sort((n,a)=>n.start-a.start).forEach(n=>{let{start:a,end:i,valid:s}=this.callNoMatchOnInvalidRanges(n,r);s&&(n.start=a,n.length=i-a,t.push(n),r=i)}),t}callNoMatchOnInvalidRanges(e,t){let r,n,a=!1;return e&&typeof e.start<"u"?(r=parseInt(e.start,10),n=r+parseInt(e.length,10),this.isNumeric(e.start)&&this.isNumeric(e.length)&&n-t>0&&n-r>0?a=!0:(this.log(`Ignoring invalid or overlapping range: ${JSON.stringify(e)}`),this.opt.noMatch(e))):(this.log(`Ignoring invalid range: ${JSON.stringify(e)}`),this.opt.noMatch(e)),{start:r,end:n,valid:a}}checkWhitespaceRanges(e,t,r){let n,a=!0,i=r.length,s=t-i,u=parseInt(e.start,10)-s;return u=u>i?i:u,n=u+parseInt(e.length,10),n>i&&(n=i,this.log(`End range automatically set to the max value of ${i}`)),u<0||n-u<0||u>i||n>i?(a=!1,this.log(`Invalid range: ${JSON.stringify(e)}`),this.opt.noMatch(e)):r.substring(u,n).replace(/\s+/g,"")===""&&(a=!1,this.log("Skipping whitespace only range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:u,end:n,valid:a}}getTextNodes(e){let t="",r=[];this.iterator.forEachNode(NodeFilter.SHOW_TEXT,n=>{r.push({start:t.length,end:(t+=n.textContent).length,node:n})},n=>this.matchesExclude(n.parentNode)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT,()=>{e({value:t,nodes:r})})}matchesExclude(e){return ce.matches(e,this.opt.exclude.concat(["script","style","title","head","html"]))}wrapRangeInTextNode(e,t,r){const n=this.opt.element?this.opt.element:"mark",a=e.splitText(t),i=a.splitText(r-t);let s=document.createElement(n);return s.setAttribute("data-markjs","true"),this.opt.className&&s.setAttribute("class",this.opt.className),s.textContent=a.textContent,a.parentNode.replaceChild(s,a),i}wrapRangeInMappedTextNode(e,t,r,n,a){e.nodes.every((i,s)=>{const u=e.nodes[s+1];if(typeof u>"u"||u.start>t){if(!n(i.node))return!1;const l=t-i.start,d=(r>i.end?i.end:r)-i.start,h=e.value.substr(0,i.start),v=e.value.substr(d+i.start);if(i.node=this.wrapRangeInTextNode(i.node,l,d),e.value=h+v,e.nodes.forEach((m,g)=>{g>=s&&(e.nodes[g].start>0&&g!==s&&(e.nodes[g].start-=d),e.nodes[g].end-=d)}),r-=d,a(i.node.previousSibling,i.start),r>i.end)t=i.end;else return!1}return!0})}wrapMatches(e,t,r,n,a){const i=t===0?0:t+1;this.getTextNodes(s=>{s.nodes.forEach(u=>{u=u.node;let l;for(;(l=e.exec(u.textContent))!==null&&l[i]!=="";){if(!r(l[i],u))continue;let d=l.index;if(i!==0)for(let h=1;h{let u;for(;(u=e.exec(s.value))!==null&&u[i]!=="";){let l=u.index;if(i!==0)for(let h=1;hr(u[i],h),(h,v)=>{e.lastIndex=v,n(h)})}a()})}wrapRangeFromIndex(e,t,r,n){this.getTextNodes(a=>{const i=a.value.length;e.forEach((s,u)=>{let{start:l,end:d,valid:h}=this.checkWhitespaceRanges(s,i,a.value);h&&this.wrapRangeInMappedTextNode(a,l,d,v=>t(v,s,a.value.substring(l,d),u),v=>{r(v,s)})}),n()})}unwrapMatches(e){const t=e.parentNode;let r=document.createDocumentFragment();for(;e.firstChild;)r.appendChild(e.removeChild(e.firstChild));t.replaceChild(r,e),this.ie?this.normalizeTextNode(t):t.normalize()}normalizeTextNode(e){if(e){if(e.nodeType===3)for(;e.nextSibling&&e.nextSibling.nodeType===3;)e.nodeValue+=e.nextSibling.nodeValue,e.parentNode.removeChild(e.nextSibling);else this.normalizeTextNode(e.firstChild);this.normalizeTextNode(e.nextSibling)}}markRegExp(e,t){this.opt=t,this.log(`Searching with expression "${e}"`);let r=0,n="wrapMatches";const a=i=>{r++,this.opt.each(i)};this.opt.acrossElements&&(n="wrapMatchesAcrossElements"),this[n](e,this.opt.ignoreGroups,(i,s)=>this.opt.filter(s,i,r),a,()=>{r===0&&this.opt.noMatch(e),this.opt.done(r)})}mark(e,t){this.opt=t;let r=0,n="wrapMatches";const{keywords:a,length:i}=this.getSeparatedKeywords(typeof e=="string"?[e]:e),s=this.opt.caseSensitive?"":"i",u=l=>{let d=new RegExp(this.createRegExp(l),`gm${s}`),h=0;this.log(`Searching with expression "${d}"`),this[n](d,1,(v,m)=>this.opt.filter(m,l,r,h),v=>{h++,r++,this.opt.each(v)},()=>{h===0&&this.opt.noMatch(l),a[i-1]===l?this.opt.done(r):u(a[a.indexOf(l)+1])})};this.opt.acrossElements&&(n="wrapMatchesAcrossElements"),i===0?this.opt.done(r):u(a[0])}markRanges(e,t){this.opt=t;let r=0,n=this.checkRanges(e);n&&n.length?(this.log("Starting to mark with the following ranges: "+JSON.stringify(n)),this.wrapRangeFromIndex(n,(a,i,s,u)=>this.opt.filter(a,i,s,u),(a,i)=>{r++,this.opt.each(a,i)},()=>{this.opt.done(r)})):this.opt.done(r)}unmark(e){this.opt=e;let t=this.opt.element?this.opt.element:"*";t+="[data-markjs]",this.opt.className&&(t+=`.${this.opt.className}`),this.log(`Removal selector "${t}"`),this.iterator.forEachNode(NodeFilter.SHOW_ELEMENT,r=>{this.unwrapMatches(r)},r=>{const n=ce.matches(r,t),a=this.matchesExclude(r);return!n||a?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT},this.opt.done)}};function Or(o){const e=new kr(o);return this.mark=(t,r)=>(e.mark(t,r),this),this.markRegExp=(t,r)=>(e.markRegExp(t,r),this),this.markRanges=(t,r)=>(e.markRanges(t,r),this),this.unmark=t=>(e.unmark(t),this),this}var $=function(){return $=Object.assign||function(e){for(var t,r=1,n=arguments.length;r0&&a[a.length-1])&&(l[0]===6||l[0]===2)){t=0;continue}if(l[0]===3&&(!a||l[1]>a[0]&&l[1]=o.length&&(o=void 0),{value:o&&o[r++],done:!o}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")}function W(o,e){var t=typeof Symbol=="function"&&o[Symbol.iterator];if(!t)return o;var r=t.call(o),n,a=[],i;try{for(;(e===void 0||e-- >0)&&!(n=r.next()).done;)a.push(n.value)}catch(s){i={error:s}}finally{try{n&&!n.done&&(t=r.return)&&t.call(r)}finally{if(i)throw i.error}}return a}var Mr="ENTRIES",xt="KEYS",Ft="VALUES",Q="",_e=function(){function o(e,t){var r=e._tree,n=Array.from(r.keys());this.set=e,this._type=t,this._path=n.length>0?[{node:r,keys:n}]:[]}return o.prototype.next=function(){var e=this.dive();return this.backtrack(),e},o.prototype.dive=function(){if(this._path.length===0)return{done:!0,value:void 0};var e=le(this._path),t=e.node,r=e.keys;if(le(r)===Q)return{done:!1,value:this.result()};var n=t.get(le(r));return this._path.push({node:n,keys:Array.from(n.keys())}),this.dive()},o.prototype.backtrack=function(){if(this._path.length!==0){var e=le(this._path).keys;e.pop(),!(e.length>0)&&(this._path.pop(),this.backtrack())}},o.prototype.key=function(){return this.set._prefix+this._path.map(function(e){var t=e.keys;return le(t)}).filter(function(e){return e!==Q}).join("")},o.prototype.value=function(){return le(this._path).node.get(Q)},o.prototype.result=function(){switch(this._type){case Ft:return this.value();case xt:return this.key();default:return[this.key(),this.value()]}},o.prototype[Symbol.iterator]=function(){return this},o}(),le=function(o){return o[o.length-1]},Lr=function(o,e,t){var r=new Map;if(e===void 0)return r;for(var n=e.length+1,a=n+t,i=new Uint8Array(a*n).fill(t+1),s=0;st)continue e}Et(o.get(m),e,t,r,n,b,i,s+m)}}}catch(c){u={error:c}}finally{try{v&&!v.done&&(l=h.return)&&l.call(h)}finally{if(u)throw u.error}}},Me=function(){function o(e,t){e===void 0&&(e=new Map),t===void 0&&(t=""),this._size=void 0,this._tree=e,this._prefix=t}return o.prototype.atPrefix=function(e){var t,r;if(!e.startsWith(this._prefix))throw new Error("Mismatched prefix");var n=W(De(this._tree,e.slice(this._prefix.length)),2),a=n[0],i=n[1];if(a===void 0){var s=W(Je(i),2),u=s[0],l=s[1];try{for(var d=D(u.keys()),h=d.next();!h.done;h=d.next()){var v=h.value;if(v!==Q&&v.startsWith(l)){var m=new Map;return m.set(v.slice(l.length),u.get(v)),new o(m,e)}}}catch(g){t={error:g}}finally{try{h&&!h.done&&(r=d.return)&&r.call(d)}finally{if(t)throw t.error}}}return new o(a,e)},o.prototype.clear=function(){this._size=void 0,this._tree.clear()},o.prototype.delete=function(e){return this._size=void 0,Pr(this._tree,e)},o.prototype.entries=function(){return new _e(this,Mr)},o.prototype.forEach=function(e){var t,r;try{for(var n=D(this),a=n.next();!a.done;a=n.next()){var i=W(a.value,2),s=i[0],u=i[1];e(s,u,this)}}catch(l){t={error:l}}finally{try{a&&!a.done&&(r=n.return)&&r.call(n)}finally{if(t)throw t.error}}},o.prototype.fuzzyGet=function(e,t){return Lr(this._tree,e,t)},o.prototype.get=function(e){var t=We(this._tree,e);return t!==void 0?t.get(Q):void 0},o.prototype.has=function(e){var t=We(this._tree,e);return t!==void 0&&t.has(Q)},o.prototype.keys=function(){return new _e(this,xt)},o.prototype.set=function(e,t){if(typeof e!="string")throw new Error("key must be a string");this._size=void 0;var r=Le(this._tree,e);return r.set(Q,t),this},Object.defineProperty(o.prototype,"size",{get:function(){if(this._size)return this._size;this._size=0;for(var e=this.entries();!e.next().done;)this._size+=1;return this._size},enumerable:!1,configurable:!0}),o.prototype.update=function(e,t){if(typeof e!="string")throw new Error("key must be a string");this._size=void 0;var r=Le(this._tree,e);return r.set(Q,t(r.get(Q))),this},o.prototype.fetch=function(e,t){if(typeof e!="string")throw new Error("key must be a string");this._size=void 0;var r=Le(this._tree,e),n=r.get(Q);return n===void 0&&r.set(Q,n=t()),n},o.prototype.values=function(){return new _e(this,Ft)},o.prototype[Symbol.iterator]=function(){return this.entries()},o.from=function(e){var t,r,n=new o;try{for(var a=D(e),i=a.next();!i.done;i=a.next()){var s=W(i.value,2),u=s[0],l=s[1];n.set(u,l)}}catch(d){t={error:d}}finally{try{i&&!i.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}return n},o.fromObject=function(e){return o.from(Object.entries(e))},o}(),De=function(o,e,t){var r,n;if(t===void 0&&(t=[]),e.length===0||o==null)return[o,t];try{for(var a=D(o.keys()),i=a.next();!i.done;i=a.next()){var s=i.value;if(s!==Q&&e.startsWith(s))return t.push([o,s]),De(o.get(s),e.slice(s.length),t)}}catch(u){r={error:u}}finally{try{i&&!i.done&&(n=a.return)&&n.call(a)}finally{if(r)throw r.error}}return t.push([o,e]),De(void 0,"",t)},We=function(o,e){var t,r;if(e.length===0||o==null)return o;try{for(var n=D(o.keys()),a=n.next();!a.done;a=n.next()){var i=a.value;if(i!==Q&&e.startsWith(i))return We(o.get(i),e.slice(i.length))}}catch(s){t={error:s}}finally{try{a&&!a.done&&(r=n.return)&&r.call(n)}finally{if(t)throw t.error}}},Le=function(o,e){var t,r,n=e.length;e:for(var a=0;o&&a0)throw new Error("Expected documents to be present. Omit the argument to remove all documents.");this._index=new Me,this._documentCount=0,this._documentIds=new Map,this._idToShortId=new Map,this._fieldLength=new Map,this._avgFieldLength=[],this._storedFields=new Map,this._nextId=0}},o.prototype.discard=function(e){var t=this,r=this._idToShortId.get(e);if(r==null)throw new Error("MiniSearch: cannot discard document with ID ".concat(e,": it is not in the index"));this._idToShortId.delete(e),this._documentIds.delete(r),this._storedFields.delete(r),(this._fieldLength.get(r)||[]).forEach(function(n,a){t.removeFieldLength(r,a,t._documentCount,n)}),this._fieldLength.delete(r),this._documentCount-=1,this._dirtCount+=1,this.maybeAutoVacuum()},o.prototype.maybeAutoVacuum=function(){if(this._options.autoVacuum!==!1){var e=this._options.autoVacuum,t=e.minDirtFactor,r=e.minDirtCount,n=e.batchSize,a=e.batchWait;this.conditionalVacuum({batchSize:n,batchWait:a},{minDirtCount:r,minDirtFactor:t})}},o.prototype.discardAll=function(e){var t,r,n=this._options.autoVacuum;try{this._options.autoVacuum=!1;try{for(var a=D(e),i=a.next();!i.done;i=a.next()){var s=i.value;this.discard(s)}}catch(u){t={error:u}}finally{try{i&&!i.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}}finally{this._options.autoVacuum=n}this.maybeAutoVacuum()},o.prototype.replace=function(e){var t=this._options,r=t.idField,n=t.extractField,a=n(e,r);this.discard(a),this.add(e)},o.prototype.vacuum=function(e){return e===void 0&&(e={}),this.conditionalVacuum(e)},o.prototype.conditionalVacuum=function(e,t){var r=this;return this._currentVacuum?(this._enqueuedVacuumConditions=this._enqueuedVacuumConditions&&t,this._enqueuedVacuum!=null?this._enqueuedVacuum:(this._enqueuedVacuum=this._currentVacuum.then(function(){var n=r._enqueuedVacuumConditions;return r._enqueuedVacuumConditions=Ue,r.performVacuuming(e,n)}),this._enqueuedVacuum)):this.vacuumConditionsMet(t)===!1?Promise.resolve():(this._currentVacuum=this.performVacuuming(e),this._currentVacuum)},o.prototype.performVacuuming=function(e,t){return Rr(this,void 0,void 0,function(){var r,n,a,i,s,u,l,d,h,v,m,g,b,x,S,T,A,_,L,P,I,E,O,R,F;return _r(this,function(f){switch(f.label){case 0:if(r=this._dirtCount,!this.vacuumConditionsMet(t))return[3,10];n=e.batchSize||Ke.batchSize,a=e.batchWait||Ke.batchWait,i=1,f.label=1;case 1:f.trys.push([1,7,8,9]),s=D(this._index),u=s.next(),f.label=2;case 2:if(u.done)return[3,6];l=W(u.value,2),d=l[0],h=l[1];try{for(v=(E=void 0,D(h)),m=v.next();!m.done;m=v.next()){g=W(m.value,2),b=g[0],x=g[1];try{for(S=(R=void 0,D(x)),T=S.next();!T.done;T=S.next())A=W(T.value,1),_=A[0],!this._documentIds.has(_)&&(x.size<=1?h.delete(b):x.delete(_))}catch(c){R={error:c}}finally{try{T&&!T.done&&(F=S.return)&&F.call(S)}finally{if(R)throw R.error}}}}catch(c){E={error:c}}finally{try{m&&!m.done&&(O=v.return)&&O.call(v)}finally{if(E)throw E.error}}return this._index.get(d).size===0&&this._index.delete(d),i%n!==0?[3,4]:[4,new Promise(function(c){return setTimeout(c,a)})];case 3:f.sent(),f.label=4;case 4:i+=1,f.label=5;case 5:return u=s.next(),[3,2];case 6:return[3,9];case 7:return L=f.sent(),P={error:L},[3,9];case 8:try{u&&!u.done&&(I=s.return)&&I.call(s)}finally{if(P)throw P.error}return[7];case 9:this._dirtCount-=r,f.label=10;case 10:return[4,null];case 11:return f.sent(),this._currentVacuum=this._enqueuedVacuum,this._enqueuedVacuum=null,[2]}})})},o.prototype.vacuumConditionsMet=function(e){if(e==null)return!0;var t=e.minDirtCount,r=e.minDirtFactor;return t=t||Ve.minDirtCount,r=r||Ve.minDirtFactor,this.dirtCount>=t&&this.dirtFactor>=r},Object.defineProperty(o.prototype,"isVacuuming",{get:function(){return this._currentVacuum!=null},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"dirtCount",{get:function(){return this._dirtCount},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"dirtFactor",{get:function(){return this._dirtCount/(1+this._documentCount+this._dirtCount)},enumerable:!1,configurable:!0}),o.prototype.has=function(e){return this._idToShortId.has(e)},o.prototype.getStoredFields=function(e){var t=this._idToShortId.get(e);if(t!=null)return this._storedFields.get(t)},o.prototype.search=function(e,t){var r,n;t===void 0&&(t={});var a=this.executeQuery(e,t),i=[];try{for(var s=D(a),u=s.next();!u.done;u=s.next()){var l=W(u.value,2),d=l[0],h=l[1],v=h.score,m=h.terms,g=h.match,b=m.length||1,x={id:this._documentIds.get(d),score:v*b,terms:Object.keys(g),queryTerms:m,match:g};Object.assign(x,this._storedFields.get(d)),(t.filter==null||t.filter(x))&&i.push(x)}}catch(S){r={error:S}}finally{try{u&&!u.done&&(n=s.return)&&n.call(s)}finally{if(r)throw r.error}}return e===o.wildcard&&t.boostDocument==null&&this._options.searchOptions.boostDocument==null||i.sort(dt),i},o.prototype.autoSuggest=function(e,t){var r,n,a,i;t===void 0&&(t={}),t=$($({},this._options.autoSuggestOptions),t);var s=new Map;try{for(var u=D(this.search(e,t)),l=u.next();!l.done;l=u.next()){var d=l.value,h=d.score,v=d.terms,m=v.join(" "),g=s.get(m);g!=null?(g.score+=h,g.count+=1):s.set(m,{score:h,terms:v,count:1})}}catch(L){r={error:L}}finally{try{l&&!l.done&&(n=u.return)&&n.call(u)}finally{if(r)throw r.error}}var b=[];try{for(var x=D(s),S=x.next();!S.done;S=x.next()){var T=W(S.value,2),g=T[0],A=T[1],h=A.score,v=A.terms,_=A.count;b.push({suggestion:g,terms:v,score:h/_})}}catch(L){a={error:L}}finally{try{S&&!S.done&&(i=x.return)&&i.call(x)}finally{if(a)throw a.error}}return b.sort(dt),b},Object.defineProperty(o.prototype,"documentCount",{get:function(){return this._documentCount},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"termCount",{get:function(){return this._index.size},enumerable:!1,configurable:!0}),o.loadJSON=function(e,t){if(t==null)throw new Error("MiniSearch: loadJSON should be given the same options used when serializing the index");return this.loadJS(JSON.parse(e),t)},o.getDefault=function(e){if(ze.hasOwnProperty(e))return Pe(ze,e);throw new Error('MiniSearch: unknown option "'.concat(e,'"'))},o.loadJS=function(e,t){var r,n,a,i,s,u,l=e.index,d=e.documentCount,h=e.nextId,v=e.documentIds,m=e.fieldIds,g=e.fieldLength,b=e.averageFieldLength,x=e.storedFields,S=e.dirtCount,T=e.serializationVersion;if(T!==1&&T!==2)throw new Error("MiniSearch: cannot deserialize an index created with an incompatible version");var A=new o(t);A._documentCount=d,A._nextId=h,A._documentIds=Ae(v),A._idToShortId=new Map,A._fieldIds=m,A._fieldLength=Ae(g),A._avgFieldLength=b,A._storedFields=Ae(x),A._dirtCount=S||0,A._index=new Me;try{for(var _=D(A._documentIds),L=_.next();!L.done;L=_.next()){var P=W(L.value,2),I=P[0],E=P[1];A._idToShortId.set(E,I)}}catch(y){r={error:y}}finally{try{L&&!L.done&&(n=_.return)&&n.call(_)}finally{if(r)throw r.error}}try{for(var O=D(l),R=O.next();!R.done;R=O.next()){var F=W(R.value,2),f=F[0],c=F[1],p=new Map;try{for(var C=(s=void 0,D(Object.keys(c))),N=C.next();!N.done;N=C.next()){var M=N.value,z=c[M];T===1&&(z=z.ds),p.set(parseInt(M,10),Ae(z))}}catch(y){s={error:y}}finally{try{N&&!N.done&&(u=C.return)&&u.call(C)}finally{if(s)throw s.error}}A._index.set(f,p)}}catch(y){a={error:y}}finally{try{R&&!R.done&&(i=O.return)&&i.call(O)}finally{if(a)throw a.error}}return A},o.prototype.executeQuery=function(e,t){var r=this;if(t===void 0&&(t={}),e===o.wildcard)return this.executeWildcardQuery(t);if(typeof e!="string"){var n=$($($({},t),e),{queries:void 0}),a=e.queries.map(function(x){return r.executeQuery(x,n)});return this.combineResults(a,n.combineWith)}var i=this._options,s=i.tokenize,u=i.processTerm,l=i.searchOptions,d=$($({tokenize:s,processTerm:u},l),t),h=d.tokenize,v=d.processTerm,m=h(e).flatMap(function(x){return v(x)}).filter(function(x){return!!x}),g=m.map(Kr(d)),b=g.map(function(x){return r.executeQuerySpec(x,d)});return this.combineResults(b,d.combineWith)},o.prototype.executeQuerySpec=function(e,t){var r,n,a,i,s=$($({},this._options.searchOptions),t),u=(s.fields||this._options.fields).reduce(function(M,z){var y;return $($({},M),(y={},y[z]=Pe(s.boost,z)||1,y))},{}),l=s.boostDocument,d=s.weights,h=s.maxFuzzy,v=s.bm25,m=$($({},ft.weights),d),g=m.fuzzy,b=m.prefix,x=this._index.get(e.term),S=this.termResults(e.term,e.term,1,x,u,l,v),T,A;if(e.prefix&&(T=this._index.atPrefix(e.term)),e.fuzzy){var _=e.fuzzy===!0?.2:e.fuzzy,L=_<1?Math.min(h,Math.round(e.term.length*_)):_;L&&(A=this._index.fuzzyGet(e.term,L))}if(T)try{for(var P=D(T),I=P.next();!I.done;I=P.next()){var E=W(I.value,2),O=E[0],R=E[1],F=O.length-e.term.length;if(F){A==null||A.delete(O);var f=b*O.length/(O.length+.3*F);this.termResults(e.term,O,f,R,u,l,v,S)}}}catch(M){r={error:M}}finally{try{I&&!I.done&&(n=P.return)&&n.call(P)}finally{if(r)throw r.error}}if(A)try{for(var c=D(A.keys()),p=c.next();!p.done;p=c.next()){var O=p.value,C=W(A.get(O),2),N=C[0],F=C[1];if(F){var f=g*O.length/(O.length+F);this.termResults(e.term,O,f,N,u,l,v,S)}}}catch(M){a={error:M}}finally{try{p&&!p.done&&(i=c.return)&&i.call(c)}finally{if(a)throw a.error}}return S},o.prototype.executeWildcardQuery=function(e){var t,r,n=new Map,a=$($({},this._options.searchOptions),e);try{for(var i=D(this._documentIds),s=i.next();!s.done;s=i.next()){var u=W(s.value,2),l=u[0],d=u[1],h=a.boostDocument?a.boostDocument(d,"",this._storedFields.get(l)):1;n.set(l,{score:h,terms:[],match:{}})}}catch(v){t={error:v}}finally{try{s&&!s.done&&(r=i.return)&&r.call(i)}finally{if(t)throw t.error}}return n},o.prototype.combineResults=function(e,t){if(t===void 0&&(t=je),e.length===0)return new Map;var r=t.toLowerCase();return e.reduce(Br[r])||new Map},o.prototype.toJSON=function(){var e,t,r,n,a=[];try{for(var i=D(this._index),s=i.next();!s.done;s=i.next()){var u=W(s.value,2),l=u[0],d=u[1],h={};try{for(var v=(r=void 0,D(d)),m=v.next();!m.done;m=v.next()){var g=W(m.value,2),b=g[0],x=g[1];h[b]=Object.fromEntries(x)}}catch(S){r={error:S}}finally{try{m&&!m.done&&(n=v.return)&&n.call(v)}finally{if(r)throw r.error}}a.push([l,h])}}catch(S){e={error:S}}finally{try{s&&!s.done&&(t=i.return)&&t.call(i)}finally{if(e)throw e.error}}return{documentCount:this._documentCount,nextId:this._nextId,documentIds:Object.fromEntries(this._documentIds),fieldIds:this._fieldIds,fieldLength:Object.fromEntries(this._fieldLength),averageFieldLength:this._avgFieldLength,storedFields:Object.fromEntries(this._storedFields),dirtCount:this._dirtCount,index:a,serializationVersion:2}},o.prototype.termResults=function(e,t,r,n,a,i,s,u){var l,d,h,v,m;if(u===void 0&&(u=new Map),n==null)return u;try{for(var g=D(Object.keys(a)),b=g.next();!b.done;b=g.next()){var x=b.value,S=a[x],T=this._fieldIds[x],A=n.get(T);if(A!=null){var _=A.size,L=this._avgFieldLength[T];try{for(var P=(h=void 0,D(A.keys())),I=P.next();!I.done;I=P.next()){var E=I.value;if(!this._documentIds.has(E)){this.removeTerm(T,E,t),_-=1;continue}var O=i?i(this._documentIds.get(E),t,this._storedFields.get(E)):1;if(O){var R=A.get(E),F=this._fieldLength.get(E)[T],f=Wr(R,_,this._documentCount,F,L,s),c=r*S*O*f,p=u.get(E);if(p){p.score+=c,Jr(p.terms,e);var C=Pe(p.match,t);C?C.push(x):p.match[t]=[x]}else u.set(E,{score:c,terms:[e],match:(m={},m[t]=[x],m)})}}}catch(N){h={error:N}}finally{try{I&&!I.done&&(v=P.return)&&v.call(P)}finally{if(h)throw h.error}}}}}catch(N){l={error:N}}finally{try{b&&!b.done&&(d=g.return)&&d.call(g)}finally{if(l)throw l.error}}return u},o.prototype.addTerm=function(e,t,r){var n=this._index.fetch(r,vt),a=n.get(e);if(a==null)a=new Map,a.set(t,1),n.set(e,a);else{var i=a.get(t);a.set(t,(i||0)+1)}},o.prototype.removeTerm=function(e,t,r){if(!this._index.has(r)){this.warnDocumentChanged(t,e,r);return}var n=this._index.fetch(r,vt),a=n.get(e);a==null||a.get(t)==null?this.warnDocumentChanged(t,e,r):a.get(t)<=1?a.size<=1?n.delete(e):a.delete(t):a.set(t,a.get(t)-1),this._index.get(r).size===0&&this._index.delete(r)},o.prototype.warnDocumentChanged=function(e,t,r){var n,a;try{for(var i=D(Object.keys(this._fieldIds)),s=i.next();!s.done;s=i.next()){var u=s.value;if(this._fieldIds[u]===t){this._options.logger("warn","MiniSearch: document with ID ".concat(this._documentIds.get(e),' has changed before removal: term "').concat(r,'" was not present in field "').concat(u,'". Removing a document after it has changed can corrupt the index!'),"version_conflict");return}}}catch(l){n={error:l}}finally{try{s&&!s.done&&(a=i.return)&&a.call(i)}finally{if(n)throw n.error}}},o.prototype.addDocumentId=function(e){var t=this._nextId;return this._idToShortId.set(e,t),this._documentIds.set(t,e),this._documentCount+=1,this._nextId+=1,t},o.prototype.addFields=function(e){for(var t=0;t(Qt("data-v-639d7ab9"),o=o(),Ht(),o),Qr=["aria-owns"],Hr={class:"shell"},qr=["title"],Yr=Y(()=>k("span",{"aria-hidden":"true",class:"vpi-search search-icon local-search-icon"},null,-1)),Zr=[Yr],Xr={class:"search-actions before"},ea=["title"],ta=Y(()=>k("span",{class:"vpi-arrow-left local-search-icon"},null,-1)),ra=[ta],aa=["placeholder"],na={class:"search-actions"},ia=["title"],oa=Y(()=>k("span",{class:"vpi-layout-list local-search-icon"},null,-1)),sa=[oa],ua=["disabled","title"],la=Y(()=>k("span",{class:"vpi-delete local-search-icon"},null,-1)),ca=[la],fa=["id","role","aria-labelledby"],ha=["aria-selected"],da=["href","aria-label","onMouseenter","onFocusin"],va={class:"titles"},pa=Y(()=>k("span",{class:"title-icon"},"#",-1)),ya=["innerHTML"],ma=Y(()=>k("span",{class:"vpi-chevron-right local-search-icon"},null,-1)),ga={class:"title main"},ba=["innerHTML"],wa={key:0,class:"excerpt-wrapper"},xa={key:0,class:"excerpt",inert:""},Fa=["innerHTML"],Ea=Y(()=>k("div",{class:"excerpt-gradient-bottom"},null,-1)),Sa=Y(()=>k("div",{class:"excerpt-gradient-top"},null,-1)),Aa={key:0,class:"no-results"},Ta={class:"search-keyboard-shortcuts"},Na=["aria-label"],Ca=Y(()=>k("span",{class:"vpi-arrow-up navigate-icon"},null,-1)),Ia=[Ca],Da=["aria-label"],ka=Y(()=>k("span",{class:"vpi-arrow-down navigate-icon"},null,-1)),Oa=[ka],Ra=["aria-label"],_a=Y(()=>k("span",{class:"vpi-corner-down-left navigate-icon"},null,-1)),Ma=[_a],La=["aria-label"],Pa=Ot({__name:"VPLocalSearchBox",emits:["close"],setup(o,{emit:e}){var M,z;const t=we(),r=we(),n=we(ar),a=tr(),{activate:i}=Dr(t,{immediate:!0,allowOutsideClick:!0,clickOutsideDeactivates:!0,escapeDeactivates:!0}),{localeIndex:s,theme:u}=a,l=et(async()=>{var y,w,V,J,K,U,B,j,H;return nt(Vr.loadJSON((V=await((w=(y=n.value)[s.value])==null?void 0:w.call(y)))==null?void 0:V.default,{fields:["title","titles","text"],storeFields:["title","titles"],searchOptions:{fuzzy:.2,prefix:!0,boost:{title:4,text:2,titles:1},...((J=u.value.search)==null?void 0:J.provider)==="local"&&((U=(K=u.value.search.options)==null?void 0:K.miniSearch)==null?void 0:U.searchOptions)},...((B=u.value.search)==null?void 0:B.provider)==="local"&&((H=(j=u.value.search.options)==null?void 0:j.miniSearch)==null?void 0:H.options)}))}),h=xe(()=>{var y,w;return((y=u.value.search)==null?void 0:y.provider)==="local"&&((w=u.value.search.options)==null?void 0:w.disableQueryPersistence)===!0}).value?ie(""):Rt("vitepress:local-search-filter",""),v=_t("vitepress:local-search-detailed-list",((M=u.value.search)==null?void 0:M.provider)==="local"&&((z=u.value.search.options)==null?void 0:z.detailedView)===!0),m=xe(()=>{var y,w,V;return((y=u.value.search)==null?void 0:y.provider)==="local"&&(((w=u.value.search.options)==null?void 0:w.disableDetailedView)===!0||((V=u.value.search.options)==null?void 0:V.detailedView)===!1)}),g=xe(()=>{var w,V,J,K,U,B,j;const y=((w=u.value.search)==null?void 0:w.options)??u.value.algolia;return((U=(K=(J=(V=y==null?void 0:y.locales)==null?void 0:V[s.value])==null?void 0:J.translations)==null?void 0:K.button)==null?void 0:U.buttonText)||((j=(B=y==null?void 0:y.translations)==null?void 0:B.button)==null?void 0:j.buttonText)||"Search"});Mt(()=>{m.value&&(v.value=!1)});const b=we([]),x=ie(!1);Be(h,()=>{x.value=!1});const S=et(async()=>{if(r.value)return nt(new Or(r.value))},null),T=new Gr(16);Lt(()=>[l.value,h.value,v.value],async([y,w,V],J,K)=>{var ge,Ge,Qe,He;(J==null?void 0:J[0])!==y&&T.clear();let U=!1;if(K(()=>{U=!0}),!y)return;b.value=y.search(w).slice(0,16),x.value=!0;const B=V?await Promise.all(b.value.map(q=>A(q.id))):[];if(U)return;for(const{id:q,mod:re}of B){const ae=q.slice(0,q.indexOf("#"));let ee=T.get(ae);if(ee)continue;ee=new Map,T.set(ae,ee);const Z=re.default??re;if(Z!=null&&Z.render||Z!=null&&Z.setup){const ne=qt(Z);ne.config.warnHandler=()=>{},ne.provide(Yt,a),Object.defineProperties(ne.config.globalProperties,{$frontmatter:{get(){return a.frontmatter.value}},$params:{get(){return a.page.value.params}}});const qe=document.createElement("div");ne.mount(qe),qe.querySelectorAll("h1, h2, h3, h4, h5, h6").forEach(fe=>{var Xe;const be=(Xe=fe.querySelector("a"))==null?void 0:Xe.getAttribute("href"),Ye=(be==null?void 0:be.startsWith("#"))&&be.slice(1);if(!Ye)return;let Ze="";for(;(fe=fe.nextElementSibling)&&!/^h[1-6]$/i.test(fe.tagName);)Ze+=fe.outerHTML;ee.set(Ye,Ze)}),ne.unmount()}if(U)return}const j=new Set;if(b.value=b.value.map(q=>{const[re,ae]=q.id.split("#"),ee=T.get(re),Z=(ee==null?void 0:ee.get(ae))??"";for(const ne in q.match)j.add(ne);return{...q,text:Z}}),await he(),U)return;await new Promise(q=>{var re;(re=S.value)==null||re.unmark({done:()=>{var ae;(ae=S.value)==null||ae.markRegExp(N(j),{done:q})}})});const H=((ge=t.value)==null?void 0:ge.querySelectorAll(".result .excerpt"))??[];for(const q of H)(Ge=q.querySelector('mark[data-markjs="true"]'))==null||Ge.scrollIntoView({block:"center"});(He=(Qe=r.value)==null?void 0:Qe.firstElementChild)==null||He.scrollIntoView({block:"start"})},{debounce:200,immediate:!0});async function A(y){const w=Zt(y.slice(0,y.indexOf("#")));try{if(!w)throw new Error(`Cannot find file for id: ${y}`);return{id:y,mod:await import(w)}}catch(V){return console.error(V),{id:y,mod:{}}}}const _=ie(),L=xe(()=>{var y;return((y=h.value)==null?void 0:y.length)<=0});function P(y=!0){var w,V;(w=_.value)==null||w.focus(),y&&((V=_.value)==null||V.select())}Oe(()=>{P()});function I(y){y.pointerType==="mouse"&&P()}const E=ie(-1),O=ie(!1);Be(b,y=>{E.value=y.length?0:-1,R()});function R(){he(()=>{const y=document.querySelector(".result.selected");y==null||y.scrollIntoView({block:"nearest"})})}Fe("ArrowUp",y=>{y.preventDefault(),E.value--,E.value<0&&(E.value=b.value.length-1),O.value=!0,R()}),Fe("ArrowDown",y=>{y.preventDefault(),E.value++,E.value>=b.value.length&&(E.value=0),O.value=!0,R()});const F=Pt();Fe("Enter",y=>{if(y.isComposing||y.target instanceof HTMLButtonElement&&y.target.type!=="submit")return;const w=b.value[E.value];if(y.target instanceof HTMLInputElement&&!w){y.preventDefault();return}w&&(F.go(w.id),e("close"))}),Fe("Escape",()=>{e("close")});const c=rr({modal:{displayDetails:"Display detailed list",resetButtonTitle:"Reset search",backButtonTitle:"Close search",noResultsText:"No results for",footer:{selectText:"to select",selectKeyAriaLabel:"enter",navigateText:"to navigate",navigateUpKeyAriaLabel:"up arrow",navigateDownKeyAriaLabel:"down arrow",closeText:"to close",closeKeyAriaLabel:"escape"}}});Oe(()=>{window.history.pushState(null,"",null)}),zt("popstate",y=>{y.preventDefault(),e("close")});const p=Vt(Bt?document.body:null);Oe(()=>{he(()=>{p.value=!0,he().then(()=>i())})}),$t(()=>{p.value=!1});function C(){h.value="",he().then(()=>P(!1))}function N(y){return new RegExp([...y].sort((w,V)=>V.length-w.length).map(w=>`(${Xt(w)})`).join("|"),"gi")}return(y,w)=>{var V,J,K,U;return X(),Wt(Gt,{to:"body"},[k("div",{ref_key:"el",ref:t,role:"button","aria-owns":(V=b.value)!=null&&V.length?"localsearch-list":void 0,"aria-expanded":"true","aria-haspopup":"listbox","aria-labelledby":"localsearch-label",class:"VPLocalSearchBox"},[k("div",{class:"backdrop",onClick:w[0]||(w[0]=B=>y.$emit("close"))}),k("div",Hr,[k("form",{class:"search-bar",onPointerup:w[4]||(w[4]=B=>I(B)),onSubmit:w[5]||(w[5]=Kt(()=>{},["prevent"]))},[k("label",{title:g.value,id:"localsearch-label",for:"localsearch-input"},Zr,8,qr),k("div",Xr,[k("button",{class:"back-button",title:G(c)("modal.backButtonTitle"),onClick:w[1]||(w[1]=B=>y.$emit("close"))},ra,8,ea)]),Ut(k("input",{ref_key:"searchInput",ref:_,"onUpdate:modelValue":w[2]||(w[2]=B=>jt(h)?h.value=B:null),placeholder:g.value,id:"localsearch-input","aria-labelledby":"localsearch-label",class:"search-input"},null,8,aa),[[Jt,G(h)]]),k("div",na,[m.value?Ee("",!0):(X(),te("button",{key:0,class:tt(["toggle-layout-button",{"detailed-list":G(v)}]),type:"button",title:G(c)("modal.displayDetails"),onClick:w[3]||(w[3]=B=>E.value>-1&&(v.value=!G(v)))},sa,10,ia)),k("button",{class:"clear-button",type:"reset",disabled:L.value,title:G(c)("modal.resetButtonTitle"),onClick:C},ca,8,ua)])],32),k("ul",{ref_key:"resultsEl",ref:r,id:(J=b.value)!=null&&J.length?"localsearch-list":void 0,role:(K=b.value)!=null&&K.length?"listbox":void 0,"aria-labelledby":(U=b.value)!=null&&U.length?"localsearch-label":void 0,class:"results",onMousemove:w[7]||(w[7]=B=>O.value=!1)},[(X(!0),te(at,null,rt(b.value,(B,j)=>(X(),te("li",{key:B.id,role:"option","aria-selected":E.value===j?"true":"false"},[k("a",{href:B.id,class:tt(["result",{selected:E.value===j}]),"aria-label":[...B.titles,B.title].join(" > "),onMouseenter:H=>!O.value&&(E.value=j),onFocusin:H=>E.value=j,onClick:w[6]||(w[6]=H=>y.$emit("close"))},[k("div",null,[k("div",va,[pa,(X(!0),te(at,null,rt(B.titles,(H,ge)=>(X(),te("span",{key:ge,class:"title"},[k("span",{class:"text",innerHTML:H},null,8,ya),ma]))),128)),k("span",ga,[k("span",{class:"text",innerHTML:B.title},null,8,ba)])]),G(v)?(X(),te("div",wa,[B.text?(X(),te("div",xa,[k("div",{class:"vp-doc",innerHTML:B.text},null,8,Fa)])):Ee("",!0),Ea,Sa])):Ee("",!0)])],42,da)],8,ha))),128)),G(h)&&!b.value.length&&x.value?(X(),te("li",Aa,[de(ve(G(c)("modal.noResultsText"))+' "',1),k("strong",null,ve(G(h)),1),de('" ')])):Ee("",!0)],40,fa),k("div",Ta,[k("span",null,[k("kbd",{"aria-label":G(c)("modal.footer.navigateUpKeyAriaLabel")},Ia,8,Na),k("kbd",{"aria-label":G(c)("modal.footer.navigateDownKeyAriaLabel")},Oa,8,Da),de(" "+ve(G(c)("modal.footer.navigateText")),1)]),k("span",null,[k("kbd",{"aria-label":G(c)("modal.footer.selectKeyAriaLabel")},Ma,8,Ra),de(" "+ve(G(c)("modal.footer.selectText")),1)]),k("span",null,[k("kbd",{"aria-label":G(c)("modal.footer.closeKeyAriaLabel")},"esc",8,La),de(" "+ve(G(c)("modal.footer.closeText")),1)])])])],8,Qr)])}}}),Ka=er(Pa,[["__scopeId","data-v-639d7ab9"]]);export{Ka as default}; +*/function ot(o,e){var t=Object.keys(o);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(o);e&&(r=r.filter(function(n){return Object.getOwnPropertyDescriptor(o,n).enumerable})),t.push.apply(t,r)}return t}function st(o){for(var e=1;e0){var r=e[e.length-1];r!==t&&r.pause()}var n=e.indexOf(t);n===-1||e.splice(n,1),e.push(t)},deactivateTrap:function(e,t){var r=e.indexOf(t);r!==-1&&e.splice(r,1),e.length>0&&e[e.length-1].unpause()}},Sr=function(e){return e.tagName&&e.tagName.toLowerCase()==="input"&&typeof e.select=="function"},Ar=function(e){return(e==null?void 0:e.key)==="Escape"||(e==null?void 0:e.key)==="Esc"||(e==null?void 0:e.keyCode)===27},me=function(e){return(e==null?void 0:e.key)==="Tab"||(e==null?void 0:e.keyCode)===9},Tr=function(e){return me(e)&&!e.shiftKey},Nr=function(e){return me(e)&&e.shiftKey},lt=function(e){return setTimeout(e,0)},ct=function(e,t){var r=-1;return e.every(function(n,a){return t(n)?(r=a,!1):!0}),r},pe=function(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),n=1;n1?p-1:0),N=1;N=0)f=r.activeElement;else{var c=i.tabbableGroups[0],p=c&&c.firstTabbableNode;f=p||d("fallbackFocus")}if(!f)throw new Error("Your focus-trap needs to have at least one focusable element");return f},v=function(){if(i.containerGroups=i.containers.map(function(f){var c=gr(f,a.tabbableOptions),p=br(f,a.tabbableOptions),C=c.length>0?c[0]:void 0,N=c.length>0?c[c.length-1]:void 0,M=p.find(function(w){return ue(w)}),z=p.slice().reverse().find(function(w){return ue(w)}),y=!!c.find(function(w){return oe(w)>0});return{container:f,tabbableNodes:c,focusableNodes:p,posTabIndexesFound:y,firstTabbableNode:C,lastTabbableNode:N,firstDomTabbableNode:M,lastDomTabbableNode:z,nextTabbableNode:function(V){var U=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0,K=c.indexOf(V);return K<0?U?p.slice(p.indexOf(V)+1).find(function(J){return ue(J)}):p.slice(0,p.indexOf(V)).reverse().find(function(J){return ue(J)}):c[K+(U?1:-1)]}}}),i.tabbableGroups=i.containerGroups.filter(function(f){return f.tabbableNodes.length>0}),i.tabbableGroups.length<=0&&!d("fallbackFocus"))throw new Error("Your focus-trap must have at least one container with at least one tabbable node in it at all times");if(i.containerGroups.find(function(f){return f.posTabIndexesFound})&&i.containerGroups.length>1)throw new Error("At least one node with a positive tabindex was found in one of your focus-trap's multiple containers. Positive tabindexes are only supported in single-container focus-traps.")},m=function F(f){var c=f.activeElement;if(c)return c.shadowRoot&&c.shadowRoot.activeElement!==null?F(c.shadowRoot):c},g=function F(f){if(f!==!1&&f!==m(document)){if(!f||!f.focus){F(h());return}f.focus({preventScroll:!!a.preventScroll}),i.mostRecentlyFocusedNode=f,Sr(f)&&f.select()}},b=function(f){var c=d("setReturnFocus",f);return c||(c===!1?!1:f)},x=function(f){var c=f.target,p=f.event,C=f.isBackward,N=C===void 0?!1:C;c=c||Se(p),v();var M=null;if(i.tabbableGroups.length>0){var z=l(c,p),y=z>=0?i.containerGroups[z]:void 0;if(z<0)N?M=i.tabbableGroups[i.tabbableGroups.length-1].lastTabbableNode:M=i.tabbableGroups[0].firstTabbableNode;else if(N){var w=ct(i.tabbableGroups,function(j){var H=j.firstTabbableNode;return c===H});if(w<0&&(y.container===c||Re(c,a.tabbableOptions)&&!ue(c,a.tabbableOptions)&&!y.nextTabbableNode(c,!1))&&(w=z),w>=0){var V=w===0?i.tabbableGroups.length-1:w-1,U=i.tabbableGroups[V];M=oe(c)>=0?U.lastTabbableNode:U.lastDomTabbableNode}else me(p)||(M=y.nextTabbableNode(c,!1))}else{var K=ct(i.tabbableGroups,function(j){var H=j.lastTabbableNode;return c===H});if(K<0&&(y.container===c||Re(c,a.tabbableOptions)&&!ue(c,a.tabbableOptions)&&!y.nextTabbableNode(c))&&(K=z),K>=0){var J=K===i.tabbableGroups.length-1?0:K+1,B=i.tabbableGroups[J];M=oe(c)>=0?B.firstTabbableNode:B.firstDomTabbableNode}else me(p)||(M=y.nextTabbableNode(c))}}else M=d("fallbackFocus");return M},S=function(f){var c=Se(f);if(!(l(c,f)>=0)){if(pe(a.clickOutsideDeactivates,f)){s.deactivate({returnFocus:a.returnFocusOnDeactivate});return}pe(a.allowOutsideClick,f)||f.preventDefault()}},T=function(f){var c=Se(f),p=l(c,f)>=0;if(p||c instanceof Document)p&&(i.mostRecentlyFocusedNode=c);else{f.stopImmediatePropagation();var C,N=!0;if(i.mostRecentlyFocusedNode)if(oe(i.mostRecentlyFocusedNode)>0){var M=l(i.mostRecentlyFocusedNode),z=i.containerGroups[M].tabbableNodes;if(z.length>0){var y=z.findIndex(function(w){return w===i.mostRecentlyFocusedNode});y>=0&&(a.isKeyForward(i.recentNavEvent)?y+1=0&&(C=z[y-1],N=!1))}}else i.containerGroups.some(function(w){return w.tabbableNodes.some(function(V){return oe(V)>0})})||(N=!1);else N=!1;N&&(C=x({target:i.mostRecentlyFocusedNode,isBackward:a.isKeyBackward(i.recentNavEvent)})),g(C||i.mostRecentlyFocusedNode||h())}i.recentNavEvent=void 0},A=function(f){var c=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1;i.recentNavEvent=f;var p=x({event:f,isBackward:c});p&&(me(f)&&f.preventDefault(),g(p))},_=function(f){if(Ar(f)&&pe(a.escapeDeactivates,f)!==!1){f.preventDefault(),s.deactivate();return}(a.isKeyForward(f)||a.isKeyBackward(f))&&A(f,a.isKeyBackward(f))},L=function(f){var c=Se(f);l(c,f)>=0||pe(a.clickOutsideDeactivates,f)||pe(a.allowOutsideClick,f)||(f.preventDefault(),f.stopImmediatePropagation())},P=function(){if(i.active)return ut.activateTrap(n,s),i.delayInitialFocusTimer=a.delayInitialFocus?lt(function(){g(h())}):g(h()),r.addEventListener("focusin",T,!0),r.addEventListener("mousedown",S,{capture:!0,passive:!1}),r.addEventListener("touchstart",S,{capture:!0,passive:!1}),r.addEventListener("click",L,{capture:!0,passive:!1}),r.addEventListener("keydown",_,{capture:!0,passive:!1}),s},I=function(){if(i.active)return r.removeEventListener("focusin",T,!0),r.removeEventListener("mousedown",S,!0),r.removeEventListener("touchstart",S,!0),r.removeEventListener("click",L,!0),r.removeEventListener("keydown",_,!0),s},E=function(f){var c=f.some(function(p){var C=Array.from(p.removedNodes);return C.some(function(N){return N===i.mostRecentlyFocusedNode})});c&&g(h())},O=typeof window<"u"&&"MutationObserver"in window?new MutationObserver(E):void 0,R=function(){O&&(O.disconnect(),i.active&&!i.paused&&i.containers.map(function(f){O.observe(f,{subtree:!0,childList:!0})}))};return s={get active(){return i.active},get paused(){return i.paused},activate:function(f){if(i.active)return this;var c=u(f,"onActivate"),p=u(f,"onPostActivate"),C=u(f,"checkCanFocusTrap");C||v(),i.active=!0,i.paused=!1,i.nodeFocusedBeforeActivation=r.activeElement,c==null||c();var N=function(){C&&v(),P(),R(),p==null||p()};return C?(C(i.containers.concat()).then(N,N),this):(N(),this)},deactivate:function(f){if(!i.active)return this;var c=st({onDeactivate:a.onDeactivate,onPostDeactivate:a.onPostDeactivate,checkCanReturnFocus:a.checkCanReturnFocus},f);clearTimeout(i.delayInitialFocusTimer),i.delayInitialFocusTimer=void 0,I(),i.active=!1,i.paused=!1,R(),ut.deactivateTrap(n,s);var p=u(c,"onDeactivate"),C=u(c,"onPostDeactivate"),N=u(c,"checkCanReturnFocus"),M=u(c,"returnFocus","returnFocusOnDeactivate");p==null||p();var z=function(){lt(function(){M&&g(b(i.nodeFocusedBeforeActivation)),C==null||C()})};return M&&N?(N(b(i.nodeFocusedBeforeActivation)).then(z,z),this):(z(),this)},pause:function(f){if(i.paused||!i.active)return this;var c=u(f,"onPause"),p=u(f,"onPostPause");return i.paused=!0,c==null||c(),I(),R(),p==null||p(),this},unpause:function(f){if(!i.paused||!i.active)return this;var c=u(f,"onUnpause"),p=u(f,"onPostUnpause");return i.paused=!1,c==null||c(),v(),P(),R(),p==null||p(),this},updateContainerElements:function(f){var c=[].concat(f).filter(Boolean);return i.containers=c.map(function(p){return typeof p=="string"?r.querySelector(p):p}),i.active&&v(),R(),this}},s.updateContainerElements(e),s};function Dr(o,e={}){let t;const{immediate:r,...n}=e,a=ie(!1),i=ie(!1),s=h=>t&&t.activate(h),u=h=>t&&t.deactivate(h),l=()=>{t&&(t.pause(),i.value=!0)},d=()=>{t&&(t.unpause(),i.value=!1)};return Be(()=>Dt(o),h=>{h&&(t=Ir(h,{...n,onActivate(){a.value=!0,e.onActivate&&e.onActivate()},onDeactivate(){a.value=!1,e.onDeactivate&&e.onDeactivate()}}),r&&s())},{flush:"post"}),kt(()=>u()),{hasFocus:a,isPaused:i,activate:s,deactivate:u,pause:l,unpause:d}}class ce{constructor(e,t=!0,r=[],n=5e3){this.ctx=e,this.iframes=t,this.exclude=r,this.iframesTimeout=n}static matches(e,t){const r=typeof t=="string"?[t]:t,n=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector;if(n){let a=!1;return r.every(i=>n.call(e,i)?(a=!0,!1):!0),a}else return!1}getContexts(){let e,t=[];return typeof this.ctx>"u"||!this.ctx?e=[]:NodeList.prototype.isPrototypeOf(this.ctx)?e=Array.prototype.slice.call(this.ctx):Array.isArray(this.ctx)?e=this.ctx:typeof this.ctx=="string"?e=Array.prototype.slice.call(document.querySelectorAll(this.ctx)):e=[this.ctx],e.forEach(r=>{const n=t.filter(a=>a.contains(r)).length>0;t.indexOf(r)===-1&&!n&&t.push(r)}),t}getIframeContents(e,t,r=()=>{}){let n;try{const a=e.contentWindow;if(n=a.document,!a||!n)throw new Error("iframe inaccessible")}catch{r()}n&&t(n)}isIframeBlank(e){const t="about:blank",r=e.getAttribute("src").trim();return e.contentWindow.location.href===t&&r!==t&&r}observeIframeLoad(e,t,r){let n=!1,a=null;const i=()=>{if(!n){n=!0,clearTimeout(a);try{this.isIframeBlank(e)||(e.removeEventListener("load",i),this.getIframeContents(e,t,r))}catch{r()}}};e.addEventListener("load",i),a=setTimeout(i,this.iframesTimeout)}onIframeReady(e,t,r){try{e.contentWindow.document.readyState==="complete"?this.isIframeBlank(e)?this.observeIframeLoad(e,t,r):this.getIframeContents(e,t,r):this.observeIframeLoad(e,t,r)}catch{r()}}waitForIframes(e,t){let r=0;this.forEachIframe(e,()=>!0,n=>{r++,this.waitForIframes(n.querySelector("html"),()=>{--r||t()})},n=>{n||t()})}forEachIframe(e,t,r,n=()=>{}){let a=e.querySelectorAll("iframe"),i=a.length,s=0;a=Array.prototype.slice.call(a);const u=()=>{--i<=0&&n(s)};i||u(),a.forEach(l=>{ce.matches(l,this.exclude)?u():this.onIframeReady(l,d=>{t(l)&&(s++,r(d)),u()},u)})}createIterator(e,t,r){return document.createNodeIterator(e,t,r,!1)}createInstanceOnIframe(e){return new ce(e.querySelector("html"),this.iframes)}compareNodeIframe(e,t,r){const n=e.compareDocumentPosition(r),a=Node.DOCUMENT_POSITION_PRECEDING;if(n&a)if(t!==null){const i=t.compareDocumentPosition(r),s=Node.DOCUMENT_POSITION_FOLLOWING;if(i&s)return!0}else return!0;return!1}getIteratorNode(e){const t=e.previousNode();let r;return t===null?r=e.nextNode():r=e.nextNode()&&e.nextNode(),{prevNode:t,node:r}}checkIframeFilter(e,t,r,n){let a=!1,i=!1;return n.forEach((s,u)=>{s.val===r&&(a=u,i=s.handled)}),this.compareNodeIframe(e,t,r)?(a===!1&&!i?n.push({val:r,handled:!0}):a!==!1&&!i&&(n[a].handled=!0),!0):(a===!1&&n.push({val:r,handled:!1}),!1)}handleOpenIframes(e,t,r,n){e.forEach(a=>{a.handled||this.getIframeContents(a.val,i=>{this.createInstanceOnIframe(i).forEachNode(t,r,n)})})}iterateThroughNodes(e,t,r,n,a){const i=this.createIterator(t,e,n);let s=[],u=[],l,d,h=()=>({prevNode:d,node:l}=this.getIteratorNode(i),l);for(;h();)this.iframes&&this.forEachIframe(t,v=>this.checkIframeFilter(l,d,v,s),v=>{this.createInstanceOnIframe(v).forEachNode(e,m=>u.push(m),n)}),u.push(l);u.forEach(v=>{r(v)}),this.iframes&&this.handleOpenIframes(s,e,r,n),a()}forEachNode(e,t,r,n=()=>{}){const a=this.getContexts();let i=a.length;i||n(),a.forEach(s=>{const u=()=>{this.iterateThroughNodes(e,s,t,r,()=>{--i<=0&&n()})};this.iframes?this.waitForIframes(s,u):u()})}}let kr=class{constructor(e){this.ctx=e,this.ie=!1;const t=window.navigator.userAgent;(t.indexOf("MSIE")>-1||t.indexOf("Trident")>-1)&&(this.ie=!0)}set opt(e){this._opt=Object.assign({},{element:"",className:"",exclude:[],iframes:!1,iframesTimeout:5e3,separateWordSearch:!0,diacritics:!0,synonyms:{},accuracy:"partially",acrossElements:!1,caseSensitive:!1,ignoreJoiners:!1,ignoreGroups:0,ignorePunctuation:[],wildcards:"disabled",each:()=>{},noMatch:()=>{},filter:()=>!0,done:()=>{},debug:!1,log:window.console},e)}get opt(){return this._opt}get iterator(){return new ce(this.ctx,this.opt.iframes,this.opt.exclude,this.opt.iframesTimeout)}log(e,t="debug"){const r=this.opt.log;this.opt.debug&&typeof r=="object"&&typeof r[t]=="function"&&r[t](`mark.js: ${e}`)}escapeStr(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}createRegExp(e){return this.opt.wildcards!=="disabled"&&(e=this.setupWildcardsRegExp(e)),e=this.escapeStr(e),Object.keys(this.opt.synonyms).length&&(e=this.createSynonymsRegExp(e)),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),this.opt.diacritics&&(e=this.createDiacriticsRegExp(e)),e=this.createMergedBlanksRegExp(e),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.createJoinersRegExp(e)),this.opt.wildcards!=="disabled"&&(e=this.createWildcardsRegExp(e)),e=this.createAccuracyRegExp(e),e}createSynonymsRegExp(e){const t=this.opt.synonyms,r=this.opt.caseSensitive?"":"i",n=this.opt.ignoreJoiners||this.opt.ignorePunctuation.length?"\0":"";for(let a in t)if(t.hasOwnProperty(a)){const i=t[a],s=this.opt.wildcards!=="disabled"?this.setupWildcardsRegExp(a):this.escapeStr(a),u=this.opt.wildcards!=="disabled"?this.setupWildcardsRegExp(i):this.escapeStr(i);s!==""&&u!==""&&(e=e.replace(new RegExp(`(${this.escapeStr(s)}|${this.escapeStr(u)})`,`gm${r}`),n+`(${this.processSynomyms(s)}|${this.processSynomyms(u)})`+n))}return e}processSynomyms(e){return(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),e}setupWildcardsRegExp(e){return e=e.replace(/(?:\\)*\?/g,t=>t.charAt(0)==="\\"?"?":""),e.replace(/(?:\\)*\*/g,t=>t.charAt(0)==="\\"?"*":"")}createWildcardsRegExp(e){let t=this.opt.wildcards==="withSpaces";return e.replace(/\u0001/g,t?"[\\S\\s]?":"\\S?").replace(/\u0002/g,t?"[\\S\\s]*?":"\\S*")}setupIgnoreJoinersRegExp(e){return e.replace(/[^(|)\\]/g,(t,r,n)=>{let a=n.charAt(r+1);return/[(|)\\]/.test(a)||a===""?t:t+"\0"})}createJoinersRegExp(e){let t=[];const r=this.opt.ignorePunctuation;return Array.isArray(r)&&r.length&&t.push(this.escapeStr(r.join(""))),this.opt.ignoreJoiners&&t.push("\\u00ad\\u200b\\u200c\\u200d"),t.length?e.split(/\u0000+/).join(`[${t.join("")}]*`):e}createDiacriticsRegExp(e){const t=this.opt.caseSensitive?"":"i",r=this.opt.caseSensitive?["aàáảãạăằắẳẵặâầấẩẫậäåāą","AÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćč","CÇĆČ","dđď","DĐĎ","eèéẻẽẹêềếểễệëěēę","EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïī","IÌÍỈĨỊÎÏĪ","lł","LŁ","nñňń","NÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøō","OÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rř","RŘ","sšśșş","SŠŚȘŞ","tťțţ","TŤȚŢ","uùúủũụưừứửữựûüůū","UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿ","YÝỲỶỸỴŸ","zžżź","ZŽŻŹ"]:["aàáảãạăằắẳẵặâầấẩẫậäåāąAÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćčCÇĆČ","dđďDĐĎ","eèéẻẽẹêềếểễệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïīIÌÍỈĨỊÎÏĪ","lłLŁ","nñňńNÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøōOÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rřRŘ","sšśșşSŠŚȘŞ","tťțţTŤȚŢ","uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿYÝỲỶỸỴŸ","zžżźZŽŻŹ"];let n=[];return e.split("").forEach(a=>{r.every(i=>{if(i.indexOf(a)!==-1){if(n.indexOf(i)>-1)return!1;e=e.replace(new RegExp(`[${i}]`,`gm${t}`),`[${i}]`),n.push(i)}return!0})}),e}createMergedBlanksRegExp(e){return e.replace(/[\s]+/gmi,"[\\s]+")}createAccuracyRegExp(e){const t="!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~¡¿";let r=this.opt.accuracy,n=typeof r=="string"?r:r.value,a=typeof r=="string"?[]:r.limiters,i="";switch(a.forEach(s=>{i+=`|${this.escapeStr(s)}`}),n){case"partially":default:return`()(${e})`;case"complementary":return i="\\s"+(i||this.escapeStr(t)),`()([^${i}]*${e}[^${i}]*)`;case"exactly":return`(^|\\s${i})(${e})(?=$|\\s${i})`}}getSeparatedKeywords(e){let t=[];return e.forEach(r=>{this.opt.separateWordSearch?r.split(" ").forEach(n=>{n.trim()&&t.indexOf(n)===-1&&t.push(n)}):r.trim()&&t.indexOf(r)===-1&&t.push(r)}),{keywords:t.sort((r,n)=>n.length-r.length),length:t.length}}isNumeric(e){return Number(parseFloat(e))==e}checkRanges(e){if(!Array.isArray(e)||Object.prototype.toString.call(e[0])!=="[object Object]")return this.log("markRanges() will only accept an array of objects"),this.opt.noMatch(e),[];const t=[];let r=0;return e.sort((n,a)=>n.start-a.start).forEach(n=>{let{start:a,end:i,valid:s}=this.callNoMatchOnInvalidRanges(n,r);s&&(n.start=a,n.length=i-a,t.push(n),r=i)}),t}callNoMatchOnInvalidRanges(e,t){let r,n,a=!1;return e&&typeof e.start<"u"?(r=parseInt(e.start,10),n=r+parseInt(e.length,10),this.isNumeric(e.start)&&this.isNumeric(e.length)&&n-t>0&&n-r>0?a=!0:(this.log(`Ignoring invalid or overlapping range: ${JSON.stringify(e)}`),this.opt.noMatch(e))):(this.log(`Ignoring invalid range: ${JSON.stringify(e)}`),this.opt.noMatch(e)),{start:r,end:n,valid:a}}checkWhitespaceRanges(e,t,r){let n,a=!0,i=r.length,s=t-i,u=parseInt(e.start,10)-s;return u=u>i?i:u,n=u+parseInt(e.length,10),n>i&&(n=i,this.log(`End range automatically set to the max value of ${i}`)),u<0||n-u<0||u>i||n>i?(a=!1,this.log(`Invalid range: ${JSON.stringify(e)}`),this.opt.noMatch(e)):r.substring(u,n).replace(/\s+/g,"")===""&&(a=!1,this.log("Skipping whitespace only range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:u,end:n,valid:a}}getTextNodes(e){let t="",r=[];this.iterator.forEachNode(NodeFilter.SHOW_TEXT,n=>{r.push({start:t.length,end:(t+=n.textContent).length,node:n})},n=>this.matchesExclude(n.parentNode)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT,()=>{e({value:t,nodes:r})})}matchesExclude(e){return ce.matches(e,this.opt.exclude.concat(["script","style","title","head","html"]))}wrapRangeInTextNode(e,t,r){const n=this.opt.element?this.opt.element:"mark",a=e.splitText(t),i=a.splitText(r-t);let s=document.createElement(n);return s.setAttribute("data-markjs","true"),this.opt.className&&s.setAttribute("class",this.opt.className),s.textContent=a.textContent,a.parentNode.replaceChild(s,a),i}wrapRangeInMappedTextNode(e,t,r,n,a){e.nodes.every((i,s)=>{const u=e.nodes[s+1];if(typeof u>"u"||u.start>t){if(!n(i.node))return!1;const l=t-i.start,d=(r>i.end?i.end:r)-i.start,h=e.value.substr(0,i.start),v=e.value.substr(d+i.start);if(i.node=this.wrapRangeInTextNode(i.node,l,d),e.value=h+v,e.nodes.forEach((m,g)=>{g>=s&&(e.nodes[g].start>0&&g!==s&&(e.nodes[g].start-=d),e.nodes[g].end-=d)}),r-=d,a(i.node.previousSibling,i.start),r>i.end)t=i.end;else return!1}return!0})}wrapMatches(e,t,r,n,a){const i=t===0?0:t+1;this.getTextNodes(s=>{s.nodes.forEach(u=>{u=u.node;let l;for(;(l=e.exec(u.textContent))!==null&&l[i]!=="";){if(!r(l[i],u))continue;let d=l.index;if(i!==0)for(let h=1;h{let u;for(;(u=e.exec(s.value))!==null&&u[i]!=="";){let l=u.index;if(i!==0)for(let h=1;hr(u[i],h),(h,v)=>{e.lastIndex=v,n(h)})}a()})}wrapRangeFromIndex(e,t,r,n){this.getTextNodes(a=>{const i=a.value.length;e.forEach((s,u)=>{let{start:l,end:d,valid:h}=this.checkWhitespaceRanges(s,i,a.value);h&&this.wrapRangeInMappedTextNode(a,l,d,v=>t(v,s,a.value.substring(l,d),u),v=>{r(v,s)})}),n()})}unwrapMatches(e){const t=e.parentNode;let r=document.createDocumentFragment();for(;e.firstChild;)r.appendChild(e.removeChild(e.firstChild));t.replaceChild(r,e),this.ie?this.normalizeTextNode(t):t.normalize()}normalizeTextNode(e){if(e){if(e.nodeType===3)for(;e.nextSibling&&e.nextSibling.nodeType===3;)e.nodeValue+=e.nextSibling.nodeValue,e.parentNode.removeChild(e.nextSibling);else this.normalizeTextNode(e.firstChild);this.normalizeTextNode(e.nextSibling)}}markRegExp(e,t){this.opt=t,this.log(`Searching with expression "${e}"`);let r=0,n="wrapMatches";const a=i=>{r++,this.opt.each(i)};this.opt.acrossElements&&(n="wrapMatchesAcrossElements"),this[n](e,this.opt.ignoreGroups,(i,s)=>this.opt.filter(s,i,r),a,()=>{r===0&&this.opt.noMatch(e),this.opt.done(r)})}mark(e,t){this.opt=t;let r=0,n="wrapMatches";const{keywords:a,length:i}=this.getSeparatedKeywords(typeof e=="string"?[e]:e),s=this.opt.caseSensitive?"":"i",u=l=>{let d=new RegExp(this.createRegExp(l),`gm${s}`),h=0;this.log(`Searching with expression "${d}"`),this[n](d,1,(v,m)=>this.opt.filter(m,l,r,h),v=>{h++,r++,this.opt.each(v)},()=>{h===0&&this.opt.noMatch(l),a[i-1]===l?this.opt.done(r):u(a[a.indexOf(l)+1])})};this.opt.acrossElements&&(n="wrapMatchesAcrossElements"),i===0?this.opt.done(r):u(a[0])}markRanges(e,t){this.opt=t;let r=0,n=this.checkRanges(e);n&&n.length?(this.log("Starting to mark with the following ranges: "+JSON.stringify(n)),this.wrapRangeFromIndex(n,(a,i,s,u)=>this.opt.filter(a,i,s,u),(a,i)=>{r++,this.opt.each(a,i)},()=>{this.opt.done(r)})):this.opt.done(r)}unmark(e){this.opt=e;let t=this.opt.element?this.opt.element:"*";t+="[data-markjs]",this.opt.className&&(t+=`.${this.opt.className}`),this.log(`Removal selector "${t}"`),this.iterator.forEachNode(NodeFilter.SHOW_ELEMENT,r=>{this.unwrapMatches(r)},r=>{const n=ce.matches(r,t),a=this.matchesExclude(r);return!n||a?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT},this.opt.done)}};function Or(o){const e=new kr(o);return this.mark=(t,r)=>(e.mark(t,r),this),this.markRegExp=(t,r)=>(e.markRegExp(t,r),this),this.markRanges=(t,r)=>(e.markRanges(t,r),this),this.unmark=t=>(e.unmark(t),this),this}var $=function(){return $=Object.assign||function(e){for(var t,r=1,n=arguments.length;r0&&a[a.length-1])&&(l[0]===6||l[0]===2)){t=0;continue}if(l[0]===3&&(!a||l[1]>a[0]&&l[1]=o.length&&(o=void 0),{value:o&&o[r++],done:!o}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")}function W(o,e){var t=typeof Symbol=="function"&&o[Symbol.iterator];if(!t)return o;var r=t.call(o),n,a=[],i;try{for(;(e===void 0||e-- >0)&&!(n=r.next()).done;)a.push(n.value)}catch(s){i={error:s}}finally{try{n&&!n.done&&(t=r.return)&&t.call(r)}finally{if(i)throw i.error}}return a}var Mr="ENTRIES",xt="KEYS",Ft="VALUES",Q="",_e=function(){function o(e,t){var r=e._tree,n=Array.from(r.keys());this.set=e,this._type=t,this._path=n.length>0?[{node:r,keys:n}]:[]}return o.prototype.next=function(){var e=this.dive();return this.backtrack(),e},o.prototype.dive=function(){if(this._path.length===0)return{done:!0,value:void 0};var e=le(this._path),t=e.node,r=e.keys;if(le(r)===Q)return{done:!1,value:this.result()};var n=t.get(le(r));return this._path.push({node:n,keys:Array.from(n.keys())}),this.dive()},o.prototype.backtrack=function(){if(this._path.length!==0){var e=le(this._path).keys;e.pop(),!(e.length>0)&&(this._path.pop(),this.backtrack())}},o.prototype.key=function(){return this.set._prefix+this._path.map(function(e){var t=e.keys;return le(t)}).filter(function(e){return e!==Q}).join("")},o.prototype.value=function(){return le(this._path).node.get(Q)},o.prototype.result=function(){switch(this._type){case Ft:return this.value();case xt:return this.key();default:return[this.key(),this.value()]}},o.prototype[Symbol.iterator]=function(){return this},o}(),le=function(o){return o[o.length-1]},Lr=function(o,e,t){var r=new Map;if(e===void 0)return r;for(var n=e.length+1,a=n+t,i=new Uint8Array(a*n).fill(t+1),s=0;st)continue e}Et(o.get(m),e,t,r,n,b,i,s+m)}}}catch(c){u={error:c}}finally{try{v&&!v.done&&(l=h.return)&&l.call(h)}finally{if(u)throw u.error}}},Me=function(){function o(e,t){e===void 0&&(e=new Map),t===void 0&&(t=""),this._size=void 0,this._tree=e,this._prefix=t}return o.prototype.atPrefix=function(e){var t,r;if(!e.startsWith(this._prefix))throw new Error("Mismatched prefix");var n=W(De(this._tree,e.slice(this._prefix.length)),2),a=n[0],i=n[1];if(a===void 0){var s=W(Ue(i),2),u=s[0],l=s[1];try{for(var d=D(u.keys()),h=d.next();!h.done;h=d.next()){var v=h.value;if(v!==Q&&v.startsWith(l)){var m=new Map;return m.set(v.slice(l.length),u.get(v)),new o(m,e)}}}catch(g){t={error:g}}finally{try{h&&!h.done&&(r=d.return)&&r.call(d)}finally{if(t)throw t.error}}}return new o(a,e)},o.prototype.clear=function(){this._size=void 0,this._tree.clear()},o.prototype.delete=function(e){return this._size=void 0,Pr(this._tree,e)},o.prototype.entries=function(){return new _e(this,Mr)},o.prototype.forEach=function(e){var t,r;try{for(var n=D(this),a=n.next();!a.done;a=n.next()){var i=W(a.value,2),s=i[0],u=i[1];e(s,u,this)}}catch(l){t={error:l}}finally{try{a&&!a.done&&(r=n.return)&&r.call(n)}finally{if(t)throw t.error}}},o.prototype.fuzzyGet=function(e,t){return Lr(this._tree,e,t)},o.prototype.get=function(e){var t=We(this._tree,e);return t!==void 0?t.get(Q):void 0},o.prototype.has=function(e){var t=We(this._tree,e);return t!==void 0&&t.has(Q)},o.prototype.keys=function(){return new _e(this,xt)},o.prototype.set=function(e,t){if(typeof e!="string")throw new Error("key must be a string");this._size=void 0;var r=Le(this._tree,e);return r.set(Q,t),this},Object.defineProperty(o.prototype,"size",{get:function(){if(this._size)return this._size;this._size=0;for(var e=this.entries();!e.next().done;)this._size+=1;return this._size},enumerable:!1,configurable:!0}),o.prototype.update=function(e,t){if(typeof e!="string")throw new Error("key must be a string");this._size=void 0;var r=Le(this._tree,e);return r.set(Q,t(r.get(Q))),this},o.prototype.fetch=function(e,t){if(typeof e!="string")throw new Error("key must be a string");this._size=void 0;var r=Le(this._tree,e),n=r.get(Q);return n===void 0&&r.set(Q,n=t()),n},o.prototype.values=function(){return new _e(this,Ft)},o.prototype[Symbol.iterator]=function(){return this.entries()},o.from=function(e){var t,r,n=new o;try{for(var a=D(e),i=a.next();!i.done;i=a.next()){var s=W(i.value,2),u=s[0],l=s[1];n.set(u,l)}}catch(d){t={error:d}}finally{try{i&&!i.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}return n},o.fromObject=function(e){return o.from(Object.entries(e))},o}(),De=function(o,e,t){var r,n;if(t===void 0&&(t=[]),e.length===0||o==null)return[o,t];try{for(var a=D(o.keys()),i=a.next();!i.done;i=a.next()){var s=i.value;if(s!==Q&&e.startsWith(s))return t.push([o,s]),De(o.get(s),e.slice(s.length),t)}}catch(u){r={error:u}}finally{try{i&&!i.done&&(n=a.return)&&n.call(a)}finally{if(r)throw r.error}}return t.push([o,e]),De(void 0,"",t)},We=function(o,e){var t,r;if(e.length===0||o==null)return o;try{for(var n=D(o.keys()),a=n.next();!a.done;a=n.next()){var i=a.value;if(i!==Q&&e.startsWith(i))return We(o.get(i),e.slice(i.length))}}catch(s){t={error:s}}finally{try{a&&!a.done&&(r=n.return)&&r.call(n)}finally{if(t)throw t.error}}},Le=function(o,e){var t,r,n=e.length;e:for(var a=0;o&&a0)throw new Error("Expected documents to be present. Omit the argument to remove all documents.");this._index=new Me,this._documentCount=0,this._documentIds=new Map,this._idToShortId=new Map,this._fieldLength=new Map,this._avgFieldLength=[],this._storedFields=new Map,this._nextId=0}},o.prototype.discard=function(e){var t=this,r=this._idToShortId.get(e);if(r==null)throw new Error("MiniSearch: cannot discard document with ID ".concat(e,": it is not in the index"));this._idToShortId.delete(e),this._documentIds.delete(r),this._storedFields.delete(r),(this._fieldLength.get(r)||[]).forEach(function(n,a){t.removeFieldLength(r,a,t._documentCount,n)}),this._fieldLength.delete(r),this._documentCount-=1,this._dirtCount+=1,this.maybeAutoVacuum()},o.prototype.maybeAutoVacuum=function(){if(this._options.autoVacuum!==!1){var e=this._options.autoVacuum,t=e.minDirtFactor,r=e.minDirtCount,n=e.batchSize,a=e.batchWait;this.conditionalVacuum({batchSize:n,batchWait:a},{minDirtCount:r,minDirtFactor:t})}},o.prototype.discardAll=function(e){var t,r,n=this._options.autoVacuum;try{this._options.autoVacuum=!1;try{for(var a=D(e),i=a.next();!i.done;i=a.next()){var s=i.value;this.discard(s)}}catch(u){t={error:u}}finally{try{i&&!i.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}}finally{this._options.autoVacuum=n}this.maybeAutoVacuum()},o.prototype.replace=function(e){var t=this._options,r=t.idField,n=t.extractField,a=n(e,r);this.discard(a),this.add(e)},o.prototype.vacuum=function(e){return e===void 0&&(e={}),this.conditionalVacuum(e)},o.prototype.conditionalVacuum=function(e,t){var r=this;return this._currentVacuum?(this._enqueuedVacuumConditions=this._enqueuedVacuumConditions&&t,this._enqueuedVacuum!=null?this._enqueuedVacuum:(this._enqueuedVacuum=this._currentVacuum.then(function(){var n=r._enqueuedVacuumConditions;return r._enqueuedVacuumConditions=Je,r.performVacuuming(e,n)}),this._enqueuedVacuum)):this.vacuumConditionsMet(t)===!1?Promise.resolve():(this._currentVacuum=this.performVacuuming(e),this._currentVacuum)},o.prototype.performVacuuming=function(e,t){return Rr(this,void 0,void 0,function(){var r,n,a,i,s,u,l,d,h,v,m,g,b,x,S,T,A,_,L,P,I,E,O,R,F;return _r(this,function(f){switch(f.label){case 0:if(r=this._dirtCount,!this.vacuumConditionsMet(t))return[3,10];n=e.batchSize||Ke.batchSize,a=e.batchWait||Ke.batchWait,i=1,f.label=1;case 1:f.trys.push([1,7,8,9]),s=D(this._index),u=s.next(),f.label=2;case 2:if(u.done)return[3,6];l=W(u.value,2),d=l[0],h=l[1];try{for(v=(E=void 0,D(h)),m=v.next();!m.done;m=v.next()){g=W(m.value,2),b=g[0],x=g[1];try{for(S=(R=void 0,D(x)),T=S.next();!T.done;T=S.next())A=W(T.value,1),_=A[0],!this._documentIds.has(_)&&(x.size<=1?h.delete(b):x.delete(_))}catch(c){R={error:c}}finally{try{T&&!T.done&&(F=S.return)&&F.call(S)}finally{if(R)throw R.error}}}}catch(c){E={error:c}}finally{try{m&&!m.done&&(O=v.return)&&O.call(v)}finally{if(E)throw E.error}}return this._index.get(d).size===0&&this._index.delete(d),i%n!==0?[3,4]:[4,new Promise(function(c){return setTimeout(c,a)})];case 3:f.sent(),f.label=4;case 4:i+=1,f.label=5;case 5:return u=s.next(),[3,2];case 6:return[3,9];case 7:return L=f.sent(),P={error:L},[3,9];case 8:try{u&&!u.done&&(I=s.return)&&I.call(s)}finally{if(P)throw P.error}return[7];case 9:this._dirtCount-=r,f.label=10;case 10:return[4,null];case 11:return f.sent(),this._currentVacuum=this._enqueuedVacuum,this._enqueuedVacuum=null,[2]}})})},o.prototype.vacuumConditionsMet=function(e){if(e==null)return!0;var t=e.minDirtCount,r=e.minDirtFactor;return t=t||Ve.minDirtCount,r=r||Ve.minDirtFactor,this.dirtCount>=t&&this.dirtFactor>=r},Object.defineProperty(o.prototype,"isVacuuming",{get:function(){return this._currentVacuum!=null},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"dirtCount",{get:function(){return this._dirtCount},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"dirtFactor",{get:function(){return this._dirtCount/(1+this._documentCount+this._dirtCount)},enumerable:!1,configurable:!0}),o.prototype.has=function(e){return this._idToShortId.has(e)},o.prototype.getStoredFields=function(e){var t=this._idToShortId.get(e);if(t!=null)return this._storedFields.get(t)},o.prototype.search=function(e,t){var r,n;t===void 0&&(t={});var a=this.executeQuery(e,t),i=[];try{for(var s=D(a),u=s.next();!u.done;u=s.next()){var l=W(u.value,2),d=l[0],h=l[1],v=h.score,m=h.terms,g=h.match,b=m.length||1,x={id:this._documentIds.get(d),score:v*b,terms:Object.keys(g),queryTerms:m,match:g};Object.assign(x,this._storedFields.get(d)),(t.filter==null||t.filter(x))&&i.push(x)}}catch(S){r={error:S}}finally{try{u&&!u.done&&(n=s.return)&&n.call(s)}finally{if(r)throw r.error}}return e===o.wildcard&&t.boostDocument==null&&this._options.searchOptions.boostDocument==null||i.sort(dt),i},o.prototype.autoSuggest=function(e,t){var r,n,a,i;t===void 0&&(t={}),t=$($({},this._options.autoSuggestOptions),t);var s=new Map;try{for(var u=D(this.search(e,t)),l=u.next();!l.done;l=u.next()){var d=l.value,h=d.score,v=d.terms,m=v.join(" "),g=s.get(m);g!=null?(g.score+=h,g.count+=1):s.set(m,{score:h,terms:v,count:1})}}catch(L){r={error:L}}finally{try{l&&!l.done&&(n=u.return)&&n.call(u)}finally{if(r)throw r.error}}var b=[];try{for(var x=D(s),S=x.next();!S.done;S=x.next()){var T=W(S.value,2),g=T[0],A=T[1],h=A.score,v=A.terms,_=A.count;b.push({suggestion:g,terms:v,score:h/_})}}catch(L){a={error:L}}finally{try{S&&!S.done&&(i=x.return)&&i.call(x)}finally{if(a)throw a.error}}return b.sort(dt),b},Object.defineProperty(o.prototype,"documentCount",{get:function(){return this._documentCount},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"termCount",{get:function(){return this._index.size},enumerable:!1,configurable:!0}),o.loadJSON=function(e,t){if(t==null)throw new Error("MiniSearch: loadJSON should be given the same options used when serializing the index");return this.loadJS(JSON.parse(e),t)},o.getDefault=function(e){if(ze.hasOwnProperty(e))return Pe(ze,e);throw new Error('MiniSearch: unknown option "'.concat(e,'"'))},o.loadJS=function(e,t){var r,n,a,i,s,u,l=e.index,d=e.documentCount,h=e.nextId,v=e.documentIds,m=e.fieldIds,g=e.fieldLength,b=e.averageFieldLength,x=e.storedFields,S=e.dirtCount,T=e.serializationVersion;if(T!==1&&T!==2)throw new Error("MiniSearch: cannot deserialize an index created with an incompatible version");var A=new o(t);A._documentCount=d,A._nextId=h,A._documentIds=Ae(v),A._idToShortId=new Map,A._fieldIds=m,A._fieldLength=Ae(g),A._avgFieldLength=b,A._storedFields=Ae(x),A._dirtCount=S||0,A._index=new Me;try{for(var _=D(A._documentIds),L=_.next();!L.done;L=_.next()){var P=W(L.value,2),I=P[0],E=P[1];A._idToShortId.set(E,I)}}catch(y){r={error:y}}finally{try{L&&!L.done&&(n=_.return)&&n.call(_)}finally{if(r)throw r.error}}try{for(var O=D(l),R=O.next();!R.done;R=O.next()){var F=W(R.value,2),f=F[0],c=F[1],p=new Map;try{for(var C=(s=void 0,D(Object.keys(c))),N=C.next();!N.done;N=C.next()){var M=N.value,z=c[M];T===1&&(z=z.ds),p.set(parseInt(M,10),Ae(z))}}catch(y){s={error:y}}finally{try{N&&!N.done&&(u=C.return)&&u.call(C)}finally{if(s)throw s.error}}A._index.set(f,p)}}catch(y){a={error:y}}finally{try{R&&!R.done&&(i=O.return)&&i.call(O)}finally{if(a)throw a.error}}return A},o.prototype.executeQuery=function(e,t){var r=this;if(t===void 0&&(t={}),e===o.wildcard)return this.executeWildcardQuery(t);if(typeof e!="string"){var n=$($($({},t),e),{queries:void 0}),a=e.queries.map(function(x){return r.executeQuery(x,n)});return this.combineResults(a,n.combineWith)}var i=this._options,s=i.tokenize,u=i.processTerm,l=i.searchOptions,d=$($({tokenize:s,processTerm:u},l),t),h=d.tokenize,v=d.processTerm,m=h(e).flatMap(function(x){return v(x)}).filter(function(x){return!!x}),g=m.map(Kr(d)),b=g.map(function(x){return r.executeQuerySpec(x,d)});return this.combineResults(b,d.combineWith)},o.prototype.executeQuerySpec=function(e,t){var r,n,a,i,s=$($({},this._options.searchOptions),t),u=(s.fields||this._options.fields).reduce(function(M,z){var y;return $($({},M),(y={},y[z]=Pe(s.boost,z)||1,y))},{}),l=s.boostDocument,d=s.weights,h=s.maxFuzzy,v=s.bm25,m=$($({},ft.weights),d),g=m.fuzzy,b=m.prefix,x=this._index.get(e.term),S=this.termResults(e.term,e.term,1,x,u,l,v),T,A;if(e.prefix&&(T=this._index.atPrefix(e.term)),e.fuzzy){var _=e.fuzzy===!0?.2:e.fuzzy,L=_<1?Math.min(h,Math.round(e.term.length*_)):_;L&&(A=this._index.fuzzyGet(e.term,L))}if(T)try{for(var P=D(T),I=P.next();!I.done;I=P.next()){var E=W(I.value,2),O=E[0],R=E[1],F=O.length-e.term.length;if(F){A==null||A.delete(O);var f=b*O.length/(O.length+.3*F);this.termResults(e.term,O,f,R,u,l,v,S)}}}catch(M){r={error:M}}finally{try{I&&!I.done&&(n=P.return)&&n.call(P)}finally{if(r)throw r.error}}if(A)try{for(var c=D(A.keys()),p=c.next();!p.done;p=c.next()){var O=p.value,C=W(A.get(O),2),N=C[0],F=C[1];if(F){var f=g*O.length/(O.length+F);this.termResults(e.term,O,f,N,u,l,v,S)}}}catch(M){a={error:M}}finally{try{p&&!p.done&&(i=c.return)&&i.call(c)}finally{if(a)throw a.error}}return S},o.prototype.executeWildcardQuery=function(e){var t,r,n=new Map,a=$($({},this._options.searchOptions),e);try{for(var i=D(this._documentIds),s=i.next();!s.done;s=i.next()){var u=W(s.value,2),l=u[0],d=u[1],h=a.boostDocument?a.boostDocument(d,"",this._storedFields.get(l)):1;n.set(l,{score:h,terms:[],match:{}})}}catch(v){t={error:v}}finally{try{s&&!s.done&&(r=i.return)&&r.call(i)}finally{if(t)throw t.error}}return n},o.prototype.combineResults=function(e,t){if(t===void 0&&(t=je),e.length===0)return new Map;var r=t.toLowerCase();return e.reduce(Br[r])||new Map},o.prototype.toJSON=function(){var e,t,r,n,a=[];try{for(var i=D(this._index),s=i.next();!s.done;s=i.next()){var u=W(s.value,2),l=u[0],d=u[1],h={};try{for(var v=(r=void 0,D(d)),m=v.next();!m.done;m=v.next()){var g=W(m.value,2),b=g[0],x=g[1];h[b]=Object.fromEntries(x)}}catch(S){r={error:S}}finally{try{m&&!m.done&&(n=v.return)&&n.call(v)}finally{if(r)throw r.error}}a.push([l,h])}}catch(S){e={error:S}}finally{try{s&&!s.done&&(t=i.return)&&t.call(i)}finally{if(e)throw e.error}}return{documentCount:this._documentCount,nextId:this._nextId,documentIds:Object.fromEntries(this._documentIds),fieldIds:this._fieldIds,fieldLength:Object.fromEntries(this._fieldLength),averageFieldLength:this._avgFieldLength,storedFields:Object.fromEntries(this._storedFields),dirtCount:this._dirtCount,index:a,serializationVersion:2}},o.prototype.termResults=function(e,t,r,n,a,i,s,u){var l,d,h,v,m;if(u===void 0&&(u=new Map),n==null)return u;try{for(var g=D(Object.keys(a)),b=g.next();!b.done;b=g.next()){var x=b.value,S=a[x],T=this._fieldIds[x],A=n.get(T);if(A!=null){var _=A.size,L=this._avgFieldLength[T];try{for(var P=(h=void 0,D(A.keys())),I=P.next();!I.done;I=P.next()){var E=I.value;if(!this._documentIds.has(E)){this.removeTerm(T,E,t),_-=1;continue}var O=i?i(this._documentIds.get(E),t,this._storedFields.get(E)):1;if(O){var R=A.get(E),F=this._fieldLength.get(E)[T],f=Wr(R,_,this._documentCount,F,L,s),c=r*S*O*f,p=u.get(E);if(p){p.score+=c,Ur(p.terms,e);var C=Pe(p.match,t);C?C.push(x):p.match[t]=[x]}else u.set(E,{score:c,terms:[e],match:(m={},m[t]=[x],m)})}}}catch(N){h={error:N}}finally{try{I&&!I.done&&(v=P.return)&&v.call(P)}finally{if(h)throw h.error}}}}}catch(N){l={error:N}}finally{try{b&&!b.done&&(d=g.return)&&d.call(g)}finally{if(l)throw l.error}}return u},o.prototype.addTerm=function(e,t,r){var n=this._index.fetch(r,vt),a=n.get(e);if(a==null)a=new Map,a.set(t,1),n.set(e,a);else{var i=a.get(t);a.set(t,(i||0)+1)}},o.prototype.removeTerm=function(e,t,r){if(!this._index.has(r)){this.warnDocumentChanged(t,e,r);return}var n=this._index.fetch(r,vt),a=n.get(e);a==null||a.get(t)==null?this.warnDocumentChanged(t,e,r):a.get(t)<=1?a.size<=1?n.delete(e):a.delete(t):a.set(t,a.get(t)-1),this._index.get(r).size===0&&this._index.delete(r)},o.prototype.warnDocumentChanged=function(e,t,r){var n,a;try{for(var i=D(Object.keys(this._fieldIds)),s=i.next();!s.done;s=i.next()){var u=s.value;if(this._fieldIds[u]===t){this._options.logger("warn","MiniSearch: document with ID ".concat(this._documentIds.get(e),' has changed before removal: term "').concat(r,'" was not present in field "').concat(u,'". Removing a document after it has changed can corrupt the index!'),"version_conflict");return}}}catch(l){n={error:l}}finally{try{s&&!s.done&&(a=i.return)&&a.call(i)}finally{if(n)throw n.error}}},o.prototype.addDocumentId=function(e){var t=this._nextId;return this._idToShortId.set(e,t),this._documentIds.set(t,e),this._documentCount+=1,this._nextId+=1,t},o.prototype.addFields=function(e){for(var t=0;t(Qt("data-v-639d7ab9"),o=o(),Ht(),o),Qr=["aria-owns"],Hr={class:"shell"},qr=["title"],Yr=Y(()=>k("span",{"aria-hidden":"true",class:"vpi-search search-icon local-search-icon"},null,-1)),Zr=[Yr],Xr={class:"search-actions before"},ea=["title"],ta=Y(()=>k("span",{class:"vpi-arrow-left local-search-icon"},null,-1)),ra=[ta],aa=["placeholder"],na={class:"search-actions"},ia=["title"],oa=Y(()=>k("span",{class:"vpi-layout-list local-search-icon"},null,-1)),sa=[oa],ua=["disabled","title"],la=Y(()=>k("span",{class:"vpi-delete local-search-icon"},null,-1)),ca=[la],fa=["id","role","aria-labelledby"],ha=["aria-selected"],da=["href","aria-label","onMouseenter","onFocusin"],va={class:"titles"},pa=Y(()=>k("span",{class:"title-icon"},"#",-1)),ya=["innerHTML"],ma=Y(()=>k("span",{class:"vpi-chevron-right local-search-icon"},null,-1)),ga={class:"title main"},ba=["innerHTML"],wa={key:0,class:"excerpt-wrapper"},xa={key:0,class:"excerpt",inert:""},Fa=["innerHTML"],Ea=Y(()=>k("div",{class:"excerpt-gradient-bottom"},null,-1)),Sa=Y(()=>k("div",{class:"excerpt-gradient-top"},null,-1)),Aa={key:0,class:"no-results"},Ta={class:"search-keyboard-shortcuts"},Na=["aria-label"],Ca=Y(()=>k("span",{class:"vpi-arrow-up navigate-icon"},null,-1)),Ia=[Ca],Da=["aria-label"],ka=Y(()=>k("span",{class:"vpi-arrow-down navigate-icon"},null,-1)),Oa=[ka],Ra=["aria-label"],_a=Y(()=>k("span",{class:"vpi-corner-down-left navigate-icon"},null,-1)),Ma=[_a],La=["aria-label"],Pa=Ot({__name:"VPLocalSearchBox",emits:["close"],setup(o,{emit:e}){var M,z;const t=we(),r=we(),n=we(ar),a=tr(),{activate:i}=Dr(t,{immediate:!0,allowOutsideClick:!0,clickOutsideDeactivates:!0,escapeDeactivates:!0}),{localeIndex:s,theme:u}=a,l=et(async()=>{var y,w,V,U,K,J,B,j,H;return nt(Vr.loadJSON((V=await((w=(y=n.value)[s.value])==null?void 0:w.call(y)))==null?void 0:V.default,{fields:["title","titles","text"],storeFields:["title","titles"],searchOptions:{fuzzy:.2,prefix:!0,boost:{title:4,text:2,titles:1},...((U=u.value.search)==null?void 0:U.provider)==="local"&&((J=(K=u.value.search.options)==null?void 0:K.miniSearch)==null?void 0:J.searchOptions)},...((B=u.value.search)==null?void 0:B.provider)==="local"&&((H=(j=u.value.search.options)==null?void 0:j.miniSearch)==null?void 0:H.options)}))}),h=xe(()=>{var y,w;return((y=u.value.search)==null?void 0:y.provider)==="local"&&((w=u.value.search.options)==null?void 0:w.disableQueryPersistence)===!0}).value?ie(""):Rt("vitepress:local-search-filter",""),v=_t("vitepress:local-search-detailed-list",((M=u.value.search)==null?void 0:M.provider)==="local"&&((z=u.value.search.options)==null?void 0:z.detailedView)===!0),m=xe(()=>{var y,w,V;return((y=u.value.search)==null?void 0:y.provider)==="local"&&(((w=u.value.search.options)==null?void 0:w.disableDetailedView)===!0||((V=u.value.search.options)==null?void 0:V.detailedView)===!1)}),g=xe(()=>{var w,V,U,K,J,B,j;const y=((w=u.value.search)==null?void 0:w.options)??u.value.algolia;return((J=(K=(U=(V=y==null?void 0:y.locales)==null?void 0:V[s.value])==null?void 0:U.translations)==null?void 0:K.button)==null?void 0:J.buttonText)||((j=(B=y==null?void 0:y.translations)==null?void 0:B.button)==null?void 0:j.buttonText)||"Search"});Mt(()=>{m.value&&(v.value=!1)});const b=we([]),x=ie(!1);Be(h,()=>{x.value=!1});const S=et(async()=>{if(r.value)return nt(new Or(r.value))},null),T=new Gr(16);Lt(()=>[l.value,h.value,v.value],async([y,w,V],U,K)=>{var ge,Ge,Qe,He;(U==null?void 0:U[0])!==y&&T.clear();let J=!1;if(K(()=>{J=!0}),!y)return;b.value=y.search(w).slice(0,16),x.value=!0;const B=V?await Promise.all(b.value.map(q=>A(q.id))):[];if(J)return;for(const{id:q,mod:re}of B){const ae=q.slice(0,q.indexOf("#"));let ee=T.get(ae);if(ee)continue;ee=new Map,T.set(ae,ee);const Z=re.default??re;if(Z!=null&&Z.render||Z!=null&&Z.setup){const ne=qt(Z);ne.config.warnHandler=()=>{},ne.provide(Yt,a),Object.defineProperties(ne.config.globalProperties,{$frontmatter:{get(){return a.frontmatter.value}},$params:{get(){return a.page.value.params}}});const qe=document.createElement("div");ne.mount(qe),qe.querySelectorAll("h1, h2, h3, h4, h5, h6").forEach(fe=>{var Xe;const be=(Xe=fe.querySelector("a"))==null?void 0:Xe.getAttribute("href"),Ye=(be==null?void 0:be.startsWith("#"))&&be.slice(1);if(!Ye)return;let Ze="";for(;(fe=fe.nextElementSibling)&&!/^h[1-6]$/i.test(fe.tagName);)Ze+=fe.outerHTML;ee.set(Ye,Ze)}),ne.unmount()}if(J)return}const j=new Set;if(b.value=b.value.map(q=>{const[re,ae]=q.id.split("#"),ee=T.get(re),Z=(ee==null?void 0:ee.get(ae))??"";for(const ne in q.match)j.add(ne);return{...q,text:Z}}),await he(),J)return;await new Promise(q=>{var re;(re=S.value)==null||re.unmark({done:()=>{var ae;(ae=S.value)==null||ae.markRegExp(N(j),{done:q})}})});const H=((ge=t.value)==null?void 0:ge.querySelectorAll(".result .excerpt"))??[];for(const q of H)(Ge=q.querySelector('mark[data-markjs="true"]'))==null||Ge.scrollIntoView({block:"center"});(He=(Qe=r.value)==null?void 0:Qe.firstElementChild)==null||He.scrollIntoView({block:"start"})},{debounce:200,immediate:!0});async function A(y){const w=Zt(y.slice(0,y.indexOf("#")));try{if(!w)throw new Error(`Cannot find file for id: ${y}`);return{id:y,mod:await import(w)}}catch(V){return console.error(V),{id:y,mod:{}}}}const _=ie(),L=xe(()=>{var y;return((y=h.value)==null?void 0:y.length)<=0});function P(y=!0){var w,V;(w=_.value)==null||w.focus(),y&&((V=_.value)==null||V.select())}Oe(()=>{P()});function I(y){y.pointerType==="mouse"&&P()}const E=ie(-1),O=ie(!1);Be(b,y=>{E.value=y.length?0:-1,R()});function R(){he(()=>{const y=document.querySelector(".result.selected");y==null||y.scrollIntoView({block:"nearest"})})}Fe("ArrowUp",y=>{y.preventDefault(),E.value--,E.value<0&&(E.value=b.value.length-1),O.value=!0,R()}),Fe("ArrowDown",y=>{y.preventDefault(),E.value++,E.value>=b.value.length&&(E.value=0),O.value=!0,R()});const F=Pt();Fe("Enter",y=>{if(y.isComposing||y.target instanceof HTMLButtonElement&&y.target.type!=="submit")return;const w=b.value[E.value];if(y.target instanceof HTMLInputElement&&!w){y.preventDefault();return}w&&(F.go(w.id),e("close"))}),Fe("Escape",()=>{e("close")});const c=rr({modal:{displayDetails:"Display detailed list",resetButtonTitle:"Reset search",backButtonTitle:"Close search",noResultsText:"No results for",footer:{selectText:"to select",selectKeyAriaLabel:"enter",navigateText:"to navigate",navigateUpKeyAriaLabel:"up arrow",navigateDownKeyAriaLabel:"down arrow",closeText:"to close",closeKeyAriaLabel:"escape"}}});Oe(()=>{window.history.pushState(null,"",null)}),zt("popstate",y=>{y.preventDefault(),e("close")});const p=Vt(Bt?document.body:null);Oe(()=>{he(()=>{p.value=!0,he().then(()=>i())})}),$t(()=>{p.value=!1});function C(){h.value="",he().then(()=>P(!1))}function N(y){return new RegExp([...y].sort((w,V)=>V.length-w.length).map(w=>`(${Xt(w)})`).join("|"),"gi")}return(y,w)=>{var V,U,K,J;return X(),Wt(Gt,{to:"body"},[k("div",{ref_key:"el",ref:t,role:"button","aria-owns":(V=b.value)!=null&&V.length?"localsearch-list":void 0,"aria-expanded":"true","aria-haspopup":"listbox","aria-labelledby":"localsearch-label",class:"VPLocalSearchBox"},[k("div",{class:"backdrop",onClick:w[0]||(w[0]=B=>y.$emit("close"))}),k("div",Hr,[k("form",{class:"search-bar",onPointerup:w[4]||(w[4]=B=>I(B)),onSubmit:w[5]||(w[5]=Kt(()=>{},["prevent"]))},[k("label",{title:g.value,id:"localsearch-label",for:"localsearch-input"},Zr,8,qr),k("div",Xr,[k("button",{class:"back-button",title:G(c)("modal.backButtonTitle"),onClick:w[1]||(w[1]=B=>y.$emit("close"))},ra,8,ea)]),Jt(k("input",{ref_key:"searchInput",ref:_,"onUpdate:modelValue":w[2]||(w[2]=B=>jt(h)?h.value=B:null),placeholder:g.value,id:"localsearch-input","aria-labelledby":"localsearch-label",class:"search-input"},null,8,aa),[[Ut,G(h)]]),k("div",na,[m.value?Ee("",!0):(X(),te("button",{key:0,class:tt(["toggle-layout-button",{"detailed-list":G(v)}]),type:"button",title:G(c)("modal.displayDetails"),onClick:w[3]||(w[3]=B=>E.value>-1&&(v.value=!G(v)))},sa,10,ia)),k("button",{class:"clear-button",type:"reset",disabled:L.value,title:G(c)("modal.resetButtonTitle"),onClick:C},ca,8,ua)])],32),k("ul",{ref_key:"resultsEl",ref:r,id:(U=b.value)!=null&&U.length?"localsearch-list":void 0,role:(K=b.value)!=null&&K.length?"listbox":void 0,"aria-labelledby":(J=b.value)!=null&&J.length?"localsearch-label":void 0,class:"results",onMousemove:w[7]||(w[7]=B=>O.value=!1)},[(X(!0),te(at,null,rt(b.value,(B,j)=>(X(),te("li",{key:B.id,role:"option","aria-selected":E.value===j?"true":"false"},[k("a",{href:B.id,class:tt(["result",{selected:E.value===j}]),"aria-label":[...B.titles,B.title].join(" > "),onMouseenter:H=>!O.value&&(E.value=j),onFocusin:H=>E.value=j,onClick:w[6]||(w[6]=H=>y.$emit("close"))},[k("div",null,[k("div",va,[pa,(X(!0),te(at,null,rt(B.titles,(H,ge)=>(X(),te("span",{key:ge,class:"title"},[k("span",{class:"text",innerHTML:H},null,8,ya),ma]))),128)),k("span",ga,[k("span",{class:"text",innerHTML:B.title},null,8,ba)])]),G(v)?(X(),te("div",wa,[B.text?(X(),te("div",xa,[k("div",{class:"vp-doc",innerHTML:B.text},null,8,Fa)])):Ee("",!0),Ea,Sa])):Ee("",!0)])],42,da)],8,ha))),128)),G(h)&&!b.value.length&&x.value?(X(),te("li",Aa,[de(ve(G(c)("modal.noResultsText"))+' "',1),k("strong",null,ve(G(h)),1),de('" ')])):Ee("",!0)],40,fa),k("div",Ta,[k("span",null,[k("kbd",{"aria-label":G(c)("modal.footer.navigateUpKeyAriaLabel")},Ia,8,Na),k("kbd",{"aria-label":G(c)("modal.footer.navigateDownKeyAriaLabel")},Oa,8,Da),de(" "+ve(G(c)("modal.footer.navigateText")),1)]),k("span",null,[k("kbd",{"aria-label":G(c)("modal.footer.selectKeyAriaLabel")},Ma,8,Ra),de(" "+ve(G(c)("modal.footer.selectText")),1)]),k("span",null,[k("kbd",{"aria-label":G(c)("modal.footer.closeKeyAriaLabel")},"esc",8,La),de(" "+ve(G(c)("modal.footer.closeText")),1)])])])],8,Qr)])}}}),Ka=er(Pa,[["__scopeId","data-v-639d7ab9"]]);export{Ka as default}; diff --git a/assets/chunks/framework.DvHfxfnp.js b/assets/chunks/framework.DvHfxfnp.js new file mode 100644 index 00000000..89f2fd46 --- /dev/null +++ b/assets/chunks/framework.DvHfxfnp.js @@ -0,0 +1 @@ +function br(e,t){const n=Object.create(null),r=e.split(",");for(let s=0;s!!n[s]}const ne={},gt=[],Ne=()=>{},wo=()=>!1,Eo=/^on[^a-z]/,zt=e=>Eo.test(e),wr=e=>e.startsWith("onUpdate:"),ce=Object.assign,Er=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},Co=Object.prototype.hasOwnProperty,X=(e,t)=>Co.call(e,t),K=Array.isArray,mt=e=>Tn(e)==="[object Map]",Qs=e=>Tn(e)==="[object Set]",W=e=>typeof e=="function",oe=e=>typeof e=="string",Cr=e=>typeof e=="symbol",te=e=>e!==null&&typeof e=="object",xr=e=>te(e)&&W(e.then)&&W(e.catch),Zs=Object.prototype.toString,Tn=e=>Zs.call(e),xo=e=>Tn(e).slice(8,-1),Gs=e=>Tn(e)==="[object Object]",Tr=e=>oe(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,Nt=br(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),An=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},To=/-(\w)/g,He=An(e=>e.replace(To,(t,n)=>n?n.toUpperCase():"")),Ao=/\B([A-Z])/g,ut=An(e=>e.replace(Ao,"-$1").toLowerCase()),Sn=An(e=>e.charAt(0).toUpperCase()+e.slice(1)),hn=An(e=>e?`on${Sn(e)}`:""),Ut=(e,t)=>!Object.is(e,t),pn=(e,t)=>{for(let n=0;n{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:n})},sr=e=>{const t=parseFloat(e);return isNaN(t)?e:t},ei=e=>{const t=oe(e)?Number(e):NaN;return isNaN(t)?e:t};let ss;const ir=()=>ss||(ss=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function Ar(e){if(K(e)){const t={};for(let n=0;n{if(n){const r=n.split(Oo);r.length>1&&(t[r[0].trim()]=r[1].trim())}}),t}function Sr(e){let t="";if(oe(e))t=e;else if(K(e))for(let n=0;noe(e)?e:e==null?"":K(e)||te(e)&&(e.toString===Zs||!W(e.toString))?JSON.stringify(e,ni,2):String(e),ni=(e,t)=>t&&t.__v_isRef?ni(e,t.value):mt(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((n,[r,s])=>(n[`${r} =>`]=s,n),{})}:Qs(t)?{[`Set(${t.size})`]:[...t.values()]}:te(t)&&!K(t)&&!Gs(t)?String(t):t;let we;class Lo{constructor(t=!1){this.detached=t,this._active=!0,this.effects=[],this.cleanups=[],this.parent=we,!t&&we&&(this.index=(we.scopes||(we.scopes=[])).push(this)-1)}get active(){return this._active}run(t){if(this._active){const n=we;try{return we=this,t()}finally{we=n}}}on(){we=this}off(){we=this.parent}stop(t){if(this._active){let n,r;for(n=0,r=this.effects.length;n{const t=new Set(e);return t.w=0,t.n=0,t},si=e=>(e.w&Qe)>0,ii=e=>(e.n&Qe)>0,$o=({deps:e})=>{if(e.length)for(let t=0;t{const{deps:t}=e;if(t.length){let n=0;for(let r=0;r{(f==="length"||f>=c)&&l.push(a)})}else switch(n!==void 0&&l.push(o.get(n)),t){case"add":K(e)?Tr(n)&&l.push(o.get("length")):(l.push(o.get(ct)),mt(e)&&l.push(o.get(lr)));break;case"delete":K(e)||(l.push(o.get(ct)),mt(e)&&l.push(o.get(lr)));break;case"set":mt(e)&&l.push(o.get(ct));break}if(l.length===1)l[0]&&cr(l[0]);else{const c=[];for(const a of l)a&&c.push(...a);cr(Or(c))}}function cr(e,t){const n=K(e)?e:[...e];for(const r of n)r.computed&&os(r);for(const r of n)r.computed||os(r)}function os(e,t){(e!==Oe||e.allowRecurse)&&(e.scheduler?e.scheduler():e.run())}function Ho(e,t){var n;return(n=yn.get(e))==null?void 0:n.get(t)}const jo=br("__proto__,__v_isRef,__isVue"),ci=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(Cr)),ko=Ir(),Do=Ir(!1,!0),Uo=Ir(!0),ls=Ko();function Ko(){const e={};return["includes","indexOf","lastIndexOf"].forEach(t=>{e[t]=function(...n){const r=z(this);for(let i=0,o=this.length;i{e[t]=function(...n){St();const r=z(this)[t].apply(this,n);return Ot(),r}}),e}function Wo(e){const t=z(this);return ve(t,"has",e),t.hasOwnProperty(e)}function Ir(e=!1,t=!1){return function(r,s,i){if(s==="__v_isReactive")return!e;if(s==="__v_isReadonly")return e;if(s==="__v_isShallow")return t;if(s==="__v_raw"&&i===(e?t?ol:hi:t?di:fi).get(r))return r;const o=K(r);if(!e){if(o&&X(ls,s))return Reflect.get(ls,s,i);if(s==="hasOwnProperty")return Wo}const l=Reflect.get(r,s,i);return(Cr(s)?ci.has(s):jo(s))||(e||ve(r,"get",s),t)?l:ue(l)?o&&Tr(s)?l:l.value:te(l)?e?In(l):Rn(l):l}}const Vo=ai(),qo=ai(!0);function ai(e=!1){return function(n,r,s,i){let o=n[r];if(Et(o)&&ue(o)&&!ue(s))return!1;if(!e&&(!vn(s)&&!Et(s)&&(o=z(o),s=z(s)),!K(n)&&ue(o)&&!ue(s)))return o.value=s,!0;const l=K(n)&&Tr(r)?Number(r)e,On=e=>Reflect.getPrototypeOf(e);function en(e,t,n=!1,r=!1){e=e.__v_raw;const s=z(e),i=z(t);n||(t!==i&&ve(s,"get",t),ve(s,"get",i));const{has:o}=On(s),l=r?Fr:n?Mr:Kt;if(o.call(s,t))return l(e.get(t));if(o.call(s,i))return l(e.get(i));e!==s&&e.get(t)}function tn(e,t=!1){const n=this.__v_raw,r=z(n),s=z(e);return t||(e!==s&&ve(r,"has",e),ve(r,"has",s)),e===s?n.has(e):n.has(e)||n.has(s)}function nn(e,t=!1){return e=e.__v_raw,!t&&ve(z(e),"iterate",ct),Reflect.get(e,"size",e)}function cs(e){e=z(e);const t=z(this);return On(t).has.call(t,e)||(t.add(e),De(t,"add",e,e)),this}function as(e,t){t=z(t);const n=z(this),{has:r,get:s}=On(n);let i=r.call(n,e);i||(e=z(e),i=r.call(n,e));const o=s.call(n,e);return n.set(e,t),i?Ut(t,o)&&De(n,"set",e,t):De(n,"add",e,t),this}function us(e){const t=z(this),{has:n,get:r}=On(t);let s=n.call(t,e);s||(e=z(e),s=n.call(t,e)),r&&r.call(t,e);const i=t.delete(e);return s&&De(t,"delete",e,void 0),i}function fs(){const e=z(this),t=e.size!==0,n=e.clear();return t&&De(e,"clear",void 0,void 0),n}function rn(e,t){return function(r,s){const i=this,o=i.__v_raw,l=z(o),c=t?Fr:e?Mr:Kt;return!e&&ve(l,"iterate",ct),o.forEach((a,f)=>r.call(s,c(a),c(f),i))}}function sn(e,t,n){return function(...r){const s=this.__v_raw,i=z(s),o=mt(i),l=e==="entries"||e===Symbol.iterator&&o,c=e==="keys"&&o,a=s[e](...r),f=n?Fr:t?Mr:Kt;return!t&&ve(i,"iterate",c?lr:ct),{next(){const{value:d,done:p}=a.next();return p?{value:d,done:p}:{value:l?[f(d[0]),f(d[1])]:f(d),done:p}},[Symbol.iterator](){return this}}}}function Ke(e){return function(...t){return e==="delete"?!1:this}}function Zo(){const e={get(i){return en(this,i)},get size(){return nn(this)},has:tn,add:cs,set:as,delete:us,clear:fs,forEach:rn(!1,!1)},t={get(i){return en(this,i,!1,!0)},get size(){return nn(this)},has:tn,add:cs,set:as,delete:us,clear:fs,forEach:rn(!1,!0)},n={get(i){return en(this,i,!0)},get size(){return nn(this,!0)},has(i){return tn.call(this,i,!0)},add:Ke("add"),set:Ke("set"),delete:Ke("delete"),clear:Ke("clear"),forEach:rn(!0,!1)},r={get(i){return en(this,i,!0,!0)},get size(){return nn(this,!0)},has(i){return tn.call(this,i,!0)},add:Ke("add"),set:Ke("set"),delete:Ke("delete"),clear:Ke("clear"),forEach:rn(!0,!0)};return["keys","values","entries",Symbol.iterator].forEach(i=>{e[i]=sn(i,!1,!1),n[i]=sn(i,!0,!1),t[i]=sn(i,!1,!0),r[i]=sn(i,!0,!0)}),[e,n,t,r]}const[Go,el,tl,nl]=Zo();function Pr(e,t){const n=t?e?nl:tl:e?el:Go;return(r,s,i)=>s==="__v_isReactive"?!e:s==="__v_isReadonly"?e:s==="__v_raw"?r:Reflect.get(X(n,s)&&s in r?n:r,s,i)}const rl={get:Pr(!1,!1)},sl={get:Pr(!1,!0)},il={get:Pr(!0,!1)},fi=new WeakMap,di=new WeakMap,hi=new WeakMap,ol=new WeakMap;function ll(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function cl(e){return e.__v_skip||!Object.isExtensible(e)?0:ll(xo(e))}function Rn(e){return Et(e)?e:Lr(e,!1,ui,rl,fi)}function al(e){return Lr(e,!1,Qo,sl,di)}function In(e){return Lr(e,!0,Jo,il,hi)}function Lr(e,t,n,r,s){if(!te(e)||e.__v_raw&&!(t&&e.__v_isReactive))return e;const i=s.get(e);if(i)return i;const o=cl(e);if(o===0)return e;const l=new Proxy(e,o===2?r:n);return s.set(e,l),l}function _t(e){return Et(e)?_t(e.__v_raw):!!(e&&e.__v_isReactive)}function Et(e){return!!(e&&e.__v_isReadonly)}function vn(e){return!!(e&&e.__v_isShallow)}function pi(e){return _t(e)||Et(e)}function z(e){const t=e&&e.__v_raw;return t?z(t):e}function $t(e){return _n(e,"__v_skip",!0),e}const Kt=e=>te(e)?Rn(e):e,Mr=e=>te(e)?In(e):e;function Nr(e){Xe&&Oe&&(e=z(e),li(e.dep||(e.dep=Or())))}function $r(e,t){e=z(e);const n=e.dep;n&&cr(n)}function ue(e){return!!(e&&e.__v_isRef===!0)}function se(e){return gi(e,!1)}function Br(e){return gi(e,!0)}function gi(e,t){return ue(e)?e:new ul(e,t)}class ul{constructor(t,n){this.__v_isShallow=n,this.dep=void 0,this.__v_isRef=!0,this._rawValue=n?t:z(t),this._value=n?t:Kt(t)}get value(){return Nr(this),this._value}set value(t){const n=this.__v_isShallow||vn(t)||Et(t);t=n?t:z(t),Ut(t,this._rawValue)&&(this._rawValue=t,this._value=n?t:Kt(t),$r(this))}}function mi(e){return ue(e)?e.value:e}const fl={get:(e,t,n)=>mi(Reflect.get(e,t,n)),set:(e,t,n,r)=>{const s=e[t];return ue(s)&&!ue(n)?(s.value=n,!0):Reflect.set(e,t,n,r)}};function _i(e){return _t(e)?e:new Proxy(e,fl)}class dl{constructor(t){this.dep=void 0,this.__v_isRef=!0;const{get:n,set:r}=t(()=>Nr(this),()=>$r(this));this._get=n,this._set=r}get value(){return this._get()}set value(t){this._set(t)}}function hl(e){return new dl(e)}function eu(e){const t=K(e)?new Array(e.length):{};for(const n in e)t[n]=yi(e,n);return t}class pl{constructor(t,n,r){this._object=t,this._key=n,this._defaultValue=r,this.__v_isRef=!0}get value(){const t=this._object[this._key];return t===void 0?this._defaultValue:t}set value(t){this._object[this._key]=t}get dep(){return Ho(z(this._object),this._key)}}class gl{constructor(t){this._getter=t,this.__v_isRef=!0,this.__v_isReadonly=!0}get value(){return this._getter()}}function ml(e,t,n){return ue(e)?e:W(e)?new gl(e):te(e)&&arguments.length>1?yi(e,t,n):se(e)}function yi(e,t,n){const r=e[t];return ue(r)?r:new pl(e,t,n)}class _l{constructor(t,n,r,s){this._setter=n,this.dep=void 0,this.__v_isRef=!0,this.__v_isReadonly=!1,this._dirty=!0,this.effect=new Rr(t,()=>{this._dirty||(this._dirty=!0,$r(this))}),this.effect.computed=this,this.effect.active=this._cacheable=!s,this.__v_isReadonly=r}get value(){const t=z(this);return Nr(t),(t._dirty||!t._cacheable)&&(t._dirty=!1,t._value=t.effect.run()),t._value}set value(t){this._setter(t)}}function yl(e,t,n=!1){let r,s;const i=W(e);return i?(r=e,s=Ne):(r=e.get,s=e.set),new _l(r,s,i||!s,n)}function ze(e,t,n,r){let s;try{s=r?e(...r):e()}catch(i){Rt(i,t,n)}return s}function Ae(e,t,n,r){if(W(e)){const i=ze(e,t,n,r);return i&&xr(i)&&i.catch(o=>{Rt(o,t,n)}),i}const s=[];for(let i=0;i>>1;Vt(pe[r])Le&&pe.splice(t,1)}function wi(e){K(e)?yt.push(...e):(!ke||!ke.includes(e,e.allowRecurse?it+1:it))&&yt.push(e),bi()}function ds(e,t=Wt?Le+1:0){for(;tVt(n)-Vt(r)),it=0;ite.id==null?1/0:e.id,El=(e,t)=>{const n=Vt(e)-Vt(t);if(n===0){if(e.pre&&!t.pre)return-1;if(t.pre&&!e.pre)return 1}return n};function Ei(e){ar=!1,Wt=!0,pe.sort(El);try{for(Le=0;Leoe(y)?y.trim():y)),d&&(s=n.map(sr))}let l,c=r[l=hn(t)]||r[l=hn(He(t))];!c&&i&&(c=r[l=hn(ut(t))]),c&&Ae(c,e,6,s);const a=r[l+"Once"];if(a){if(!e.emitted)e.emitted={};else if(e.emitted[l])return;e.emitted[l]=!0,Ae(a,e,6,s)}}function Ci(e,t,n=!1){const r=t.emitsCache,s=r.get(e);if(s!==void 0)return s;const i=e.emits;let o={},l=!1;if(!W(e)){const c=a=>{const f=Ci(a,t,!0);f&&(l=!0,ce(o,f))};!n&&t.mixins.length&&t.mixins.forEach(c),e.extends&&c(e.extends),e.mixins&&e.mixins.forEach(c)}return!i&&!l?(te(e)&&r.set(e,null),null):(K(i)?i.forEach(c=>o[c]=null):ce(o,i),te(e)&&r.set(e,o),o)}function Ln(e,t){return!e||!zt(t)?!1:(t=t.slice(2).replace(/Once$/,""),X(e,t[0].toLowerCase()+t.slice(1))||X(e,ut(t))||X(e,t))}let fe=null,Mn=null;function wn(e){const t=fe;return fe=e,Mn=e&&e.type.__scopeId||null,t}function tu(e){Mn=e}function nu(){Mn=null}function xl(e,t=fe,n){if(!t||e._n)return e;const r=(...s)=>{r._d&&As(-1);const i=wn(t);let o;try{o=e(...s)}finally{wn(i),r._d&&As(1)}return o};return r._n=!0,r._c=!0,r._d=!0,r}function Un(e){const{type:t,vnode:n,proxy:r,withProxy:s,props:i,propsOptions:[o],slots:l,attrs:c,emit:a,render:f,renderCache:d,data:p,setupState:y,ctx:w,inheritAttrs:T}=e;let L,v;const _=wn(e);try{if(n.shapeFlag&4){const m=s||r;L=xe(f.call(m,m,d,i,y,p,w)),v=c}else{const m=t;L=xe(m.length>1?m(i,{attrs:c,slots:l,emit:a}):m(i,null)),v=t.props?c:Al(c)}}catch(m){kt.length=0,Rt(m,e,1),L=ie(me)}let j=L;if(v&&T!==!1){const m=Object.keys(v),{shapeFlag:R}=j;m.length&&R&7&&(o&&m.some(wr)&&(v=Sl(v,o)),j=Ze(j,v))}return n.dirs&&(j=Ze(j),j.dirs=j.dirs?j.dirs.concat(n.dirs):n.dirs),n.transition&&(j.transition=n.transition),L=j,wn(_),L}function Tl(e){let t;for(let n=0;n{let t;for(const n in e)(n==="class"||n==="style"||zt(n))&&((t||(t={}))[n]=e[n]);return t},Sl=(e,t)=>{const n={};for(const r in e)(!wr(r)||!(r.slice(9)in t))&&(n[r]=e[r]);return n};function Ol(e,t,n){const{props:r,children:s,component:i}=e,{props:o,children:l,patchFlag:c}=t,a=i.emitsOptions;if(t.dirs||t.transition)return!0;if(n&&c>=0){if(c&1024)return!0;if(c&16)return r?hs(r,o,a):!!o;if(c&8){const f=t.dynamicProps;for(let d=0;de.__isSuspense,Il={name:"Suspense",__isSuspense:!0,process(e,t,n,r,s,i,o,l,c,a){e==null?Fl(t,n,r,s,i,o,l,c,a):Pl(e,t,n,r,s,o,l,c,a)},hydrate:Ll,create:kr,normalize:Ml},ru=Il;function qt(e,t){const n=e.props&&e.props[t];W(n)&&n()}function Fl(e,t,n,r,s,i,o,l,c){const{p:a,o:{createElement:f}}=c,d=f("div"),p=e.suspense=kr(e,s,r,t,d,n,i,o,l,c);a(null,p.pendingBranch=e.ssContent,d,null,r,p,i,o),p.deps>0?(qt(e,"onPending"),qt(e,"onFallback"),a(null,e.ssFallback,t,n,r,null,i,o),vt(p,e.ssFallback)):p.resolve(!1,!0)}function Pl(e,t,n,r,s,i,o,l,{p:c,um:a,o:{createElement:f}}){const d=t.suspense=e.suspense;d.vnode=t,t.el=e.el;const p=t.ssContent,y=t.ssFallback,{activeBranch:w,pendingBranch:T,isInFallback:L,isHydrating:v}=d;if(T)d.pendingBranch=p,Me(p,T)?(c(T,p,d.hiddenContainer,null,s,d,i,o,l),d.deps<=0?d.resolve():L&&(c(w,y,n,r,s,null,i,o,l),vt(d,y))):(d.pendingId++,v?(d.isHydrating=!1,d.activeBranch=T):a(T,s,d),d.deps=0,d.effects.length=0,d.hiddenContainer=f("div"),L?(c(null,p,d.hiddenContainer,null,s,d,i,o,l),d.deps<=0?d.resolve():(c(w,y,n,r,s,null,i,o,l),vt(d,y))):w&&Me(p,w)?(c(w,p,n,r,s,d,i,o,l),d.resolve(!0)):(c(null,p,d.hiddenContainer,null,s,d,i,o,l),d.deps<=0&&d.resolve()));else if(w&&Me(p,w))c(w,p,n,r,s,d,i,o,l),vt(d,p);else if(qt(t,"onPending"),d.pendingBranch=p,d.pendingId++,c(null,p,d.hiddenContainer,null,s,d,i,o,l),d.deps<=0)d.resolve();else{const{timeout:_,pendingId:j}=d;_>0?setTimeout(()=>{d.pendingId===j&&d.fallback(y)},_):_===0&&d.fallback(y)}}function kr(e,t,n,r,s,i,o,l,c,a,f=!1){const{p:d,m:p,um:y,n:w,o:{parentNode:T,remove:L}}=a;let v;const _=Nl(e);_&&t!=null&&t.pendingBranch&&(v=t.pendingId,t.deps++);const j=e.props?ei(e.props.timeout):void 0,m={vnode:e,parent:t,parentComponent:n,isSVG:o,container:r,hiddenContainer:s,anchor:i,deps:0,pendingId:0,timeout:typeof j=="number"?j:-1,activeBranch:null,pendingBranch:null,isInFallback:!0,isHydrating:f,isUnmounted:!1,effects:[],resolve(R=!1,U=!1){const{vnode:B,activeBranch:b,pendingBranch:M,pendingId:A,effects:N,parentComponent:F,container:q}=m;if(m.isHydrating)m.isHydrating=!1;else if(!R){const J=b&&M.transition&&M.transition.mode==="out-in";J&&(b.transition.afterLeave=()=>{A===m.pendingId&&p(M,q,Z,0)});let{anchor:Z}=m;b&&(Z=w(b),y(b,F,m,!0)),J||p(M,q,Z,0)}vt(m,M),m.pendingBranch=null,m.isInFallback=!1;let $=m.parent,de=!1;for(;$;){if($.pendingBranch){$.effects.push(...N),de=!0;break}$=$.parent}de||wi(N),m.effects=[],_&&t&&t.pendingBranch&&v===t.pendingId&&(t.deps--,t.deps===0&&!U&&t.resolve()),qt(B,"onResolve")},fallback(R){if(!m.pendingBranch)return;const{vnode:U,activeBranch:B,parentComponent:b,container:M,isSVG:A}=m;qt(U,"onFallback");const N=w(B),F=()=>{m.isInFallback&&(d(null,R,M,N,b,null,A,l,c),vt(m,R))},q=R.transition&&R.transition.mode==="out-in";q&&(B.transition.afterLeave=F),m.isInFallback=!0,y(B,b,null,!0),q||F()},move(R,U,B){m.activeBranch&&p(m.activeBranch,R,U,B),m.container=R},next(){return m.activeBranch&&w(m.activeBranch)},registerDep(R,U){const B=!!m.pendingBranch;B&&m.deps++;const b=R.vnode.el;R.asyncDep.catch(M=>{Rt(M,R,0)}).then(M=>{if(R.isUnmounted||m.isUnmounted||m.pendingId!==R.suspenseId)return;R.asyncResolved=!0;const{vnode:A}=R;_r(R,M,!1),b&&(A.el=b);const N=!b&&R.subTree.el;U(R,A,T(b||R.subTree.el),b?null:w(R.subTree),m,o,c),N&&L(N),jr(R,A.el),B&&--m.deps===0&&m.resolve()})},unmount(R,U){m.isUnmounted=!0,m.activeBranch&&y(m.activeBranch,n,R,U),m.pendingBranch&&y(m.pendingBranch,n,R,U)}};return m}function Ll(e,t,n,r,s,i,o,l,c){const a=t.suspense=kr(t,r,n,e.parentNode,document.createElement("div"),null,s,i,o,l,!0),f=c(e,a.pendingBranch=t.ssContent,n,a,i,o);return a.deps===0&&a.resolve(!1,!0),f}function Ml(e){const{shapeFlag:t,children:n}=e,r=t&32;e.ssContent=ps(r?n.default:n),e.ssFallback=r?ps(n.fallback):ie(me)}function ps(e){let t;if(W(e)){const n=xt&&e._c;n&&(e._d=!1,Yr()),e=e(),n&&(e._d=!0,t=Te,Ki())}return K(e)&&(e=Tl(e)),e=xe(e),t&&!e.dynamicChildren&&(e.dynamicChildren=t.filter(n=>n!==e)),e}function xi(e,t){t&&t.pendingBranch?K(e)?t.effects.push(...e):t.effects.push(e):wi(e)}function vt(e,t){e.activeBranch=t;const{vnode:n,parentComponent:r}=e,s=n.el=t.el;r&&r.subTree===n&&(r.vnode.el=s,jr(r,s))}function Nl(e){var t;return((t=e.props)==null?void 0:t.suspensible)!=null&&e.props.suspensible!==!1}function Dr(e,t){return Nn(e,null,t)}function su(e,t){return Nn(e,null,{flush:"post"})}const on={};function $e(e,t,n){return Nn(e,t,n)}function Nn(e,t,{immediate:n,deep:r,flush:s,onTrack:i,onTrigger:o}=ne){var l;const c=ri()===((l=ae)==null?void 0:l.scope)?ae:null;let a,f=!1,d=!1;if(ue(e)?(a=()=>e.value,f=vn(e)):_t(e)?(a=()=>e,r=!0):K(e)?(d=!0,f=e.some(m=>_t(m)||vn(m)),a=()=>e.map(m=>{if(ue(m))return m.value;if(_t(m))return lt(m);if(W(m))return ze(m,c,2)})):W(e)?t?a=()=>ze(e,c,2):a=()=>{if(!(c&&c.isUnmounted))return p&&p(),Ae(e,c,3,[y])}:a=Ne,t&&r){const m=a;a=()=>lt(m())}let p,y=m=>{p=_.onStop=()=>{ze(m,c,4)}},w;if(Tt)if(y=Ne,t?n&&Ae(t,c,3,[a(),d?[]:void 0,y]):a(),s==="sync"){const m=Ic();w=m.__watcherHandles||(m.__watcherHandles=[])}else return Ne;let T=d?new Array(e.length).fill(on):on;const L=()=>{if(_.active)if(t){const m=_.run();(r||f||(d?m.some((R,U)=>Ut(R,T[U])):Ut(m,T)))&&(p&&p(),Ae(t,c,3,[m,T===on?void 0:d&&T[0]===on?[]:T,y]),T=m)}else _.run()};L.allowRecurse=!!t;let v;s==="sync"?v=L:s==="post"?v=()=>_e(L,c&&c.suspense):(L.pre=!0,c&&(L.id=c.uid),v=()=>Pn(L));const _=new Rr(a,v);t?n?L():T=_.run():s==="post"?_e(_.run.bind(_),c&&c.suspense):_.run();const j=()=>{_.stop(),c&&c.scope&&Er(c.scope.effects,_)};return w&&w.push(j),j}function $l(e,t,n){const r=this.proxy,s=oe(e)?e.includes(".")?Ti(r,e):()=>r[e]:e.bind(r,r);let i;W(t)?i=t:(i=t.handler,n=t);const o=ae;Ge(this);const l=Nn(s,i.bind(r),n);return o?Ge(o):Je(),l}function Ti(e,t){const n=t.split(".");return()=>{let r=e;for(let s=0;s{lt(n,t)});else if(Gs(e))for(const n in e)lt(e[n],t);return e}function iu(e,t){const n=fe;if(n===null)return e;const r=jn(n)||n.proxy,s=e.dirs||(e.dirs=[]);for(let i=0;i{e.isMounted=!0}),Ii(()=>{e.isUnmounting=!0}),e}const Ee=[Function,Array],Ai={mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:Ee,onEnter:Ee,onAfterEnter:Ee,onEnterCancelled:Ee,onBeforeLeave:Ee,onLeave:Ee,onAfterLeave:Ee,onLeaveCancelled:Ee,onBeforeAppear:Ee,onAppear:Ee,onAfterAppear:Ee,onAppearCancelled:Ee},Hl={name:"BaseTransition",props:Ai,setup(e,{slots:t}){const n=Qt(),r=Bl();let s;return()=>{const i=t.default&&Oi(t.default(),!0);if(!i||!i.length)return;let o=i[0];if(i.length>1){for(const T of i)if(T.type!==me){o=T;break}}const l=z(e),{mode:c}=l;if(r.isLeaving)return Kn(o);const a=gs(o);if(!a)return Kn(o);const f=ur(a,l,r,n);fr(a,f);const d=n.subTree,p=d&&gs(d);let y=!1;const{getTransitionKey:w}=a.type;if(w){const T=w();s===void 0?s=T:T!==s&&(s=T,y=!0)}if(p&&p.type!==me&&(!Me(a,p)||y)){const T=ur(p,l,r,n);if(fr(p,T),c==="out-in")return r.isLeaving=!0,T.afterLeave=()=>{r.isLeaving=!1,n.update.active!==!1&&n.update()},Kn(o);c==="in-out"&&a.type!==me&&(T.delayLeave=(L,v,_)=>{const j=Si(r,p);j[String(p.key)]=p,L._leaveCb=()=>{v(),L._leaveCb=void 0,delete f.delayedLeave},f.delayedLeave=_})}return o}}},jl=Hl;function Si(e,t){const{leavingVNodes:n}=e;let r=n.get(t.type);return r||(r=Object.create(null),n.set(t.type,r)),r}function ur(e,t,n,r){const{appear:s,mode:i,persisted:o=!1,onBeforeEnter:l,onEnter:c,onAfterEnter:a,onEnterCancelled:f,onBeforeLeave:d,onLeave:p,onAfterLeave:y,onLeaveCancelled:w,onBeforeAppear:T,onAppear:L,onAfterAppear:v,onAppearCancelled:_}=t,j=String(e.key),m=Si(n,e),R=(b,M)=>{b&&Ae(b,r,9,M)},U=(b,M)=>{const A=M[1];R(b,M),K(b)?b.every(N=>N.length<=1)&&A():b.length<=1&&A()},B={mode:i,persisted:o,beforeEnter(b){let M=l;if(!n.isMounted)if(s)M=T||l;else return;b._leaveCb&&b._leaveCb(!0);const A=m[j];A&&Me(e,A)&&A.el._leaveCb&&A.el._leaveCb(),R(M,[b])},enter(b){let M=c,A=a,N=f;if(!n.isMounted)if(s)M=L||c,A=v||a,N=_||f;else return;let F=!1;const q=b._enterCb=$=>{F||(F=!0,$?R(N,[b]):R(A,[b]),B.delayedLeave&&B.delayedLeave(),b._enterCb=void 0)};M?U(M,[b,q]):q()},leave(b,M){const A=String(e.key);if(b._enterCb&&b._enterCb(!0),n.isUnmounting)return M();R(d,[b]);let N=!1;const F=b._leaveCb=q=>{N||(N=!0,M(),q?R(w,[b]):R(y,[b]),b._leaveCb=void 0,m[A]===e&&delete m[A])};m[A]=e,p?U(p,[b,F]):F()},clone(b){return ur(b,t,n,r)}};return B}function Kn(e){if(Jt(e))return e=Ze(e),e.children=null,e}function gs(e){return Jt(e)?e.children?e.children[0]:void 0:e}function fr(e,t){e.shapeFlag&6&&e.component?fr(e.component.subTree,t):e.shapeFlag&128?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function Oi(e,t=!1,n){let r=[],s=0;for(let i=0;i1)for(let i=0;i!!e.type.__asyncLoader;function ou(e){W(e)&&(e={loader:e});const{loader:t,loadingComponent:n,errorComponent:r,delay:s=200,timeout:i,suspensible:o=!0,onError:l}=e;let c=null,a,f=0;const d=()=>(f++,c=null,p()),p=()=>{let y;return c||(y=c=t().catch(w=>{if(w=w instanceof Error?w:new Error(String(w)),l)return new Promise((T,L)=>{l(w,()=>T(d()),()=>L(w),f+1)});throw w}).then(w=>y!==c&&c?c:(w&&(w.__esModule||w[Symbol.toStringTag]==="Module")&&(w=w.default),a=w,w)))};return Ur({name:"AsyncComponentWrapper",__asyncLoader:p,get __asyncResolved(){return a},setup(){const y=ae;if(a)return()=>Wn(a,y);const w=_=>{c=null,Rt(_,y,13,!r)};if(o&&y.suspense||Tt)return p().then(_=>()=>Wn(_,y)).catch(_=>(w(_),()=>r?ie(r,{error:_}):null));const T=se(!1),L=se(),v=se(!!s);return s&&setTimeout(()=>{v.value=!1},s),i!=null&&setTimeout(()=>{if(!T.value&&!L.value){const _=new Error(`Async component timed out after ${i}ms.`);w(_),L.value=_}},i),p().then(()=>{T.value=!0,y.parent&&Jt(y.parent.vnode)&&Pn(y.parent.update)}).catch(_=>{w(_),L.value=_}),()=>{if(T.value&&a)return Wn(a,y);if(L.value&&r)return ie(r,{error:L.value});if(n&&!v.value)return ie(n)}}})}function Wn(e,t){const{ref:n,props:r,children:s,ce:i}=t.vnode,o=ie(e,r,s);return o.ref=n,o.ce=i,delete t.vnode.ce,o}const Jt=e=>e.type.__isKeepAlive;function kl(e,t){Ri(e,"a",t)}function Dl(e,t){Ri(e,"da",t)}function Ri(e,t,n=ae){const r=e.__wdc||(e.__wdc=()=>{let s=n;for(;s;){if(s.isDeactivated)return;s=s.parent}return e()});if($n(t,r,n),n){let s=n.parent;for(;s&&s.parent;)Jt(s.parent.vnode)&&Ul(r,t,n,s),s=s.parent}}function Ul(e,t,n,r){const s=$n(t,e,r,!0);Bn(()=>{Er(r[t],s)},n)}function $n(e,t,n=ae,r=!1){if(n){const s=n[e]||(n[e]=[]),i=t.__weh||(t.__weh=(...o)=>{if(n.isUnmounted)return;St(),Ge(n);const l=Ae(t,n,e,o);return Je(),Ot(),l});return r?s.unshift(i):s.push(i),i}}const Ue=e=>(t,n=ae)=>(!Tt||e==="sp")&&$n(e,(...r)=>t(...r),n),Kl=Ue("bm"),It=Ue("m"),Wl=Ue("bu"),Vl=Ue("u"),Ii=Ue("bum"),Bn=Ue("um"),ql=Ue("sp"),Yl=Ue("rtg"),Xl=Ue("rtc");function zl(e,t=ae){$n("ec",e,t)}const Kr="components";function lu(e,t){return Pi(Kr,e,!0,t)||e}const Fi=Symbol.for("v-ndc");function cu(e){return oe(e)?Pi(Kr,e,!1)||e:e||Fi}function Pi(e,t,n=!0,r=!1){const s=fe||ae;if(s){const i=s.type;if(e===Kr){const l=Sc(i,!1);if(l&&(l===t||l===He(t)||l===Sn(He(t))))return i}const o=ms(s[e]||i[e],t)||ms(s.appContext[e],t);return!o&&r?i:o}}function ms(e,t){return e&&(e[t]||e[He(t)]||e[Sn(He(t))])}function au(e,t,n,r){let s;const i=n;if(K(e)||oe(e)){s=new Array(e.length);for(let o=0,l=e.length;ot(o,l,void 0,i));else{const o=Object.keys(e);s=new Array(o.length);for(let l=0,c=o.length;lYt(t)?!(t.type===me||t.type===ye&&!Li(t.children)):!0)?e:null}function fu(e,t){const n={};for(const r in e)n[/[A-Z]/.test(r)?`on:${r}`:hn(r)]=e[r];return n}const dr=e=>e?zi(e)?jn(e)||e.proxy:dr(e.parent):null,Bt=ce(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>dr(e.parent),$root:e=>dr(e.root),$emit:e=>e.emit,$options:e=>Wr(e),$forceUpdate:e=>e.f||(e.f=()=>Pn(e.update)),$nextTick:e=>e.n||(e.n=Fn.bind(e.proxy)),$watch:e=>$l.bind(e)}),Vn=(e,t)=>e!==ne&&!e.__isScriptSetup&&X(e,t),Jl={get({_:e},t){const{ctx:n,setupState:r,data:s,props:i,accessCache:o,type:l,appContext:c}=e;let a;if(t[0]!=="$"){const y=o[t];if(y!==void 0)switch(y){case 1:return r[t];case 2:return s[t];case 4:return n[t];case 3:return i[t]}else{if(Vn(r,t))return o[t]=1,r[t];if(s!==ne&&X(s,t))return o[t]=2,s[t];if((a=e.propsOptions[0])&&X(a,t))return o[t]=3,i[t];if(n!==ne&&X(n,t))return o[t]=4,n[t];hr&&(o[t]=0)}}const f=Bt[t];let d,p;if(f)return t==="$attrs"&&ve(e,"get",t),f(e);if((d=l.__cssModules)&&(d=d[t]))return d;if(n!==ne&&X(n,t))return o[t]=4,n[t];if(p=c.config.globalProperties,X(p,t))return p[t]},set({_:e},t,n){const{data:r,setupState:s,ctx:i}=e;return Vn(s,t)?(s[t]=n,!0):r!==ne&&X(r,t)?(r[t]=n,!0):X(e.props,t)||t[0]==="$"&&t.slice(1)in e?!1:(i[t]=n,!0)},has({_:{data:e,setupState:t,accessCache:n,ctx:r,appContext:s,propsOptions:i}},o){let l;return!!n[o]||e!==ne&&X(e,o)||Vn(t,o)||(l=i[0])&&X(l,o)||X(r,o)||X(Bt,o)||X(s.config.globalProperties,o)},defineProperty(e,t,n){return n.get!=null?e._.accessCache[t]=0:X(n,"value")&&this.set(e,t,n.value,null),Reflect.defineProperty(e,t,n)}};function du(){return Ql().slots}function Ql(){const e=Qt();return e.setupContext||(e.setupContext=Qi(e))}function _s(e){return K(e)?e.reduce((t,n)=>(t[n]=null,t),{}):e}function hu(e){const t=Qt();let n=e();return Je(),xr(n)&&(n=n.catch(r=>{throw Ge(t),r})),[n,()=>Ge(t)]}let hr=!0;function Zl(e){const t=Wr(e),n=e.proxy,r=e.ctx;hr=!1,t.beforeCreate&&ys(t.beforeCreate,e,"bc");const{data:s,computed:i,methods:o,watch:l,provide:c,inject:a,created:f,beforeMount:d,mounted:p,beforeUpdate:y,updated:w,activated:T,deactivated:L,beforeDestroy:v,beforeUnmount:_,destroyed:j,unmounted:m,render:R,renderTracked:U,renderTriggered:B,errorCaptured:b,serverPrefetch:M,expose:A,inheritAttrs:N,components:F,directives:q,filters:$}=t;if(a&&Gl(a,r,null),o)for(const Z in o){const G=o[Z];W(G)&&(r[Z]=G.bind(n))}if(s){const Z=s.call(n,n);te(Z)&&(e.data=Rn(Z))}if(hr=!0,i)for(const Z in i){const G=i[Z],et=W(G)?G.bind(n,n):W(G.get)?G.get.bind(n,n):Ne,Zt=!W(G)&&W(G.set)?G.set.bind(n):Ne,tt=re({get:et,set:Zt});Object.defineProperty(r,Z,{enumerable:!0,configurable:!0,get:()=>tt.value,set:Ie=>tt.value=Ie})}if(l)for(const Z in l)Mi(l[Z],r,n,Z);if(c){const Z=W(c)?c.call(n):c;Reflect.ownKeys(Z).forEach(G=>{ic(G,Z[G])})}f&&ys(f,e,"c");function J(Z,G){K(G)?G.forEach(et=>Z(et.bind(n))):G&&Z(G.bind(n))}if(J(Kl,d),J(It,p),J(Wl,y),J(Vl,w),J(kl,T),J(Dl,L),J(zl,b),J(Xl,U),J(Yl,B),J(Ii,_),J(Bn,m),J(ql,M),K(A))if(A.length){const Z=e.exposed||(e.exposed={});A.forEach(G=>{Object.defineProperty(Z,G,{get:()=>n[G],set:et=>n[G]=et})})}else e.exposed||(e.exposed={});R&&e.render===Ne&&(e.render=R),N!=null&&(e.inheritAttrs=N),F&&(e.components=F),q&&(e.directives=q)}function Gl(e,t,n=Ne){K(e)&&(e=pr(e));for(const r in e){const s=e[r];let i;te(s)?"default"in s?i=wt(s.from||r,s.default,!0):i=wt(s.from||r):i=wt(s),ue(i)?Object.defineProperty(t,r,{enumerable:!0,configurable:!0,get:()=>i.value,set:o=>i.value=o}):t[r]=i}}function ys(e,t,n){Ae(K(e)?e.map(r=>r.bind(t.proxy)):e.bind(t.proxy),t,n)}function Mi(e,t,n,r){const s=r.includes(".")?Ti(n,r):()=>n[r];if(oe(e)){const i=t[e];W(i)&&$e(s,i)}else if(W(e))$e(s,e.bind(n));else if(te(e))if(K(e))e.forEach(i=>Mi(i,t,n,r));else{const i=W(e.handler)?e.handler.bind(n):t[e.handler];W(i)&&$e(s,i,e)}}function Wr(e){const t=e.type,{mixins:n,extends:r}=t,{mixins:s,optionsCache:i,config:{optionMergeStrategies:o}}=e.appContext,l=i.get(t);let c;return l?c=l:!s.length&&!n&&!r?c=t:(c={},s.length&&s.forEach(a=>En(c,a,o,!0)),En(c,t,o)),te(t)&&i.set(t,c),c}function En(e,t,n,r=!1){const{mixins:s,extends:i}=t;i&&En(e,i,n,!0),s&&s.forEach(o=>En(e,o,n,!0));for(const o in t)if(!(r&&o==="expose")){const l=ec[o]||n&&n[o];e[o]=l?l(e[o],t[o]):t[o]}return e}const ec={data:vs,props:bs,emits:bs,methods:Mt,computed:Mt,beforeCreate:ge,created:ge,beforeMount:ge,mounted:ge,beforeUpdate:ge,updated:ge,beforeDestroy:ge,beforeUnmount:ge,destroyed:ge,unmounted:ge,activated:ge,deactivated:ge,errorCaptured:ge,serverPrefetch:ge,components:Mt,directives:Mt,watch:nc,provide:vs,inject:tc};function vs(e,t){return t?e?function(){return ce(W(e)?e.call(this,this):e,W(t)?t.call(this,this):t)}:t:e}function tc(e,t){return Mt(pr(e),pr(t))}function pr(e){if(K(e)){const t={};for(let n=0;n1)return n&&W(t)?t.call(r&&r.proxy):t}}function oc(e,t,n,r=!1){const s={},i={};_n(i,Hn,1),e.propsDefaults=Object.create(null),$i(e,t,s,i);for(const o in e.propsOptions[0])o in s||(s[o]=void 0);n?e.props=r?s:al(s):e.type.props?e.props=s:e.props=i,e.attrs=i}function lc(e,t,n,r){const{props:s,attrs:i,vnode:{patchFlag:o}}=e,l=z(s),[c]=e.propsOptions;let a=!1;if((r||o>0)&&!(o&16)){if(o&8){const f=e.vnode.dynamicProps;for(let d=0;d{c=!0;const[p,y]=Bi(d,t,!0);ce(o,p),y&&l.push(...y)};!n&&t.mixins.length&&t.mixins.forEach(f),e.extends&&f(e.extends),e.mixins&&e.mixins.forEach(f)}if(!i&&!c)return te(e)&&r.set(e,gt),gt;if(K(i))for(let f=0;f-1,y[1]=T<0||w-1||X(y,"default"))&&l.push(d)}}}const a=[o,l];return te(e)&&r.set(e,a),a}function ws(e){return e[0]!=="$"}function Es(e){const t=e&&e.toString().match(/^\s*(function|class) (\w+)/);return t?t[2]:e===null?"null":""}function Cs(e,t){return Es(e)===Es(t)}function xs(e,t){return K(t)?t.findIndex(n=>Cs(n,e)):W(t)&&Cs(t,e)?0:-1}const Hi=e=>e[0]==="_"||e==="$stable",Vr=e=>K(e)?e.map(xe):[xe(e)],cc=(e,t,n)=>{if(t._n)return t;const r=xl((...s)=>Vr(t(...s)),n);return r._c=!1,r},ji=(e,t,n)=>{const r=e._ctx;for(const s in e){if(Hi(s))continue;const i=e[s];if(W(i))t[s]=cc(s,i,r);else if(i!=null){const o=Vr(i);t[s]=()=>o}}},ki=(e,t)=>{const n=Vr(t);e.slots.default=()=>n},ac=(e,t)=>{if(e.vnode.shapeFlag&32){const n=t._;n?(e.slots=z(t),_n(t,"_",n)):ji(t,e.slots={})}else e.slots={},t&&ki(e,t);_n(e.slots,Hn,1)},uc=(e,t,n)=>{const{vnode:r,slots:s}=e;let i=!0,o=ne;if(r.shapeFlag&32){const l=t._;l?n&&l===1?i=!1:(ce(s,t),!n&&l===1&&delete s._):(i=!t.$stable,ji(t,s)),o=t}else t&&(ki(e,t),o={default:1});if(i)for(const l in s)!Hi(l)&&!(l in o)&&delete s[l]};function xn(e,t,n,r,s=!1){if(K(e)){e.forEach((p,y)=>xn(p,t&&(K(t)?t[y]:t),n,r,s));return}if(bt(r)&&!s)return;const i=r.shapeFlag&4?jn(r.component)||r.component.proxy:r.el,o=s?null:i,{i:l,r:c}=e,a=t&&t.r,f=l.refs===ne?l.refs={}:l.refs,d=l.setupState;if(a!=null&&a!==c&&(oe(a)?(f[a]=null,X(d,a)&&(d[a]=null)):ue(a)&&(a.value=null)),W(c))ze(c,l,12,[o,f]);else{const p=oe(c),y=ue(c);if(p||y){const w=()=>{if(e.f){const T=p?X(d,c)?d[c]:f[c]:c.value;s?K(T)&&Er(T,i):K(T)?T.includes(i)||T.push(i):p?(f[c]=[i],X(d,c)&&(d[c]=f[c])):(c.value=[i],e.k&&(f[e.k]=c.value))}else p?(f[c]=o,X(d,c)&&(d[c]=o)):y&&(c.value=o,e.k&&(f[e.k]=o))};o?(w.id=-1,_e(w,n)):w()}}}let We=!1;const ln=e=>/svg/.test(e.namespaceURI)&&e.tagName!=="foreignObject",cn=e=>e.nodeType===8;function fc(e){const{mt:t,p:n,o:{patchProp:r,createText:s,nextSibling:i,parentNode:o,remove:l,insert:c,createComment:a}}=e,f=(v,_)=>{if(!_.hasChildNodes()){n(null,v,_),bn(),_._vnode=v;return}We=!1,d(_.firstChild,v,null,null,null),bn(),_._vnode=v,We&&console.error("Hydration completed but contains mismatches.")},d=(v,_,j,m,R,U=!1)=>{const B=cn(v)&&v.data==="[",b=()=>T(v,_,j,m,R,B),{type:M,ref:A,shapeFlag:N,patchFlag:F}=_;let q=v.nodeType;_.el=v,F===-2&&(U=!1,_.dynamicChildren=null);let $=null;switch(M){case Ct:q!==3?_.children===""?(c(_.el=s(""),o(v),v),$=v):$=b():(v.data!==_.children&&(We=!0,v.data=_.children),$=i(v));break;case me:q!==8||B?$=b():$=i(v);break;case jt:if(B&&(v=i(v),q=v.nodeType),q===1||q===3){$=v;const de=!_.children.length;for(let J=0;J<_.staticCount;J++)de&&(_.children+=$.nodeType===1?$.outerHTML:$.data),J===_.staticCount-1&&(_.anchor=$),$=i($);return B?i($):$}else b();break;case ye:B?$=w(v,_,j,m,R,U):$=b();break;default:if(N&1)q!==1||_.type.toLowerCase()!==v.tagName.toLowerCase()?$=b():$=p(v,_,j,m,R,U);else if(N&6){_.slotScopeIds=R;const de=o(v);if(t(_,de,null,j,m,ln(de),U),$=B?L(v):i(v),$&&cn($)&&$.data==="teleport end"&&($=i($)),bt(_)){let J;B?(J=ie(ye),J.anchor=$?$.previousSibling:de.lastChild):J=v.nodeType===3?Xi(""):ie("div"),J.el=v,_.component.subTree=J}}else N&64?q!==8?$=b():$=_.type.hydrate(v,_,j,m,R,U,e,y):N&128&&($=_.type.hydrate(v,_,j,m,ln(o(v)),R,U,e,d))}return A!=null&&xn(A,null,m,_),$},p=(v,_,j,m,R,U)=>{U=U||!!_.dynamicChildren;const{type:B,props:b,patchFlag:M,shapeFlag:A,dirs:N}=_,F=B==="input"&&N||B==="option";if(F||M!==-1){if(N&&Pe(_,null,j,"created"),b)if(F||!U||M&48)for(const $ in b)(F&&$.endsWith("value")||zt($)&&!Nt($))&&r(v,$,null,b[$],!1,void 0,j);else b.onClick&&r(v,"onClick",null,b.onClick,!1,void 0,j);let q;if((q=b&&b.onVnodeBeforeMount)&&Ce(q,j,_),N&&Pe(_,null,j,"beforeMount"),((q=b&&b.onVnodeMounted)||N)&&xi(()=>{q&&Ce(q,j,_),N&&Pe(_,null,j,"mounted")},m),A&16&&!(b&&(b.innerHTML||b.textContent))){let $=y(v.firstChild,_,v,j,m,R,U);for(;$;){We=!0;const de=$;$=$.nextSibling,l(de)}}else A&8&&v.textContent!==_.children&&(We=!0,v.textContent=_.children)}return v.nextSibling},y=(v,_,j,m,R,U,B)=>{B=B||!!_.dynamicChildren;const b=_.children,M=b.length;for(let A=0;A{const{slotScopeIds:B}=_;B&&(R=R?R.concat(B):B);const b=o(v),M=y(i(v),_,b,j,m,R,U);return M&&cn(M)&&M.data==="]"?i(_.anchor=M):(We=!0,c(_.anchor=a("]"),b,M),M)},T=(v,_,j,m,R,U)=>{if(We=!0,_.el=null,U){const M=L(v);for(;;){const A=i(v);if(A&&A!==M)l(A);else break}}const B=i(v),b=o(v);return l(v),n(null,_,b,B,j,m,ln(b),R),B},L=v=>{let _=0;for(;v;)if(v=i(v),v&&cn(v)&&(v.data==="["&&_++,v.data==="]")){if(_===0)return i(v);_--}return v};return[f,d]}const _e=xi;function dc(e){return Di(e)}function hc(e){return Di(e,fc)}function Di(e,t){const n=ir();n.__VUE__=!0;const{insert:r,remove:s,patchProp:i,createElement:o,createText:l,createComment:c,setText:a,setElementText:f,parentNode:d,nextSibling:p,setScopeId:y=Ne,insertStaticContent:w}=e,T=(u,h,g,C=null,E=null,O=null,P=!1,S=null,I=!!h.dynamicChildren)=>{if(u===h)return;u&&!Me(u,h)&&(C=Gt(u),Ie(u,E,O,!0),u=null),h.patchFlag===-2&&(I=!1,h.dynamicChildren=null);const{type:x,ref:k,shapeFlag:H}=h;switch(x){case Ct:L(u,h,g,C);break;case me:v(u,h,g,C);break;case jt:u==null&&_(h,g,C,P);break;case ye:F(u,h,g,C,E,O,P,S,I);break;default:H&1?R(u,h,g,C,E,O,P,S,I):H&6?q(u,h,g,C,E,O,P,S,I):(H&64||H&128)&&x.process(u,h,g,C,E,O,P,S,I,ft)}k!=null&&E&&xn(k,u&&u.ref,O,h||u,!h)},L=(u,h,g,C)=>{if(u==null)r(h.el=l(h.children),g,C);else{const E=h.el=u.el;h.children!==u.children&&a(E,h.children)}},v=(u,h,g,C)=>{u==null?r(h.el=c(h.children||""),g,C):h.el=u.el},_=(u,h,g,C)=>{[u.el,u.anchor]=w(u.children,h,g,C,u.el,u.anchor)},j=({el:u,anchor:h},g,C)=>{let E;for(;u&&u!==h;)E=p(u),r(u,g,C),u=E;r(h,g,C)},m=({el:u,anchor:h})=>{let g;for(;u&&u!==h;)g=p(u),s(u),u=g;s(h)},R=(u,h,g,C,E,O,P,S,I)=>{P=P||h.type==="svg",u==null?U(h,g,C,E,O,P,S,I):M(u,h,E,O,P,S,I)},U=(u,h,g,C,E,O,P,S)=>{let I,x;const{type:k,props:H,shapeFlag:D,transition:V,dirs:Y}=u;if(I=u.el=o(u.type,O,H&&H.is,H),D&8?f(I,u.children):D&16&&b(u.children,I,null,C,E,O&&k!=="foreignObject",P,S),Y&&Pe(u,null,C,"created"),B(I,u,u.scopeId,P,C),H){for(const Q in H)Q!=="value"&&!Nt(Q)&&i(I,Q,null,H[Q],O,u.children,C,E,je);"value"in H&&i(I,"value",null,H.value),(x=H.onVnodeBeforeMount)&&Ce(x,C,u)}Y&&Pe(u,null,C,"beforeMount");const ee=(!E||E&&!E.pendingBranch)&&V&&!V.persisted;ee&&V.beforeEnter(I),r(I,h,g),((x=H&&H.onVnodeMounted)||ee||Y)&&_e(()=>{x&&Ce(x,C,u),ee&&V.enter(I),Y&&Pe(u,null,C,"mounted")},E)},B=(u,h,g,C,E)=>{if(g&&y(u,g),C)for(let O=0;O{for(let x=I;x{const S=h.el=u.el;let{patchFlag:I,dynamicChildren:x,dirs:k}=h;I|=u.patchFlag&16;const H=u.props||ne,D=h.props||ne;let V;g&&nt(g,!1),(V=D.onVnodeBeforeUpdate)&&Ce(V,g,h,u),k&&Pe(h,u,g,"beforeUpdate"),g&&nt(g,!0);const Y=E&&h.type!=="foreignObject";if(x?A(u.dynamicChildren,x,S,g,C,Y,O):P||G(u,h,S,null,g,C,Y,O,!1),I>0){if(I&16)N(S,h,H,D,g,C,E);else if(I&2&&H.class!==D.class&&i(S,"class",null,D.class,E),I&4&&i(S,"style",H.style,D.style,E),I&8){const ee=h.dynamicProps;for(let Q=0;Q{V&&Ce(V,g,h,u),k&&Pe(h,u,g,"updated")},C)},A=(u,h,g,C,E,O,P)=>{for(let S=0;S{if(g!==C){if(g!==ne)for(const S in g)!Nt(S)&&!(S in C)&&i(u,S,g[S],null,P,h.children,E,O,je);for(const S in C){if(Nt(S))continue;const I=C[S],x=g[S];I!==x&&S!=="value"&&i(u,S,x,I,P,h.children,E,O,je)}"value"in C&&i(u,"value",g.value,C.value)}},F=(u,h,g,C,E,O,P,S,I)=>{const x=h.el=u?u.el:l(""),k=h.anchor=u?u.anchor:l("");let{patchFlag:H,dynamicChildren:D,slotScopeIds:V}=h;V&&(S=S?S.concat(V):V),u==null?(r(x,g,C),r(k,g,C),b(h.children,g,k,E,O,P,S,I)):H>0&&H&64&&D&&u.dynamicChildren?(A(u.dynamicChildren,D,g,E,O,P,S),(h.key!=null||E&&h===E.subTree)&&qr(u,h,!0)):G(u,h,g,k,E,O,P,S,I)},q=(u,h,g,C,E,O,P,S,I)=>{h.slotScopeIds=S,u==null?h.shapeFlag&512?E.ctx.activate(h,g,C,P,I):$(h,g,C,E,O,P,I):de(u,h,I)},$=(u,h,g,C,E,O,P)=>{const S=u.component=Cc(u,C,E);if(Jt(u)&&(S.ctx.renderer=ft),xc(S),S.asyncDep){if(E&&E.registerDep(S,J),!u.el){const I=S.subTree=ie(me);v(null,I,h,g)}return}J(S,u,h,g,E,O,P)},de=(u,h,g)=>{const C=h.component=u.component;if(Ol(u,h,g))if(C.asyncDep&&!C.asyncResolved){Z(C,h,g);return}else C.next=h,wl(C.update),C.update();else h.el=u.el,C.vnode=h},J=(u,h,g,C,E,O,P)=>{const S=()=>{if(u.isMounted){let{next:k,bu:H,u:D,parent:V,vnode:Y}=u,ee=k,Q;nt(u,!1),k?(k.el=Y.el,Z(u,k,P)):k=Y,H&&pn(H),(Q=k.props&&k.props.onVnodeBeforeUpdate)&&Ce(Q,V,k,Y),nt(u,!0);const le=Un(u),Se=u.subTree;u.subTree=le,T(Se,le,d(Se.el),Gt(Se),u,E,O),k.el=le.el,ee===null&&jr(u,le.el),D&&_e(D,E),(Q=k.props&&k.props.onVnodeUpdated)&&_e(()=>Ce(Q,V,k,Y),E)}else{let k;const{el:H,props:D}=h,{bm:V,m:Y,parent:ee}=u,Q=bt(h);if(nt(u,!1),V&&pn(V),!Q&&(k=D&&D.onVnodeBeforeMount)&&Ce(k,ee,h),nt(u,!0),H&&Dn){const le=()=>{u.subTree=Un(u),Dn(H,u.subTree,u,E,null)};Q?h.type.__asyncLoader().then(()=>!u.isUnmounted&&le()):le()}else{const le=u.subTree=Un(u);T(null,le,g,C,u,E,O),h.el=le.el}if(Y&&_e(Y,E),!Q&&(k=D&&D.onVnodeMounted)){const le=h;_e(()=>Ce(k,ee,le),E)}(h.shapeFlag&256||ee&&bt(ee.vnode)&&ee.vnode.shapeFlag&256)&&u.a&&_e(u.a,E),u.isMounted=!0,h=g=C=null}},I=u.effect=new Rr(S,()=>Pn(x),u.scope),x=u.update=()=>I.run();x.id=u.uid,nt(u,!0),x()},Z=(u,h,g)=>{h.component=u;const C=u.vnode.props;u.vnode=h,u.next=null,lc(u,h.props,C,g),uc(u,h.children,g),St(),ds(),Ot()},G=(u,h,g,C,E,O,P,S,I=!1)=>{const x=u&&u.children,k=u?u.shapeFlag:0,H=h.children,{patchFlag:D,shapeFlag:V}=h;if(D>0){if(D&128){Zt(x,H,g,C,E,O,P,S,I);return}else if(D&256){et(x,H,g,C,E,O,P,S,I);return}}V&8?(k&16&&je(x,E,O),H!==x&&f(g,H)):k&16?V&16?Zt(x,H,g,C,E,O,P,S,I):je(x,E,O,!0):(k&8&&f(g,""),V&16&&b(H,g,C,E,O,P,S,I))},et=(u,h,g,C,E,O,P,S,I)=>{u=u||gt,h=h||gt;const x=u.length,k=h.length,H=Math.min(x,k);let D;for(D=0;Dk?je(u,E,O,!0,!1,H):b(h,g,C,E,O,P,S,I,H)},Zt=(u,h,g,C,E,O,P,S,I)=>{let x=0;const k=h.length;let H=u.length-1,D=k-1;for(;x<=H&&x<=D;){const V=u[x],Y=h[x]=I?Ye(h[x]):xe(h[x]);if(Me(V,Y))T(V,Y,g,null,E,O,P,S,I);else break;x++}for(;x<=H&&x<=D;){const V=u[H],Y=h[D]=I?Ye(h[D]):xe(h[D]);if(Me(V,Y))T(V,Y,g,null,E,O,P,S,I);else break;H--,D--}if(x>H){if(x<=D){const V=D+1,Y=VD)for(;x<=H;)Ie(u[x],E,O,!0),x++;else{const V=x,Y=x,ee=new Map;for(x=Y;x<=D;x++){const be=h[x]=I?Ye(h[x]):xe(h[x]);be.key!=null&&ee.set(be.key,x)}let Q,le=0;const Se=D-Y+1;let dt=!1,ts=0;const Ft=new Array(Se);for(x=0;x=Se){Ie(be,E,O,!0);continue}let Fe;if(be.key!=null)Fe=ee.get(be.key);else for(Q=Y;Q<=D;Q++)if(Ft[Q-Y]===0&&Me(be,h[Q])){Fe=Q;break}Fe===void 0?Ie(be,E,O,!0):(Ft[Fe-Y]=x+1,Fe>=ts?ts=Fe:dt=!0,T(be,h[Fe],g,null,E,O,P,S,I),le++)}const ns=dt?pc(Ft):gt;for(Q=ns.length-1,x=Se-1;x>=0;x--){const be=Y+x,Fe=h[be],rs=be+1{const{el:O,type:P,transition:S,children:I,shapeFlag:x}=u;if(x&6){tt(u.component.subTree,h,g,C);return}if(x&128){u.suspense.move(h,g,C);return}if(x&64){P.move(u,h,g,ft);return}if(P===ye){r(O,h,g);for(let H=0;HS.enter(O),E);else{const{leave:H,delayLeave:D,afterLeave:V}=S,Y=()=>r(O,h,g),ee=()=>{H(O,()=>{Y(),V&&V()})};D?D(O,Y,ee):ee()}else r(O,h,g)},Ie=(u,h,g,C=!1,E=!1)=>{const{type:O,props:P,ref:S,children:I,dynamicChildren:x,shapeFlag:k,patchFlag:H,dirs:D}=u;if(S!=null&&xn(S,null,g,u,!0),k&256){h.ctx.deactivate(u);return}const V=k&1&&D,Y=!bt(u);let ee;if(Y&&(ee=P&&P.onVnodeBeforeUnmount)&&Ce(ee,h,u),k&6)bo(u.component,g,C);else{if(k&128){u.suspense.unmount(g,C);return}V&&Pe(u,null,h,"beforeUnmount"),k&64?u.type.remove(u,h,g,E,ft,C):x&&(O!==ye||H>0&&H&64)?je(x,h,g,!1,!0):(O===ye&&H&384||!E&&k&16)&&je(I,h,g),C&&Gr(u)}(Y&&(ee=P&&P.onVnodeUnmounted)||V)&&_e(()=>{ee&&Ce(ee,h,u),V&&Pe(u,null,h,"unmounted")},g)},Gr=u=>{const{type:h,el:g,anchor:C,transition:E}=u;if(h===ye){vo(g,C);return}if(h===jt){m(u);return}const O=()=>{s(g),E&&!E.persisted&&E.afterLeave&&E.afterLeave()};if(u.shapeFlag&1&&E&&!E.persisted){const{leave:P,delayLeave:S}=E,I=()=>P(g,O);S?S(u.el,O,I):I()}else O()},vo=(u,h)=>{let g;for(;u!==h;)g=p(u),s(u),u=g;s(h)},bo=(u,h,g)=>{const{bum:C,scope:E,update:O,subTree:P,um:S}=u;C&&pn(C),E.stop(),O&&(O.active=!1,Ie(P,u,h,g)),S&&_e(S,h),_e(()=>{u.isUnmounted=!0},h),h&&h.pendingBranch&&!h.isUnmounted&&u.asyncDep&&!u.asyncResolved&&u.suspenseId===h.pendingId&&(h.deps--,h.deps===0&&h.resolve())},je=(u,h,g,C=!1,E=!1,O=0)=>{for(let P=O;Pu.shapeFlag&6?Gt(u.component.subTree):u.shapeFlag&128?u.suspense.next():p(u.anchor||u.el),es=(u,h,g)=>{u==null?h._vnode&&Ie(h._vnode,null,null,!0):T(h._vnode||null,u,h,null,null,null,g),ds(),bn(),h._vnode=u},ft={p:T,um:Ie,m:tt,r:Gr,mt:$,mc:b,pc:G,pbc:A,n:Gt,o:e};let kn,Dn;return t&&([kn,Dn]=t(ft)),{render:es,hydrate:kn,createApp:sc(es,kn)}}function nt({effect:e,update:t},n){e.allowRecurse=t.allowRecurse=n}function qr(e,t,n=!1){const r=e.children,s=t.children;if(K(r)&&K(s))for(let i=0;i>1,e[n[l]]0&&(t[r]=n[i-1]),n[i]=r)}}for(i=n.length,o=n[i-1];i-- >0;)n[i]=o,o=t[o];return n}const gc=e=>e.__isTeleport,Ht=e=>e&&(e.disabled||e.disabled===""),Ts=e=>typeof SVGElement<"u"&&e instanceof SVGElement,mr=(e,t)=>{const n=e&&e.to;return oe(n)?t?t(n):null:n},mc={__isTeleport:!0,process(e,t,n,r,s,i,o,l,c,a){const{mc:f,pc:d,pbc:p,o:{insert:y,querySelector:w,createText:T,createComment:L}}=a,v=Ht(t.props);let{shapeFlag:_,children:j,dynamicChildren:m}=t;if(e==null){const R=t.el=T(""),U=t.anchor=T("");y(R,n,r),y(U,n,r);const B=t.target=mr(t.props,w),b=t.targetAnchor=T("");B&&(y(b,B),o=o||Ts(B));const M=(A,N)=>{_&16&&f(j,A,N,s,i,o,l,c)};v?M(n,U):B&&M(B,b)}else{t.el=e.el;const R=t.anchor=e.anchor,U=t.target=e.target,B=t.targetAnchor=e.targetAnchor,b=Ht(e.props),M=b?n:U,A=b?R:B;if(o=o||Ts(U),m?(p(e.dynamicChildren,m,M,s,i,o,l),qr(e,t,!0)):c||d(e,t,M,A,s,i,o,l,!1),v)b||an(t,n,R,a,1);else if((t.props&&t.props.to)!==(e.props&&e.props.to)){const N=t.target=mr(t.props,w);N&&an(t,N,null,a,0)}else b&&an(t,U,B,a,1)}Ui(t)},remove(e,t,n,r,{um:s,o:{remove:i}},o){const{shapeFlag:l,children:c,anchor:a,targetAnchor:f,target:d,props:p}=e;if(d&&i(f),(o||!Ht(p))&&(i(a),l&16))for(let y=0;y0?Te||gt:null,Ki(),xt>0&&Te&&Te.push(e),e}function gu(e,t,n,r,s,i){return Wi(Yi(e,t,n,r,s,i,!0))}function Vi(e,t,n,r,s){return Wi(ie(e,t,n,r,s,!0))}function Yt(e){return e?e.__v_isVNode===!0:!1}function Me(e,t){return e.type===t.type&&e.key===t.key}const Hn="__vInternal",qi=({key:e})=>e??null,gn=({ref:e,ref_key:t,ref_for:n})=>(typeof e=="number"&&(e=""+e),e!=null?oe(e)||ue(e)||W(e)?{i:fe,r:e,k:t,f:!!n}:e:null);function Yi(e,t=null,n=null,r=0,s=null,i=e===ye?0:1,o=!1,l=!1){const c={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&qi(t),ref:t&&gn(t),scopeId:Mn,slotScopeIds:null,children:n,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetAnchor:null,staticCount:0,shapeFlag:i,patchFlag:r,dynamicProps:s,dynamicChildren:null,appContext:null,ctx:fe};return l?(Xr(c,n),i&128&&e.normalize(c)):n&&(c.shapeFlag|=oe(n)?8:16),xt>0&&!o&&Te&&(c.patchFlag>0||i&6)&&c.patchFlag!==32&&Te.push(c),c}const ie=yc;function yc(e,t=null,n=null,r=0,s=null,i=!1){if((!e||e===Fi)&&(e=me),Yt(e)){const l=Ze(e,t,!0);return n&&Xr(l,n),xt>0&&!i&&Te&&(l.shapeFlag&6?Te[Te.indexOf(e)]=l:Te.push(l)),l.patchFlag|=-2,l}if(Oc(e)&&(e=e.__vccOpts),t){t=vc(t);let{class:l,style:c}=t;l&&!oe(l)&&(t.class=Sr(l)),te(c)&&(pi(c)&&!K(c)&&(c=ce({},c)),t.style=Ar(c))}const o=oe(e)?1:Rl(e)?128:gc(e)?64:te(e)?4:W(e)?2:0;return Yi(e,t,n,r,s,o,i,!0)}function vc(e){return e?pi(e)||Hn in e?ce({},e):e:null}function Ze(e,t,n=!1){const{props:r,ref:s,patchFlag:i,children:o}=e,l=t?bc(r||{},t):r;return{__v_isVNode:!0,__v_skip:!0,type:e.type,props:l,key:l&&qi(l),ref:t&&t.ref?n&&s?K(s)?s.concat(gn(t)):[s,gn(t)]:gn(t):s,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:o,target:e.target,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==ye?i===-1?16:i|16:i,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:e.transition,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&Ze(e.ssContent),ssFallback:e.ssFallback&&Ze(e.ssFallback),el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce}}function Xi(e=" ",t=0){return ie(Ct,null,e,t)}function mu(e,t){const n=ie(jt,null,e);return n.staticCount=t,n}function _u(e="",t=!1){return t?(Yr(),Vi(me,null,e)):ie(me,null,e)}function xe(e){return e==null||typeof e=="boolean"?ie(me):K(e)?ie(ye,null,e.slice()):typeof e=="object"?Ye(e):ie(Ct,null,String(e))}function Ye(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:Ze(e)}function Xr(e,t){let n=0;const{shapeFlag:r}=e;if(t==null)t=null;else if(K(t))n=16;else if(typeof t=="object")if(r&65){const s=t.default;s&&(s._c&&(s._d=!1),Xr(e,s()),s._c&&(s._d=!0));return}else{n=32;const s=t._;!s&&!(Hn in t)?t._ctx=fe:s===3&&fe&&(fe.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else W(t)?(t={default:t,_ctx:fe},n=32):(t=String(t),r&64?(n=16,t=[Xi(t)]):n=8);e.children=t,e.shapeFlag|=n}function bc(...e){const t={};for(let n=0;nae||fe;let zr,ht,Ss="__VUE_INSTANCE_SETTERS__";(ht=ir()[Ss])||(ht=ir()[Ss]=[]),ht.push(e=>ae=e),zr=e=>{ht.length>1?ht.forEach(t=>t(e)):ht[0](e)};const Ge=e=>{zr(e),e.scope.on()},Je=()=>{ae&&ae.scope.off(),zr(null)};function zi(e){return e.vnode.shapeFlag&4}let Tt=!1;function xc(e,t=!1){Tt=t;const{props:n,children:r}=e.vnode,s=zi(e);oc(e,n,s,t),ac(e,r);const i=s?Tc(e,t):void 0;return Tt=!1,i}function Tc(e,t){const n=e.type;e.accessCache=Object.create(null),e.proxy=$t(new Proxy(e.ctx,Jl));const{setup:r}=n;if(r){const s=e.setupContext=r.length>1?Qi(e):null;Ge(e),St();const i=ze(r,e,0,[e.props,s]);if(Ot(),Je(),xr(i)){if(i.then(Je,Je),t)return i.then(o=>{_r(e,o,t)}).catch(o=>{Rt(o,e,0)});e.asyncDep=i}else _r(e,i,t)}else Ji(e,t)}function _r(e,t,n){W(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:te(t)&&(e.setupState=_i(t)),Ji(e,n)}let Os;function Ji(e,t,n){const r=e.type;if(!e.render){if(!t&&Os&&!r.render){const s=r.template||Wr(e).template;if(s){const{isCustomElement:i,compilerOptions:o}=e.appContext.config,{delimiters:l,compilerOptions:c}=r,a=ce(ce({isCustomElement:i,delimiters:l},o),c);r.render=Os(s,a)}}e.render=r.render||Ne}Ge(e),St(),Zl(e),Ot(),Je()}function Ac(e){return e.attrsProxy||(e.attrsProxy=new Proxy(e.attrs,{get(t,n){return ve(e,"get","$attrs"),t[n]}}))}function Qi(e){const t=n=>{e.exposed=n||{}};return{get attrs(){return Ac(e)},slots:e.slots,emit:e.emit,expose:t}}function jn(e){if(e.exposed)return e.exposeProxy||(e.exposeProxy=new Proxy(_i($t(e.exposed)),{get(t,n){if(n in t)return t[n];if(n in Bt)return Bt[n](e)},has(t,n){return n in t||n in Bt}}))}function Sc(e,t=!0){return W(e)?e.displayName||e.name:e.name||t&&e.__name}function Oc(e){return W(e)&&"__vccOpts"in e}const re=(e,t)=>yl(e,t,Tt);function yr(e,t,n){const r=arguments.length;return r===2?te(t)&&!K(t)?Yt(t)?ie(e,null,[t]):ie(e,t):ie(e,null,t):(r>3?n=Array.prototype.slice.call(arguments,2):r===3&&Yt(n)&&(n=[n]),ie(e,t,n))}const Rc=Symbol.for("v-scx"),Ic=()=>wt(Rc),Fc="3.3.4",Pc="http://www.w3.org/2000/svg",ot=typeof document<"u"?document:null,Rs=ot&&ot.createElement("template"),Lc={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,r)=>{const s=t?ot.createElementNS(Pc,e):ot.createElement(e,n?{is:n}:void 0);return e==="select"&&r&&r.multiple!=null&&s.setAttribute("multiple",r.multiple),s},createText:e=>ot.createTextNode(e),createComment:e=>ot.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>ot.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,r,s,i){const o=n?n.previousSibling:t.lastChild;if(s&&(s===i||s.nextSibling))for(;t.insertBefore(s.cloneNode(!0),n),!(s===i||!(s=s.nextSibling)););else{Rs.innerHTML=r?`${e}`:e;const l=Rs.content;if(r){const c=l.firstChild;for(;c.firstChild;)l.appendChild(c.firstChild);l.removeChild(c)}t.insertBefore(l,n)}return[o?o.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}};function Mc(e,t,n){const r=e._vtc;r&&(t=(t?[t,...r]:[...r]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}function Nc(e,t,n){const r=e.style,s=oe(n);if(n&&!s){if(t&&!oe(t))for(const i in t)n[i]==null&&vr(r,i,"");for(const i in n)vr(r,i,n[i])}else{const i=r.display;s?t!==n&&(r.cssText=n):t&&e.removeAttribute("style"),"_vod"in e&&(r.display=i)}}const Is=/\s*!important$/;function vr(e,t,n){if(K(n))n.forEach(r=>vr(e,t,r));else if(n==null&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{const r=$c(e,t);Is.test(n)?e.setProperty(ut(r),n.replace(Is,""),"important"):e[r]=n}}const Fs=["Webkit","Moz","ms"],qn={};function $c(e,t){const n=qn[t];if(n)return n;let r=He(t);if(r!=="filter"&&r in e)return qn[t]=r;r=Sn(r);for(let s=0;sYn||(Uc.then(()=>Yn=0),Yn=Date.now());function Wc(e,t){const n=r=>{if(!r._vts)r._vts=Date.now();else if(r._vts<=n.attached)return;Ae(Vc(r,n.value),t,5,[r])};return n.value=e,n.attached=Kc(),n}function Vc(e,t){if(K(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(r=>s=>!s._stopped&&r&&r(s))}else return t}const Ms=/^on[a-z]/,qc=(e,t,n,r,s=!1,i,o,l,c)=>{t==="class"?Mc(e,r,s):t==="style"?Nc(e,n,r):zt(t)?wr(t)||kc(e,t,n,r,o):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):Yc(e,t,r,s))?Hc(e,t,r,i,o,l,c):(t==="true-value"?e._trueValue=r:t==="false-value"&&(e._falseValue=r),Bc(e,t,r,s))};function Yc(e,t,n,r){return r?!!(t==="innerHTML"||t==="textContent"||t in e&&Ms.test(t)&&W(n)):t==="spellcheck"||t==="draggable"||t==="translate"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA"||Ms.test(t)&&oe(n)?!1:t in e}const Ve="transition",Pt="animation",Zi=(e,{slots:t})=>yr(jl,Xc(e),t);Zi.displayName="Transition";const Gi={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String};Zi.props=ce({},Ai,Gi);const rt=(e,t=[])=>{K(e)?e.forEach(n=>n(...t)):e&&e(...t)},Ns=e=>e?K(e)?e.some(t=>t.length>1):e.length>1:!1;function Xc(e){const t={};for(const F in e)F in Gi||(t[F]=e[F]);if(e.css===!1)return t;const{name:n="v",type:r,duration:s,enterFromClass:i=`${n}-enter-from`,enterActiveClass:o=`${n}-enter-active`,enterToClass:l=`${n}-enter-to`,appearFromClass:c=i,appearActiveClass:a=o,appearToClass:f=l,leaveFromClass:d=`${n}-leave-from`,leaveActiveClass:p=`${n}-leave-active`,leaveToClass:y=`${n}-leave-to`}=e,w=zc(s),T=w&&w[0],L=w&&w[1],{onBeforeEnter:v,onEnter:_,onEnterCancelled:j,onLeave:m,onLeaveCancelled:R,onBeforeAppear:U=v,onAppear:B=_,onAppearCancelled:b=j}=t,M=(F,q,$)=>{st(F,q?f:l),st(F,q?a:o),$&&$()},A=(F,q)=>{F._isLeaving=!1,st(F,d),st(F,y),st(F,p),q&&q()},N=F=>(q,$)=>{const de=F?B:_,J=()=>M(q,F,$);rt(de,[q,J]),$s(()=>{st(q,F?c:i),qe(q,F?f:l),Ns(de)||Bs(q,r,T,J)})};return ce(t,{onBeforeEnter(F){rt(v,[F]),qe(F,i),qe(F,o)},onBeforeAppear(F){rt(U,[F]),qe(F,c),qe(F,a)},onEnter:N(!1),onAppear:N(!0),onLeave(F,q){F._isLeaving=!0;const $=()=>A(F,q);qe(F,d),Zc(),qe(F,p),$s(()=>{F._isLeaving&&(st(F,d),qe(F,y),Ns(m)||Bs(F,r,L,$))}),rt(m,[F,$])},onEnterCancelled(F){M(F,!1),rt(j,[F])},onAppearCancelled(F){M(F,!0),rt(b,[F])},onLeaveCancelled(F){A(F),rt(R,[F])}})}function zc(e){if(e==null)return null;if(te(e))return[Xn(e.enter),Xn(e.leave)];{const t=Xn(e);return[t,t]}}function Xn(e){return ei(e)}function qe(e,t){t.split(/\s+/).forEach(n=>n&&e.classList.add(n)),(e._vtc||(e._vtc=new Set)).add(t)}function st(e,t){t.split(/\s+/).forEach(r=>r&&e.classList.remove(r));const{_vtc:n}=e;n&&(n.delete(t),n.size||(e._vtc=void 0))}function $s(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let Jc=0;function Bs(e,t,n,r){const s=e._endId=++Jc,i=()=>{s===e._endId&&r()};if(n)return setTimeout(i,n);const{type:o,timeout:l,propCount:c}=Qc(e,t);if(!o)return r();const a=o+"end";let f=0;const d=()=>{e.removeEventListener(a,p),i()},p=y=>{y.target===e&&++f>=c&&d()};setTimeout(()=>{f(n[w]||"").split(", "),s=r(`${Ve}Delay`),i=r(`${Ve}Duration`),o=Hs(s,i),l=r(`${Pt}Delay`),c=r(`${Pt}Duration`),a=Hs(l,c);let f=null,d=0,p=0;t===Ve?o>0&&(f=Ve,d=o,p=i.length):t===Pt?a>0&&(f=Pt,d=a,p=c.length):(d=Math.max(o,a),f=d>0?o>a?Ve:Pt:null,p=f?f===Ve?i.length:c.length:0);const y=f===Ve&&/\b(transform|all)(,|$)/.test(r(`${Ve}Property`).toString());return{type:f,timeout:d,propCount:p,hasTransform:y}}function Hs(e,t){for(;e.lengthjs(n)+js(e[r])))}function js(e){return Number(e.slice(0,-1).replace(",","."))*1e3}function Zc(){return document.body.offsetHeight}const ks=e=>{const t=e.props["onUpdate:modelValue"]||!1;return K(t)?n=>pn(t,n):t};function Gc(e){e.target.composing=!0}function Ds(e){const t=e.target;t.composing&&(t.composing=!1,t.dispatchEvent(new Event("input")))}const yu={created(e,{modifiers:{lazy:t,trim:n,number:r}},s){e._assign=ks(s);const i=r||s.props&&s.props.type==="number";pt(e,t?"change":"input",o=>{if(o.target.composing)return;let l=e.value;n&&(l=l.trim()),i&&(l=sr(l)),e._assign(l)}),n&&pt(e,"change",()=>{e.value=e.value.trim()}),t||(pt(e,"compositionstart",Gc),pt(e,"compositionend",Ds),pt(e,"change",Ds))},mounted(e,{value:t}){e.value=t??""},beforeUpdate(e,{value:t,modifiers:{lazy:n,trim:r,number:s}},i){if(e._assign=ks(i),e.composing||document.activeElement===e&&e.type!=="range"&&(n||r&&e.value.trim()===t||(s||e.type==="number")&&sr(e.value)===t))return;const o=t??"";e.value!==o&&(e.value=o)}},ea=["ctrl","shift","alt","meta"],ta={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&e.button!==0,middle:e=>"button"in e&&e.button!==1,right:e=>"button"in e&&e.button!==2,exact:(e,t)=>ea.some(n=>e[`${n}Key`]&&!t.includes(n))},vu=(e,t)=>(n,...r)=>{for(let s=0;sn=>{if(!("key"in n))return;const r=ut(n.key);if(t.some(s=>s===r||na[s]===r))return e(n)},eo=ce({patchProp:qc},Lc);let Dt,Us=!1;function ra(){return Dt||(Dt=dc(eo))}function sa(){return Dt=Us?Dt:hc(eo),Us=!0,Dt}const wu=(...e)=>{const t=ra().createApp(...e),{mount:n}=t;return t.mount=r=>{const s=to(r);if(!s)return;const i=t._component;!W(i)&&!i.render&&!i.template&&(i.template=s.innerHTML),s.innerHTML="";const o=n(s,!1,s instanceof SVGElement);return s instanceof Element&&(s.removeAttribute("v-cloak"),s.setAttribute("data-v-app","")),o},t},Eu=(...e)=>{const t=sa().createApp(...e),{mount:n}=t;return t.mount=r=>{const s=to(r);if(s)return n(s,!0,s instanceof SVGElement)},t};function to(e){return oe(e)?document.querySelector(e):e}const Cu="/me.jpg",xu=(e,t)=>{const n=e.__vccOpts||e;for(const[r,s]of t)n[r]=s;return n},ia=window.__VP_SITE_DATA__;function Jr(e){return ri()?(No(e),!0):!1}function Be(e){return typeof e=="function"?e():mi(e)}const no=typeof window<"u"&&typeof document<"u";typeof WorkerGlobalScope<"u"&&globalThis instanceof WorkerGlobalScope;const oa=Object.prototype.toString,la=e=>oa.call(e)==="[object Object]",Xt=()=>{},Ks=ca();function ca(){var e,t;return no&&((e=window==null?void 0:window.navigator)==null?void 0:e.userAgent)&&(/iP(?:ad|hone|od)/.test(window.navigator.userAgent)||((t=window==null?void 0:window.navigator)==null?void 0:t.maxTouchPoints)>2&&/iPad|Macintosh/.test(window==null?void 0:window.navigator.userAgent))}function aa(e,t){function n(...r){return new Promise((s,i)=>{Promise.resolve(e(()=>t.apply(this,r),{fn:t,thisArg:this,args:r})).then(s).catch(i)})}return n}const ro=e=>e();function ua(e,t={}){let n,r,s=Xt;const i=l=>{clearTimeout(l),s(),s=Xt};return l=>{const c=Be(e),a=Be(t.maxWait);return n&&i(n),c<=0||a!==void 0&&a<=0?(r&&(i(r),r=null),Promise.resolve(l())):new Promise((f,d)=>{s=t.rejectOnCancel?d:f,a&&!r&&(r=setTimeout(()=>{n&&i(n),r=null,f(l())},a)),n=setTimeout(()=>{r&&i(r),r=null,f(l())},c)})}}function fa(e=ro){const t=se(!0);function n(){t.value=!1}function r(){t.value=!0}const s=(...i)=>{t.value&&e(...i)};return{isActive:In(t),pause:n,resume:r,eventFilter:s}}function da(e){return Qt()}function so(...e){if(e.length!==1)return ml(...e);const t=e[0];return typeof t=="function"?In(hl(()=>({get:t,set:Xt}))):se(t)}function io(e,t,n={}){const{eventFilter:r=ro,...s}=n;return $e(e,aa(r,t),s)}function ha(e,t,n={}){const{eventFilter:r,...s}=n,{eventFilter:i,pause:o,resume:l,isActive:c}=fa(r);return{stop:io(e,t,{...s,eventFilter:i}),pause:o,resume:l,isActive:c}}function Qr(e,t=!0,n){da()?It(e,n):t?e():Fn(e)}function Tu(e,t,n={}){const{debounce:r=0,maxWait:s=void 0,...i}=n;return io(e,t,{...i,eventFilter:ua(r,{maxWait:s})})}function Au(e,t,n){let r;ue(n)?r={evaluating:n}:r={};const{lazy:s=!1,evaluating:i=void 0,shallow:o=!0,onError:l=Xt}=r,c=se(!s),a=o?Br(t):se(t);let f=0;return Dr(async d=>{if(!c.value)return;f++;const p=f;let y=!1;i&&Promise.resolve().then(()=>{i.value=!0});try{const w=await e(T=>{d(()=>{i&&(i.value=!1),y||T()})});p===f&&(a.value=w)}catch(w){l(w)}finally{i&&p===f&&(i.value=!1),y=!0}}),s?re(()=>(c.value=!0,a.value)):a}function oo(e){var t;const n=Be(e);return(t=n==null?void 0:n.$el)!=null?t:n}const Re=no?window:void 0;function At(...e){let t,n,r,s;if(typeof e[0]=="string"||Array.isArray(e[0])?([n,r,s]=e,t=Re):[t,n,r,s]=e,!t)return Xt;Array.isArray(n)||(n=[n]),Array.isArray(r)||(r=[r]);const i=[],o=()=>{i.forEach(f=>f()),i.length=0},l=(f,d,p,y)=>(f.addEventListener(d,p,y),()=>f.removeEventListener(d,p,y)),c=$e(()=>[oo(t),Be(s)],([f,d])=>{if(o(),!f)return;const p=la(d)?{...d}:d;i.push(...n.flatMap(y=>r.map(w=>l(f,y,w,p))))},{immediate:!0,flush:"post"}),a=()=>{c(),o()};return Jr(a),a}function pa(e){return typeof e=="function"?e:typeof e=="string"?t=>t.key===e:Array.isArray(e)?t=>e.includes(t.key):()=>!0}function Su(...e){let t,n,r={};e.length===3?(t=e[0],n=e[1],r=e[2]):e.length===2?typeof e[1]=="object"?(t=!0,n=e[0],r=e[1]):(t=e[0],n=e[1]):(t=!0,n=e[0]);const{target:s=Re,eventName:i="keydown",passive:o=!1,dedupe:l=!1}=r,c=pa(t);return At(s,i,f=>{f.repeat&&Be(l)||c(f)&&n(f)},o)}function ga(){const e=se(!1),t=Qt();return t&&It(()=>{e.value=!0},t),e}function ma(e){const t=ga();return re(()=>(t.value,!!e()))}function lo(e,t={}){const{window:n=Re}=t,r=ma(()=>n&&"matchMedia"in n&&typeof n.matchMedia=="function");let s;const i=se(!1),o=a=>{i.value=a.matches},l=()=>{s&&("removeEventListener"in s?s.removeEventListener("change",o):s.removeListener(o))},c=Dr(()=>{r.value&&(l(),s=n.matchMedia(Be(e)),"addEventListener"in s?s.addEventListener("change",o):s.addListener(o),i.value=s.matches)});return Jr(()=>{c(),l(),s=void 0}),i}const un=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{},fn="__vueuse_ssr_handlers__",_a=ya();function ya(){return fn in un||(un[fn]=un[fn]||{}),un[fn]}function co(e,t){return _a[e]||t}function va(e){return e==null?"any":e instanceof Set?"set":e instanceof Map?"map":e instanceof Date?"date":typeof e=="boolean"?"boolean":typeof e=="string"?"string":typeof e=="object"?"object":Number.isNaN(e)?"any":"number"}const ba={boolean:{read:e=>e==="true",write:e=>String(e)},object:{read:e=>JSON.parse(e),write:e=>JSON.stringify(e)},number:{read:e=>Number.parseFloat(e),write:e=>String(e)},any:{read:e=>e,write:e=>String(e)},string:{read:e=>e,write:e=>String(e)},map:{read:e=>new Map(JSON.parse(e)),write:e=>JSON.stringify(Array.from(e.entries()))},set:{read:e=>new Set(JSON.parse(e)),write:e=>JSON.stringify(Array.from(e))},date:{read:e=>new Date(e),write:e=>e.toISOString()}},Ws="vueuse-storage";function Zr(e,t,n,r={}){var s;const{flush:i="pre",deep:o=!0,listenToStorageChanges:l=!0,writeDefaults:c=!0,mergeDefaults:a=!1,shallow:f,window:d=Re,eventFilter:p,onError:y=A=>{console.error(A)},initOnMounted:w}=r,T=(f?Br:se)(typeof t=="function"?t():t);if(!n)try{n=co("getDefaultStorage",()=>{var A;return(A=Re)==null?void 0:A.localStorage})()}catch(A){y(A)}if(!n)return T;const L=Be(t),v=va(L),_=(s=r.serializer)!=null?s:ba[v],{pause:j,resume:m}=ha(T,()=>U(T.value),{flush:i,deep:o,eventFilter:p});d&&l&&Qr(()=>{At(d,"storage",b),At(d,Ws,M),w&&b()}),w||b();function R(A,N){d&&d.dispatchEvent(new CustomEvent(Ws,{detail:{key:e,oldValue:A,newValue:N,storageArea:n}}))}function U(A){try{const N=n.getItem(e);if(A==null)R(N,null),n.removeItem(e);else{const F=_.write(A);N!==F&&(n.setItem(e,F),R(N,F))}}catch(N){y(N)}}function B(A){const N=A?A.newValue:n.getItem(e);if(N==null)return c&&L!=null&&n.setItem(e,_.write(L)),L;if(!A&&a){const F=_.read(N);return typeof a=="function"?a(F,L):v==="object"&&!Array.isArray(F)?{...L,...F}:F}else return typeof N!="string"?N:_.read(N)}function b(A){if(!(A&&A.storageArea!==n)){if(A&&A.key==null){T.value=L;return}if(!(A&&A.key!==e)){j();try{(A==null?void 0:A.newValue)!==_.write(T.value)&&(T.value=B(A))}catch(N){y(N)}finally{A?Fn(m):m()}}}}function M(A){b(A.detail)}return T}function ao(e){return lo("(prefers-color-scheme: dark)",e)}function wa(e={}){const{selector:t="html",attribute:n="class",initialValue:r="auto",window:s=Re,storage:i,storageKey:o="vueuse-color-scheme",listenToStorageChanges:l=!0,storageRef:c,emitAuto:a,disableTransition:f=!0}=e,d={auto:"",light:"light",dark:"dark",...e.modes||{}},p=ao({window:s}),y=re(()=>p.value?"dark":"light"),w=c||(o==null?so(r):Zr(o,r,i,{window:s,listenToStorageChanges:l})),T=re(()=>w.value==="auto"?y.value:w.value),L=co("updateHTMLAttrs",(m,R,U)=>{const B=typeof m=="string"?s==null?void 0:s.document.querySelector(m):oo(m);if(!B)return;let b;if(f&&(b=s.document.createElement("style"),b.appendChild(document.createTextNode("*,*::before,*::after{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}")),s.document.head.appendChild(b)),R==="class"){const M=U.split(/\s/g);Object.values(d).flatMap(A=>(A||"").split(/\s/g)).filter(Boolean).forEach(A=>{M.includes(A)?B.classList.add(A):B.classList.remove(A)})}else B.setAttribute(R,U);f&&(s.getComputedStyle(b).opacity,document.head.removeChild(b))});function v(m){var R;L(t,n,(R=d[m])!=null?R:m)}function _(m){e.onChanged?e.onChanged(m,v):v(m)}$e(T,_,{flush:"post",immediate:!0}),Qr(()=>_(T.value));const j=re({get(){return a?w.value:T.value},set(m){w.value=m}});try{return Object.assign(j,{store:w,system:y,state:T})}catch{return j}}function Ea(e={}){const{valueDark:t="dark",valueLight:n="",window:r=Re}=e,s=wa({...e,onChanged:(l,c)=>{var a;e.onChanged?(a=e.onChanged)==null||a.call(e,l==="dark",c,l):c(l)},modes:{dark:t,light:n}}),i=re(()=>s.system?s.system.value:ao({window:r}).value?"dark":"light");return re({get(){return s.value==="dark"},set(l){const c=l?"dark":"light";i.value===c?s.value="auto":s.value=c}})}function zn(e){return typeof Window<"u"&&e instanceof Window?e.document.documentElement:typeof Document<"u"&&e instanceof Document?e.documentElement:e}function Ou(e,t,n={}){const{window:r=Re}=n;return Zr(e,t,r==null?void 0:r.localStorage,n)}function uo(e){const t=window.getComputedStyle(e);if(t.overflowX==="scroll"||t.overflowY==="scroll"||t.overflowX==="auto"&&e.clientWidth1?!0:(t.preventDefault&&t.preventDefault(),!1)}const Jn=new WeakMap;function Ru(e,t=!1){const n=se(t);let r=null,s="";$e(so(e),l=>{const c=zn(Be(l));if(c){const a=c;if(Jn.get(a)||Jn.set(a,a.style.overflow),a.style.overflow!=="hidden"&&(s=a.style.overflow),a.style.overflow==="hidden")return n.value=!0;if(n.value)return a.style.overflow="hidden"}},{immediate:!0});const i=()=>{const l=zn(Be(e));!l||n.value||(Ks&&(r=At(l,"touchmove",c=>{Ca(c)},{passive:!1})),l.style.overflow="hidden",n.value=!0)},o=()=>{const l=zn(Be(e));!l||!n.value||(Ks&&(r==null||r()),l.style.overflow=s,Jn.delete(l),n.value=!1)};return Jr(o),re({get(){return n.value},set(l){l?i():o()}})}function Iu(e,t,n={}){const{window:r=Re}=n;return Zr(e,t,r==null?void 0:r.sessionStorage,n)}function Fu(e={}){const{window:t=Re,behavior:n="auto"}=e;if(!t)return{x:se(0),y:se(0)};const r=se(t.scrollX),s=se(t.scrollY),i=re({get(){return r.value},set(l){scrollTo({left:l,behavior:n})}}),o=re({get(){return s.value},set(l){scrollTo({top:l,behavior:n})}});return At(t,"scroll",()=>{r.value=t.scrollX,s.value=t.scrollY},{capture:!1,passive:!0}),{x:i,y:o}}function Pu(e={}){const{window:t=Re,initialWidth:n=Number.POSITIVE_INFINITY,initialHeight:r=Number.POSITIVE_INFINITY,listenOrientation:s=!0,includeScrollbar:i=!0}=e,o=se(n),l=se(r),c=()=>{t&&(i?(o.value=t.innerWidth,l.value=t.innerHeight):(o.value=t.document.documentElement.clientWidth,l.value=t.document.documentElement.clientHeight))};if(c(),Qr(c),At("resize",c,{passive:!0}),s){const a=lo("(orientation: portrait)");$e(a,()=>c())}return{width:o,height:l}}var Qn={BASE_URL:"/",MODE:"production",DEV:!1,PROD:!0,SSR:!1},Zn={};const fo=/^(?:[a-z]+:|\/\/)/i,xa="vitepress-theme-appearance",Ta=/#.*$/,Aa=/[?#].*$/,Sa=/(?:(^|\/)index)?\.(?:md|html)$/,he=typeof document<"u",ho={relativePath:"404.md",filePath:"",title:"404",description:"Not Found",headers:[],frontmatter:{sidebar:!1,layout:"page"},lastUpdated:0,isNotFound:!0};function Oa(e,t,n=!1){if(t===void 0)return!1;if(e=Vs(`/${e}`),n)return new RegExp(t).test(e);if(Vs(t)!==e)return!1;const r=t.match(Ta);return r?(he?location.hash:"")===r[0]:!0}function Vs(e){return decodeURI(e).replace(Aa,"").replace(Sa,"$1")}function Ra(e){return fo.test(e)}function Ia(e,t){return Object.keys((e==null?void 0:e.locales)||{}).find(n=>n!=="root"&&!Ra(n)&&Oa(t,`/${n}/`,!0))||"root"}function Fa(e,t){var r,s,i,o,l,c,a;const n=Ia(e,t);return Object.assign({},e,{localeIndex:n,lang:((r=e.locales[n])==null?void 0:r.lang)??e.lang,dir:((s=e.locales[n])==null?void 0:s.dir)??e.dir,title:((i=e.locales[n])==null?void 0:i.title)??e.title,titleTemplate:((o=e.locales[n])==null?void 0:o.titleTemplate)??e.titleTemplate,description:((l=e.locales[n])==null?void 0:l.description)??e.description,head:go(e.head,((c=e.locales[n])==null?void 0:c.head)??[]),themeConfig:{...e.themeConfig,...(a=e.locales[n])==null?void 0:a.themeConfig}})}function po(e,t){const n=t.title||e.title,r=t.titleTemplate??e.titleTemplate;if(typeof r=="string"&&r.includes(":title"))return r.replace(/:title/g,n);const s=Pa(e.title,r);return n===s.slice(3)?n:`${n}${s}`}function Pa(e,t){return t===!1?"":t===!0||t===void 0?` | ${e}`:e===t?"":` | ${t}`}function La(e,t){const[n,r]=t;if(n!=="meta")return!1;const s=Object.entries(r)[0];return s==null?!1:e.some(([i,o])=>i===n&&o[s[0]]===s[1])}function go(e,t){return[...e.filter(n=>!La(t,n)),...t]}const Ma=/[\u0000-\u001F"#$&*+,:;<=>?[\]^`{|}\u007F]/g,Na=/^[a-z]:/i;function qs(e){const t=Na.exec(e),n=t?t[0]:"";return n+e.slice(n.length).replace(Ma,"_").replace(/(^|\/)_+(?=[^/]*$)/,"$1")}const Gn=new Set;function $a(e){if(Gn.size===0){const n=typeof process=="object"&&(Zn==null?void 0:Zn.VITE_EXTRA_EXTENSIONS)||(Qn==null?void 0:Qn.VITE_EXTRA_EXTENSIONS)||"";("3g2,3gp,aac,ai,apng,au,avif,bin,bmp,cer,class,conf,crl,css,csv,dll,doc,eps,epub,exe,gif,gz,ics,ief,jar,jpe,jpeg,jpg,js,json,jsonld,m4a,man,mid,midi,mjs,mov,mp2,mp3,mp4,mpe,mpeg,mpg,mpp,oga,ogg,ogv,ogx,opus,otf,p10,p7c,p7m,p7s,pdf,png,ps,qt,roff,rtf,rtx,ser,svg,t,tif,tiff,tr,ts,tsv,ttf,txt,vtt,wav,weba,webm,webp,woff,woff2,xhtml,xml,yaml,yml,zip"+(n&&typeof n=="string"?","+n:"")).split(",").forEach(r=>Gn.add(r))}const t=e.split(".").pop();return t==null||!Gn.has(t.toLowerCase())}function Lu(e){return e.replace(/[|\\{}()[\]^$+*?.]/g,"\\$&").replace(/-/g,"\\x2d")}const Ba=Symbol(),at=Br(ia);function Mu(e){const t=re(()=>Fa(at.value,e.data.relativePath)),n=t.value.appearance,r=n==="force-dark"?se(!0):n?Ea({storageKey:xa,initialValue:()=>typeof n=="string"?n:"auto",...typeof n=="object"?n:{}}):se(!1),s=se(he?location.hash:"");return he&&window.addEventListener("hashchange",()=>{s.value=location.hash}),$e(()=>e.data,()=>{s.value=he?location.hash:""}),{site:t,theme:re(()=>t.value.themeConfig),page:re(()=>e.data),frontmatter:re(()=>e.data.frontmatter),params:re(()=>e.data.params),lang:re(()=>t.value.lang),dir:re(()=>e.data.frontmatter.dir||t.value.dir),localeIndex:re(()=>t.value.localeIndex||"root"),title:re(()=>po(t.value,e.data)),description:re(()=>e.data.description||t.value.description),isDark:r,hash:re(()=>s.value)}}function Ha(){const e=wt(Ba);if(!e)throw new Error("vitepress data not properly injected in app");return e}function ja(e,t){return`${e}${t}`.replace(/\/+/g,"/")}function Ys(e){return fo.test(e)||!e.startsWith("/")?e:ja(at.value.base,e)}function ka(e){let t=e.replace(/\.html$/,"");if(t=decodeURIComponent(t),t=t.replace(/\/$/,"/index"),he){const n="/";t=qs(t.slice(n.length).replace(/\//g,"_")||"index")+".md";let r=__VP_HASH_MAP__[t.toLowerCase()];if(r||(t=t.endsWith("_index.md")?t.slice(0,-9)+".md":t.slice(0,-3)+"_index.md",r=__VP_HASH_MAP__[t.toLowerCase()]),!r)return null;t=`${n}assets/${t}.${r}.js`}else t=`./${qs(t.slice(1).replace(/\//g,"_"))}.md.js`;return t}let mn=[];function Nu(e){mn.push(e),Bn(()=>{mn=mn.filter(t=>t!==e)})}function Da(){let e=at.value.scrollOffset,t=0,n=24;if(typeof e=="object"&&"padding"in e&&(n=e.padding,e=e.selector),typeof e=="number")t=e;else if(typeof e=="string")t=Xs(e,n);else if(Array.isArray(e))for(const r of e){const s=Xs(r,n);if(s){t=s;break}}return t}function Xs(e,t){const n=document.querySelector(e);if(!n)return 0;const r=n.getBoundingClientRect().bottom;return r<0?0:r+t}const Ua=Symbol(),mo="http://a.com",Ka=()=>({path:"/",component:null,data:ho});function $u(e,t){const n=Rn(Ka()),r={route:n,go:s};async function s(l=he?location.href:"/"){var c,a;l=er(l),await((c=r.onBeforeRouteChange)==null?void 0:c.call(r,l))!==!1&&(he&&l!==er(location.href)&&(history.replaceState({scrollPosition:window.scrollY},""),history.pushState({},"",l)),await o(l),await((a=r.onAfterRouteChanged)==null?void 0:a.call(r,l)))}let i=null;async function o(l,c=0,a=!1){var p;if(await((p=r.onBeforePageLoad)==null?void 0:p.call(r,l))===!1)return;const f=new URL(l,mo),d=i=f.pathname;try{let y=await e(d);if(!y)throw new Error(`Page not found: ${d}`);if(i===d){i=null;const{default:w,__pageData:T}=y;if(!w)throw new Error(`Invalid route component: ${w}`);n.path=he?d:Ys(d),n.component=$t(w),n.data=$t(T),he&&Fn(()=>{let L=at.value.base+T.relativePath.replace(/(?:(^|\/)index)?\.md$/,"$1");if(!at.value.cleanUrls&&!L.endsWith("/")&&(L+=".html"),L!==f.pathname&&(f.pathname=L,l=L+f.search+f.hash,history.replaceState({},"",l)),f.hash&&!c){let v=null;try{v=document.getElementById(decodeURIComponent(f.hash).slice(1))}catch(_){console.warn(_)}if(v){zs(v,f.hash);return}}window.scrollTo(0,c)})}}catch(y){if(!/fetch|Page not found/.test(y.message)&&!/^\/404(\.html|\/)?$/.test(l)&&console.error(y),!a)try{const w=await fetch(at.value.base+"hashmap.json");window.__VP_HASH_MAP__=await w.json(),await o(l,c,!0);return}catch{}if(i===d){i=null,n.path=he?d:Ys(d),n.component=t?$t(t):null;const w=he?d.replace(/(^|\/)$/,"$1index").replace(/(\.html)?$/,".md").replace(/^\//,""):"404.md";n.data={...ho,relativePath:w}}}}return he&&(history.state===null&&history.replaceState({},""),window.addEventListener("click",l=>{if(l.target.closest("button"))return;const a=l.target.closest("a");if(a&&!a.closest(".vp-raw")&&(a instanceof SVGElement||!a.download)){const{target:f}=a,{href:d,origin:p,pathname:y,hash:w,search:T}=new URL(a.href instanceof SVGAnimatedString?a.href.animVal:a.href,a.baseURI),L=new URL(location.href);!l.ctrlKey&&!l.shiftKey&&!l.altKey&&!l.metaKey&&!f&&p===L.origin&&$a(y)&&(l.preventDefault(),y===L.pathname&&T===L.search?(w!==L.hash&&(history.pushState({},"",d),window.dispatchEvent(new HashChangeEvent("hashchange",{oldURL:L.href,newURL:d}))),w?zs(a,w,a.classList.contains("header-anchor")):window.scrollTo(0,0)):s(d))}},{capture:!0}),window.addEventListener("popstate",async l=>{var c;l.state!==null&&(await o(er(location.href),l.state&&l.state.scrollPosition||0),(c=r.onAfterRouteChanged)==null||c.call(r,location.href))}),window.addEventListener("hashchange",l=>{l.preventDefault()})),r}function Wa(){const e=wt(Ua);if(!e)throw new Error("useRouter() is called without provider.");return e}function _o(){return Wa().route}function zs(e,t,n=!1){let r=null;try{r=e.classList.contains("header-anchor")?e:document.getElementById(decodeURIComponent(t).slice(1))}catch(s){console.warn(s)}if(r){let s=function(){!n||Math.abs(o-window.scrollY)>window.innerHeight?window.scrollTo(0,o):window.scrollTo({left:0,top:o,behavior:"smooth"})};const i=parseInt(window.getComputedStyle(r).paddingTop,10),o=window.scrollY+r.getBoundingClientRect().top-Da()+i;requestAnimationFrame(s)}}function er(e){const t=new URL(e,mo);return t.pathname=t.pathname.replace(/(^|\/)index(\.html)?$/,"$1"),at.value.cleanUrls?t.pathname=t.pathname.replace(/\.html$/,""):!t.pathname.endsWith("/")&&!t.pathname.endsWith(".html")&&(t.pathname+=".html"),t.pathname+t.search+t.hash}const tr=()=>mn.forEach(e=>e()),Bu=Ur({name:"VitePressContent",props:{as:{type:[Object,String],default:"div"}},setup(e){const t=_o(),{site:n}=Ha();return()=>yr(e.as,n.value.contentProps??{style:{position:"relative"}},[t.component?yr(t.component,{onVnodeMounted:tr,onVnodeUpdated:tr,onVnodeUnmounted:tr}):"404 Page Not Found"])}}),Hu="/garden/screenshot_1717381273245_0.png",ju="/garden/da2_1717378483173_0.png",ku="/garden/editors_1717378509527_0.png",Du="/garden/simulator_1717378525890_0.jpg",Uu="/garden/da1_1717378469912_0.png",Ku="/garden/da6_1717379962786_0.png",Wu="/garden/da7_1717379991458_0.png",Vu="/garden/da8_1717380011914_0.png",qu="/garden/da3_1717380046653_0.png",Yu="/garden/da9_1717380177060_0.png",Xu="/garden/6346b024-885e-45e0-9df6-5ee0311133f7_1718332409063_0.png",zu="/garden/ce7b2612-2ddb-423e-82eb-95c2ed08c4da_1718332277410_0.png",Ju="/garden/system-architecture-600_1717384793933_0.jpg",Qu="/garden/new-interface_1717384734845_0.png",Zu="/garden/documentation_1717384823218_0.png",Gu="/garden/unittests_1717384825666_0.png",ef="/garden/screenshot_1717383987886_0.png",tf="/garden/debug_1717384018620_0.png",nf="/garden/sandsoftime_1717383994964_0.png",rf="/paperpilot.png",Va="modulepreload",qa=function(e){return"/"+e},Js={},sf=function(t,n,r){let s=Promise.resolve();if(n&&n.length>0){document.getElementsByTagName("link");const i=document.querySelector("meta[property=csp-nonce]"),o=(i==null?void 0:i.nonce)||(i==null?void 0:i.getAttribute("nonce"));s=Promise.all(n.map(l=>{if(l=qa(l),l in Js)return;Js[l]=!0;const c=l.endsWith(".css"),a=c?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${l}"]${a}`))return;const f=document.createElement("link");if(f.rel=c?"stylesheet":Va,c||(f.as="script",f.crossOrigin=""),f.href=l,o&&f.setAttribute("nonce",o),document.head.appendChild(f),c)return new Promise((d,p)=>{f.addEventListener("load",d),f.addEventListener("error",()=>p(new Error(`Unable to preload CSS for ${l}`)))})}))}return s.then(()=>t()).catch(i=>{const o=new Event("vite:preloadError",{cancelable:!0});if(o.payload=i,window.dispatchEvent(o),!o.defaultPrevented)throw i})},of=Ur({setup(e,{slots:t}){const n=se(!1);return It(()=>{n.value=!0}),()=>n.value&&t.default?t.default():null}});function lf(){he&&window.addEventListener("click",e=>{var n;const t=e.target;if(t.matches(".vp-code-group input")){const r=(n=t.parentElement)==null?void 0:n.parentElement;if(!r)return;const s=Array.from(r.querySelectorAll("input")).indexOf(t);if(s<0)return;const i=r.querySelector(".blocks");if(!i)return;const o=Array.from(i.children).find(a=>a.classList.contains("active"));if(!o)return;const l=i.children[s];if(!l||o===l)return;o.classList.remove("active"),l.classList.add("active");const c=r==null?void 0:r.querySelector(`label[for="${t.id}"]`);c==null||c.scrollIntoView({block:"nearest"})}})}function cf(){if(he){const e=new WeakMap;window.addEventListener("click",t=>{var r;const n=t.target;if(n.matches('div[class*="language-"] > button.copy')){const s=n.parentElement,i=(r=n.nextElementSibling)==null?void 0:r.nextElementSibling;if(!s||!i)return;const o=/language-(shellscript|shell|bash|sh|zsh)/.test(s.className),l=[".vp-copy-ignore",".diff.remove"],c=i.cloneNode(!0);c.querySelectorAll(l.join(",")).forEach(f=>f.remove());let a=c.textContent||"";o&&(a=a.replace(/^ *(\$|>) /gm,"").trim()),Ya(a).then(()=>{n.classList.add("copied"),clearTimeout(e.get(n));const f=setTimeout(()=>{n.classList.remove("copied"),n.blur(),e.delete(n)},2e3);e.set(n,f)})}})}}async function Ya(e){try{return navigator.clipboard.writeText(e)}catch{const t=document.createElement("textarea"),n=document.activeElement;t.value=e,t.setAttribute("readonly",""),t.style.contain="strict",t.style.position="absolute",t.style.left="-9999px",t.style.fontSize="12pt";const r=document.getSelection(),s=r?r.rangeCount>0&&r.getRangeAt(0):null;document.body.appendChild(t),t.select(),t.selectionStart=0,t.selectionEnd=e.length,document.execCommand("copy"),document.body.removeChild(t),s&&(r.removeAllRanges(),r.addRange(s)),n&&n.focus()}}function af(e,t){let n=!0,r=[];const s=i=>{if(n){n=!1,i.forEach(l=>{const c=nr(l);for(const a of document.head.children)if(a.isEqualNode(c)){r.push(a);return}});return}const o=i.map(nr);r.forEach((l,c)=>{const a=o.findIndex(f=>f==null?void 0:f.isEqualNode(l??null));a!==-1?delete o[a]:(l==null||l.remove(),delete r[c])}),o.forEach(l=>l&&document.head.appendChild(l)),r=[...r,...o].filter(Boolean)};Dr(()=>{const i=e.data,o=t.value,l=i&&i.description,c=i&&i.frontmatter.head||[],a=po(o,i);a!==document.title&&(document.title=a);const f=l||o.description;let d=document.querySelector("meta[name=description]");d?d.getAttribute("content")!==f&&d.setAttribute("content",f):nr(["meta",{name:"description",content:f}]),s(go(o.head,za(c)))})}function nr([e,t,n]){const r=document.createElement(e);for(const s in t)r.setAttribute(s,t[s]);return n&&(r.innerHTML=n),e==="script"&&!t.async&&(r.async=!1),r}function Xa(e){return e[0]==="meta"&&e[1]&&e[1].name==="description"}function za(e){return e.filter(t=>!Xa(t))}const rr=new Set,yo=()=>document.createElement("link"),Ja=e=>{const t=yo();t.rel="prefetch",t.href=e,document.head.appendChild(t)},Qa=e=>{const t=new XMLHttpRequest;t.open("GET",e,t.withCredentials=!0),t.send()};let dn;const Za=he&&(dn=yo())&&dn.relList&&dn.relList.supports&&dn.relList.supports("prefetch")?Ja:Qa;function uf(){if(!he||!window.IntersectionObserver)return;let e;if((e=navigator.connection)&&(e.saveData||/2g/.test(e.effectiveType)))return;const t=window.requestIdleCallback||setTimeout;let n=null;const r=()=>{n&&n.disconnect(),n=new IntersectionObserver(i=>{i.forEach(o=>{if(o.isIntersecting){const l=o.target;n.unobserve(l);const{pathname:c}=l;if(!rr.has(c)){rr.add(c);const a=ka(c);a&&Za(a)}}})}),t(()=>{document.querySelectorAll("#app a").forEach(i=>{const{hostname:o,pathname:l}=new URL(i.href instanceof SVGAnimatedString?i.href.animVal:i.href,i.baseURI),c=l.match(/\.\w+$/);c&&c[0]!==".html"||i.target!=="_blank"&&o===location.hostname&&(l!==location.pathname?n.observe(i):rr.add(l))})})};It(r);const s=_o();$e(()=>s.path,r),Bn(()=>{n&&n.disconnect()})}export{cu as $,yr as A,hu as B,lu as C,Vi as D,xl as E,ye as F,au as G,_u as H,ie as I,uu as J,Xi as K,Ga as L,Ha as M,Ra as N,$a as O,Ys as P,Yi as Q,tu as R,nu as S,Zi as T,Oa as U,lo as V,su as W,Vl as X,Da as Y,Nu as Z,xu as _,No as a,Lu as a$,fo as a0,_o as a1,bc as a2,Pu as a3,Su as a4,Fu as a5,he as a6,ou as a7,sf as a8,Ru as a9,rf as aA,af as aB,Ua as aC,Mu as aD,Ba as aE,Bu as aF,of as aG,at as aH,Eu as aI,$u as aJ,ka as aK,uf as aL,cf as aM,lf as aN,oo as aO,Jr as aP,Au as aQ,Iu as aR,Ou as aS,Tu as aT,Wa as aU,Ii as aV,iu as aW,yu as aX,pu as aY,$t as aZ,wu as a_,fu as aa,bu as ab,vu as ac,At as ad,ru as ae,Cu as af,mu as ag,Hu as ah,ju as ai,ku as aj,Du as ak,Uu as al,Ku as am,Wu as an,Vu as ao,qu as ap,Yu as aq,Xu as ar,zu as as,Ju as at,Qu as au,Zu as av,Gu as aw,ef as ax,tf as ay,nf as az,Qt as b,hl as c,In as d,re as e,Dr as f,ri as g,wt as h,ue as i,Rn as j,Ur as k,du as l,Bn as m,Fn as n,It as o,Yr as p,gu as q,se as r,Br as s,eu as t,mi as u,Sr as v,$e as w,Ar as x,ic as y,dc as z}; diff --git a/assets/chunks/framework.VBE0TPts.js b/assets/chunks/framework.VBE0TPts.js deleted file mode 100644 index e4e63179..00000000 --- a/assets/chunks/framework.VBE0TPts.js +++ /dev/null @@ -1 +0,0 @@ -function br(e,t){const n=Object.create(null),r=e.split(",");for(let s=0;s!!n[s]}const ne={},gt=[],Ne=()=>{},wo=()=>!1,Eo=/^on[^a-z]/,zt=e=>Eo.test(e),wr=e=>e.startsWith("onUpdate:"),ce=Object.assign,Er=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},Co=Object.prototype.hasOwnProperty,X=(e,t)=>Co.call(e,t),K=Array.isArray,mt=e=>Tn(e)==="[object Map]",Js=e=>Tn(e)==="[object Set]",W=e=>typeof e=="function",oe=e=>typeof e=="string",Cr=e=>typeof e=="symbol",te=e=>e!==null&&typeof e=="object",xr=e=>te(e)&&W(e.then)&&W(e.catch),Qs=Object.prototype.toString,Tn=e=>Qs.call(e),xo=e=>Tn(e).slice(8,-1),Zs=e=>Tn(e)==="[object Object]",Tr=e=>oe(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,Nt=br(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),An=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},To=/-(\w)/g,He=An(e=>e.replace(To,(t,n)=>n?n.toUpperCase():"")),Ao=/\B([A-Z])/g,ut=An(e=>e.replace(Ao,"-$1").toLowerCase()),Sn=An(e=>e.charAt(0).toUpperCase()+e.slice(1)),hn=An(e=>e?`on${Sn(e)}`:""),Ut=(e,t)=>!Object.is(e,t),pn=(e,t)=>{for(let n=0;n{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:n})},sr=e=>{const t=parseFloat(e);return isNaN(t)?e:t},Gs=e=>{const t=oe(e)?Number(e):NaN;return isNaN(t)?e:t};let rs;const ir=()=>rs||(rs=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function Ar(e){if(K(e)){const t={};for(let n=0;n{if(n){const r=n.split(Oo);r.length>1&&(t[r[0].trim()]=r[1].trim())}}),t}function Sr(e){let t="";if(oe(e))t=e;else if(K(e))for(let n=0;noe(e)?e:e==null?"":K(e)||te(e)&&(e.toString===Qs||!W(e.toString))?JSON.stringify(e,ti,2):String(e),ti=(e,t)=>t&&t.__v_isRef?ti(e,t.value):mt(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((n,[r,s])=>(n[`${r} =>`]=s,n),{})}:Js(t)?{[`Set(${t.size})`]:[...t.values()]}:te(t)&&!K(t)&&!Zs(t)?String(t):t;let we;class Lo{constructor(t=!1){this.detached=t,this._active=!0,this.effects=[],this.cleanups=[],this.parent=we,!t&&we&&(this.index=(we.scopes||(we.scopes=[])).push(this)-1)}get active(){return this._active}run(t){if(this._active){const n=we;try{return we=this,t()}finally{we=n}}}on(){we=this}off(){we=this.parent}stop(t){if(this._active){let n,r;for(n=0,r=this.effects.length;n{const t=new Set(e);return t.w=0,t.n=0,t},ri=e=>(e.w&Qe)>0,si=e=>(e.n&Qe)>0,$o=({deps:e})=>{if(e.length)for(let t=0;t{const{deps:t}=e;if(t.length){let n=0;for(let r=0;r{(f==="length"||f>=c)&&l.push(a)})}else switch(n!==void 0&&l.push(o.get(n)),t){case"add":K(e)?Tr(n)&&l.push(o.get("length")):(l.push(o.get(ct)),mt(e)&&l.push(o.get(lr)));break;case"delete":K(e)||(l.push(o.get(ct)),mt(e)&&l.push(o.get(lr)));break;case"set":mt(e)&&l.push(o.get(ct));break}if(l.length===1)l[0]&&cr(l[0]);else{const c=[];for(const a of l)a&&c.push(...a);cr(Or(c))}}function cr(e,t){const n=K(e)?e:[...e];for(const r of n)r.computed&&is(r);for(const r of n)r.computed||is(r)}function is(e,t){(e!==Oe||e.allowRecurse)&&(e.scheduler?e.scheduler():e.run())}function Ho(e,t){var n;return(n=yn.get(e))==null?void 0:n.get(t)}const jo=br("__proto__,__v_isRef,__isVue"),li=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(Cr)),ko=Ir(),Do=Ir(!1,!0),Uo=Ir(!0),os=Ko();function Ko(){const e={};return["includes","indexOf","lastIndexOf"].forEach(t=>{e[t]=function(...n){const r=z(this);for(let i=0,o=this.length;i{e[t]=function(...n){St();const r=z(this)[t].apply(this,n);return Ot(),r}}),e}function Wo(e){const t=z(this);return ve(t,"has",e),t.hasOwnProperty(e)}function Ir(e=!1,t=!1){return function(r,s,i){if(s==="__v_isReactive")return!e;if(s==="__v_isReadonly")return e;if(s==="__v_isShallow")return t;if(s==="__v_raw"&&i===(e?t?ol:di:t?fi:ui).get(r))return r;const o=K(r);if(!e){if(o&&X(os,s))return Reflect.get(os,s,i);if(s==="hasOwnProperty")return Wo}const l=Reflect.get(r,s,i);return(Cr(s)?li.has(s):jo(s))||(e||ve(r,"get",s),t)?l:ue(l)?o&&Tr(s)?l:l.value:te(l)?e?In(l):Rn(l):l}}const Vo=ci(),qo=ci(!0);function ci(e=!1){return function(n,r,s,i){let o=n[r];if(Et(o)&&ue(o)&&!ue(s))return!1;if(!e&&(!vn(s)&&!Et(s)&&(o=z(o),s=z(s)),!K(n)&&ue(o)&&!ue(s)))return o.value=s,!0;const l=K(n)&&Tr(r)?Number(r)e,On=e=>Reflect.getPrototypeOf(e);function en(e,t,n=!1,r=!1){e=e.__v_raw;const s=z(e),i=z(t);n||(t!==i&&ve(s,"get",t),ve(s,"get",i));const{has:o}=On(s),l=r?Fr:n?Mr:Kt;if(o.call(s,t))return l(e.get(t));if(o.call(s,i))return l(e.get(i));e!==s&&e.get(t)}function tn(e,t=!1){const n=this.__v_raw,r=z(n),s=z(e);return t||(e!==s&&ve(r,"has",e),ve(r,"has",s)),e===s?n.has(e):n.has(e)||n.has(s)}function nn(e,t=!1){return e=e.__v_raw,!t&&ve(z(e),"iterate",ct),Reflect.get(e,"size",e)}function ls(e){e=z(e);const t=z(this);return On(t).has.call(t,e)||(t.add(e),De(t,"add",e,e)),this}function cs(e,t){t=z(t);const n=z(this),{has:r,get:s}=On(n);let i=r.call(n,e);i||(e=z(e),i=r.call(n,e));const o=s.call(n,e);return n.set(e,t),i?Ut(t,o)&&De(n,"set",e,t):De(n,"add",e,t),this}function as(e){const t=z(this),{has:n,get:r}=On(t);let s=n.call(t,e);s||(e=z(e),s=n.call(t,e)),r&&r.call(t,e);const i=t.delete(e);return s&&De(t,"delete",e,void 0),i}function us(){const e=z(this),t=e.size!==0,n=e.clear();return t&&De(e,"clear",void 0,void 0),n}function rn(e,t){return function(r,s){const i=this,o=i.__v_raw,l=z(o),c=t?Fr:e?Mr:Kt;return!e&&ve(l,"iterate",ct),o.forEach((a,f)=>r.call(s,c(a),c(f),i))}}function sn(e,t,n){return function(...r){const s=this.__v_raw,i=z(s),o=mt(i),l=e==="entries"||e===Symbol.iterator&&o,c=e==="keys"&&o,a=s[e](...r),f=n?Fr:t?Mr:Kt;return!t&&ve(i,"iterate",c?lr:ct),{next(){const{value:d,done:p}=a.next();return p?{value:d,done:p}:{value:l?[f(d[0]),f(d[1])]:f(d),done:p}},[Symbol.iterator](){return this}}}}function Ke(e){return function(...t){return e==="delete"?!1:this}}function Zo(){const e={get(i){return en(this,i)},get size(){return nn(this)},has:tn,add:ls,set:cs,delete:as,clear:us,forEach:rn(!1,!1)},t={get(i){return en(this,i,!1,!0)},get size(){return nn(this)},has:tn,add:ls,set:cs,delete:as,clear:us,forEach:rn(!1,!0)},n={get(i){return en(this,i,!0)},get size(){return nn(this,!0)},has(i){return tn.call(this,i,!0)},add:Ke("add"),set:Ke("set"),delete:Ke("delete"),clear:Ke("clear"),forEach:rn(!0,!1)},r={get(i){return en(this,i,!0,!0)},get size(){return nn(this,!0)},has(i){return tn.call(this,i,!0)},add:Ke("add"),set:Ke("set"),delete:Ke("delete"),clear:Ke("clear"),forEach:rn(!0,!0)};return["keys","values","entries",Symbol.iterator].forEach(i=>{e[i]=sn(i,!1,!1),n[i]=sn(i,!0,!1),t[i]=sn(i,!1,!0),r[i]=sn(i,!0,!0)}),[e,n,t,r]}const[Go,el,tl,nl]=Zo();function Pr(e,t){const n=t?e?nl:tl:e?el:Go;return(r,s,i)=>s==="__v_isReactive"?!e:s==="__v_isReadonly"?e:s==="__v_raw"?r:Reflect.get(X(n,s)&&s in r?n:r,s,i)}const rl={get:Pr(!1,!1)},sl={get:Pr(!1,!0)},il={get:Pr(!0,!1)},ui=new WeakMap,fi=new WeakMap,di=new WeakMap,ol=new WeakMap;function ll(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function cl(e){return e.__v_skip||!Object.isExtensible(e)?0:ll(xo(e))}function Rn(e){return Et(e)?e:Lr(e,!1,ai,rl,ui)}function al(e){return Lr(e,!1,Qo,sl,fi)}function In(e){return Lr(e,!0,Jo,il,di)}function Lr(e,t,n,r,s){if(!te(e)||e.__v_raw&&!(t&&e.__v_isReactive))return e;const i=s.get(e);if(i)return i;const o=cl(e);if(o===0)return e;const l=new Proxy(e,o===2?r:n);return s.set(e,l),l}function _t(e){return Et(e)?_t(e.__v_raw):!!(e&&e.__v_isReactive)}function Et(e){return!!(e&&e.__v_isReadonly)}function vn(e){return!!(e&&e.__v_isShallow)}function hi(e){return _t(e)||Et(e)}function z(e){const t=e&&e.__v_raw;return t?z(t):e}function $t(e){return _n(e,"__v_skip",!0),e}const Kt=e=>te(e)?Rn(e):e,Mr=e=>te(e)?In(e):e;function Nr(e){Xe&&Oe&&(e=z(e),oi(e.dep||(e.dep=Or())))}function $r(e,t){e=z(e);const n=e.dep;n&&cr(n)}function ue(e){return!!(e&&e.__v_isRef===!0)}function se(e){return pi(e,!1)}function Br(e){return pi(e,!0)}function pi(e,t){return ue(e)?e:new ul(e,t)}class ul{constructor(t,n){this.__v_isShallow=n,this.dep=void 0,this.__v_isRef=!0,this._rawValue=n?t:z(t),this._value=n?t:Kt(t)}get value(){return Nr(this),this._value}set value(t){const n=this.__v_isShallow||vn(t)||Et(t);t=n?t:z(t),Ut(t,this._rawValue)&&(this._rawValue=t,this._value=n?t:Kt(t),$r(this))}}function gi(e){return ue(e)?e.value:e}const fl={get:(e,t,n)=>gi(Reflect.get(e,t,n)),set:(e,t,n,r)=>{const s=e[t];return ue(s)&&!ue(n)?(s.value=n,!0):Reflect.set(e,t,n,r)}};function mi(e){return _t(e)?e:new Proxy(e,fl)}class dl{constructor(t){this.dep=void 0,this.__v_isRef=!0;const{get:n,set:r}=t(()=>Nr(this),()=>$r(this));this._get=n,this._set=r}get value(){return this._get()}set value(t){this._set(t)}}function hl(e){return new dl(e)}function eu(e){const t=K(e)?new Array(e.length):{};for(const n in e)t[n]=_i(e,n);return t}class pl{constructor(t,n,r){this._object=t,this._key=n,this._defaultValue=r,this.__v_isRef=!0}get value(){const t=this._object[this._key];return t===void 0?this._defaultValue:t}set value(t){this._object[this._key]=t}get dep(){return Ho(z(this._object),this._key)}}class gl{constructor(t){this._getter=t,this.__v_isRef=!0,this.__v_isReadonly=!0}get value(){return this._getter()}}function ml(e,t,n){return ue(e)?e:W(e)?new gl(e):te(e)&&arguments.length>1?_i(e,t,n):se(e)}function _i(e,t,n){const r=e[t];return ue(r)?r:new pl(e,t,n)}class _l{constructor(t,n,r,s){this._setter=n,this.dep=void 0,this.__v_isRef=!0,this.__v_isReadonly=!1,this._dirty=!0,this.effect=new Rr(t,()=>{this._dirty||(this._dirty=!0,$r(this))}),this.effect.computed=this,this.effect.active=this._cacheable=!s,this.__v_isReadonly=r}get value(){const t=z(this);return Nr(t),(t._dirty||!t._cacheable)&&(t._dirty=!1,t._value=t.effect.run()),t._value}set value(t){this._setter(t)}}function yl(e,t,n=!1){let r,s;const i=W(e);return i?(r=e,s=Ne):(r=e.get,s=e.set),new _l(r,s,i||!s,n)}function ze(e,t,n,r){let s;try{s=r?e(...r):e()}catch(i){Rt(i,t,n)}return s}function Ae(e,t,n,r){if(W(e)){const i=ze(e,t,n,r);return i&&xr(i)&&i.catch(o=>{Rt(o,t,n)}),i}const s=[];for(let i=0;i>>1;Vt(pe[r])Le&&pe.splice(t,1)}function bi(e){K(e)?yt.push(...e):(!ke||!ke.includes(e,e.allowRecurse?it+1:it))&&yt.push(e),vi()}function fs(e,t=Wt?Le+1:0){for(;tVt(n)-Vt(r)),it=0;ite.id==null?1/0:e.id,El=(e,t)=>{const n=Vt(e)-Vt(t);if(n===0){if(e.pre&&!t.pre)return-1;if(t.pre&&!e.pre)return 1}return n};function wi(e){ar=!1,Wt=!0,pe.sort(El);try{for(Le=0;Leoe(y)?y.trim():y)),d&&(s=n.map(sr))}let l,c=r[l=hn(t)]||r[l=hn(He(t))];!c&&i&&(c=r[l=hn(ut(t))]),c&&Ae(c,e,6,s);const a=r[l+"Once"];if(a){if(!e.emitted)e.emitted={};else if(e.emitted[l])return;e.emitted[l]=!0,Ae(a,e,6,s)}}function Ei(e,t,n=!1){const r=t.emitsCache,s=r.get(e);if(s!==void 0)return s;const i=e.emits;let o={},l=!1;if(!W(e)){const c=a=>{const f=Ei(a,t,!0);f&&(l=!0,ce(o,f))};!n&&t.mixins.length&&t.mixins.forEach(c),e.extends&&c(e.extends),e.mixins&&e.mixins.forEach(c)}return!i&&!l?(te(e)&&r.set(e,null),null):(K(i)?i.forEach(c=>o[c]=null):ce(o,i),te(e)&&r.set(e,o),o)}function Ln(e,t){return!e||!zt(t)?!1:(t=t.slice(2).replace(/Once$/,""),X(e,t[0].toLowerCase()+t.slice(1))||X(e,ut(t))||X(e,t))}let fe=null,Mn=null;function wn(e){const t=fe;return fe=e,Mn=e&&e.type.__scopeId||null,t}function tu(e){Mn=e}function nu(){Mn=null}function xl(e,t=fe,n){if(!t||e._n)return e;const r=(...s)=>{r._d&&Ts(-1);const i=wn(t);let o;try{o=e(...s)}finally{wn(i),r._d&&Ts(1)}return o};return r._n=!0,r._c=!0,r._d=!0,r}function Un(e){const{type:t,vnode:n,proxy:r,withProxy:s,props:i,propsOptions:[o],slots:l,attrs:c,emit:a,render:f,renderCache:d,data:p,setupState:y,ctx:w,inheritAttrs:T}=e;let L,v;const _=wn(e);try{if(n.shapeFlag&4){const m=s||r;L=xe(f.call(m,m,d,i,y,p,w)),v=c}else{const m=t;L=xe(m.length>1?m(i,{attrs:c,slots:l,emit:a}):m(i,null)),v=t.props?c:Al(c)}}catch(m){kt.length=0,Rt(m,e,1),L=ie(me)}let j=L;if(v&&T!==!1){const m=Object.keys(v),{shapeFlag:R}=j;m.length&&R&7&&(o&&m.some(wr)&&(v=Sl(v,o)),j=Ze(j,v))}return n.dirs&&(j=Ze(j),j.dirs=j.dirs?j.dirs.concat(n.dirs):n.dirs),n.transition&&(j.transition=n.transition),L=j,wn(_),L}function Tl(e){let t;for(let n=0;n{let t;for(const n in e)(n==="class"||n==="style"||zt(n))&&((t||(t={}))[n]=e[n]);return t},Sl=(e,t)=>{const n={};for(const r in e)(!wr(r)||!(r.slice(9)in t))&&(n[r]=e[r]);return n};function Ol(e,t,n){const{props:r,children:s,component:i}=e,{props:o,children:l,patchFlag:c}=t,a=i.emitsOptions;if(t.dirs||t.transition)return!0;if(n&&c>=0){if(c&1024)return!0;if(c&16)return r?ds(r,o,a):!!o;if(c&8){const f=t.dynamicProps;for(let d=0;de.__isSuspense,Il={name:"Suspense",__isSuspense:!0,process(e,t,n,r,s,i,o,l,c,a){e==null?Fl(t,n,r,s,i,o,l,c,a):Pl(e,t,n,r,s,o,l,c,a)},hydrate:Ll,create:kr,normalize:Ml},ru=Il;function qt(e,t){const n=e.props&&e.props[t];W(n)&&n()}function Fl(e,t,n,r,s,i,o,l,c){const{p:a,o:{createElement:f}}=c,d=f("div"),p=e.suspense=kr(e,s,r,t,d,n,i,o,l,c);a(null,p.pendingBranch=e.ssContent,d,null,r,p,i,o),p.deps>0?(qt(e,"onPending"),qt(e,"onFallback"),a(null,e.ssFallback,t,n,r,null,i,o),vt(p,e.ssFallback)):p.resolve(!1,!0)}function Pl(e,t,n,r,s,i,o,l,{p:c,um:a,o:{createElement:f}}){const d=t.suspense=e.suspense;d.vnode=t,t.el=e.el;const p=t.ssContent,y=t.ssFallback,{activeBranch:w,pendingBranch:T,isInFallback:L,isHydrating:v}=d;if(T)d.pendingBranch=p,Me(p,T)?(c(T,p,d.hiddenContainer,null,s,d,i,o,l),d.deps<=0?d.resolve():L&&(c(w,y,n,r,s,null,i,o,l),vt(d,y))):(d.pendingId++,v?(d.isHydrating=!1,d.activeBranch=T):a(T,s,d),d.deps=0,d.effects.length=0,d.hiddenContainer=f("div"),L?(c(null,p,d.hiddenContainer,null,s,d,i,o,l),d.deps<=0?d.resolve():(c(w,y,n,r,s,null,i,o,l),vt(d,y))):w&&Me(p,w)?(c(w,p,n,r,s,d,i,o,l),d.resolve(!0)):(c(null,p,d.hiddenContainer,null,s,d,i,o,l),d.deps<=0&&d.resolve()));else if(w&&Me(p,w))c(w,p,n,r,s,d,i,o,l),vt(d,p);else if(qt(t,"onPending"),d.pendingBranch=p,d.pendingId++,c(null,p,d.hiddenContainer,null,s,d,i,o,l),d.deps<=0)d.resolve();else{const{timeout:_,pendingId:j}=d;_>0?setTimeout(()=>{d.pendingId===j&&d.fallback(y)},_):_===0&&d.fallback(y)}}function kr(e,t,n,r,s,i,o,l,c,a,f=!1){const{p:d,m:p,um:y,n:w,o:{parentNode:T,remove:L}}=a;let v;const _=Nl(e);_&&t!=null&&t.pendingBranch&&(v=t.pendingId,t.deps++);const j=e.props?Gs(e.props.timeout):void 0,m={vnode:e,parent:t,parentComponent:n,isSVG:o,container:r,hiddenContainer:s,anchor:i,deps:0,pendingId:0,timeout:typeof j=="number"?j:-1,activeBranch:null,pendingBranch:null,isInFallback:!0,isHydrating:f,isUnmounted:!1,effects:[],resolve(R=!1,U=!1){const{vnode:B,activeBranch:b,pendingBranch:M,pendingId:A,effects:N,parentComponent:F,container:q}=m;if(m.isHydrating)m.isHydrating=!1;else if(!R){const J=b&&M.transition&&M.transition.mode==="out-in";J&&(b.transition.afterLeave=()=>{A===m.pendingId&&p(M,q,Z,0)});let{anchor:Z}=m;b&&(Z=w(b),y(b,F,m,!0)),J||p(M,q,Z,0)}vt(m,M),m.pendingBranch=null,m.isInFallback=!1;let $=m.parent,de=!1;for(;$;){if($.pendingBranch){$.effects.push(...N),de=!0;break}$=$.parent}de||bi(N),m.effects=[],_&&t&&t.pendingBranch&&v===t.pendingId&&(t.deps--,t.deps===0&&!U&&t.resolve()),qt(B,"onResolve")},fallback(R){if(!m.pendingBranch)return;const{vnode:U,activeBranch:B,parentComponent:b,container:M,isSVG:A}=m;qt(U,"onFallback");const N=w(B),F=()=>{m.isInFallback&&(d(null,R,M,N,b,null,A,l,c),vt(m,R))},q=R.transition&&R.transition.mode==="out-in";q&&(B.transition.afterLeave=F),m.isInFallback=!0,y(B,b,null,!0),q||F()},move(R,U,B){m.activeBranch&&p(m.activeBranch,R,U,B),m.container=R},next(){return m.activeBranch&&w(m.activeBranch)},registerDep(R,U){const B=!!m.pendingBranch;B&&m.deps++;const b=R.vnode.el;R.asyncDep.catch(M=>{Rt(M,R,0)}).then(M=>{if(R.isUnmounted||m.isUnmounted||m.pendingId!==R.suspenseId)return;R.asyncResolved=!0;const{vnode:A}=R;_r(R,M,!1),b&&(A.el=b);const N=!b&&R.subTree.el;U(R,A,T(b||R.subTree.el),b?null:w(R.subTree),m,o,c),N&&L(N),jr(R,A.el),B&&--m.deps===0&&m.resolve()})},unmount(R,U){m.isUnmounted=!0,m.activeBranch&&y(m.activeBranch,n,R,U),m.pendingBranch&&y(m.pendingBranch,n,R,U)}};return m}function Ll(e,t,n,r,s,i,o,l,c){const a=t.suspense=kr(t,r,n,e.parentNode,document.createElement("div"),null,s,i,o,l,!0),f=c(e,a.pendingBranch=t.ssContent,n,a,i,o);return a.deps===0&&a.resolve(!1,!0),f}function Ml(e){const{shapeFlag:t,children:n}=e,r=t&32;e.ssContent=hs(r?n.default:n),e.ssFallback=r?hs(n.fallback):ie(me)}function hs(e){let t;if(W(e)){const n=xt&&e._c;n&&(e._d=!1,qr()),e=e(),n&&(e._d=!0,t=Te,Ki())}return K(e)&&(e=Tl(e)),e=xe(e),t&&!e.dynamicChildren&&(e.dynamicChildren=t.filter(n=>n!==e)),e}function Ci(e,t){t&&t.pendingBranch?K(e)?t.effects.push(...e):t.effects.push(e):bi(e)}function vt(e,t){e.activeBranch=t;const{vnode:n,parentComponent:r}=e,s=n.el=t.el;r&&r.subTree===n&&(r.vnode.el=s,jr(r,s))}function Nl(e){var t;return((t=e.props)==null?void 0:t.suspensible)!=null&&e.props.suspensible!==!1}function Dr(e,t){return Nn(e,null,t)}function su(e,t){return Nn(e,null,{flush:"post"})}const on={};function $e(e,t,n){return Nn(e,t,n)}function Nn(e,t,{immediate:n,deep:r,flush:s,onTrack:i,onTrigger:o}=ne){var l;const c=ni()===((l=ae)==null?void 0:l.scope)?ae:null;let a,f=!1,d=!1;if(ue(e)?(a=()=>e.value,f=vn(e)):_t(e)?(a=()=>e,r=!0):K(e)?(d=!0,f=e.some(m=>_t(m)||vn(m)),a=()=>e.map(m=>{if(ue(m))return m.value;if(_t(m))return lt(m);if(W(m))return ze(m,c,2)})):W(e)?t?a=()=>ze(e,c,2):a=()=>{if(!(c&&c.isUnmounted))return p&&p(),Ae(e,c,3,[y])}:a=Ne,t&&r){const m=a;a=()=>lt(m())}let p,y=m=>{p=_.onStop=()=>{ze(m,c,4)}},w;if(Tt)if(y=Ne,t?n&&Ae(t,c,3,[a(),d?[]:void 0,y]):a(),s==="sync"){const m=Ic();w=m.__watcherHandles||(m.__watcherHandles=[])}else return Ne;let T=d?new Array(e.length).fill(on):on;const L=()=>{if(_.active)if(t){const m=_.run();(r||f||(d?m.some((R,U)=>Ut(R,T[U])):Ut(m,T)))&&(p&&p(),Ae(t,c,3,[m,T===on?void 0:d&&T[0]===on?[]:T,y]),T=m)}else _.run()};L.allowRecurse=!!t;let v;s==="sync"?v=L:s==="post"?v=()=>_e(L,c&&c.suspense):(L.pre=!0,c&&(L.id=c.uid),v=()=>Pn(L));const _=new Rr(a,v);t?n?L():T=_.run():s==="post"?_e(_.run.bind(_),c&&c.suspense):_.run();const j=()=>{_.stop(),c&&c.scope&&Er(c.scope.effects,_)};return w&&w.push(j),j}function $l(e,t,n){const r=this.proxy,s=oe(e)?e.includes(".")?xi(r,e):()=>r[e]:e.bind(r,r);let i;W(t)?i=t:(i=t.handler,n=t);const o=ae;Ge(this);const l=Nn(s,i.bind(r),n);return o?Ge(o):Je(),l}function xi(e,t){const n=t.split(".");return()=>{let r=e;for(let s=0;s{lt(n,t)});else if(Zs(e))for(const n in e)lt(e[n],t);return e}function iu(e,t){const n=fe;if(n===null)return e;const r=jn(n)||n.proxy,s=e.dirs||(e.dirs=[]);for(let i=0;i{e.isMounted=!0}),Ri(()=>{e.isUnmounting=!0}),e}const Ee=[Function,Array],Ti={mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:Ee,onEnter:Ee,onAfterEnter:Ee,onEnterCancelled:Ee,onBeforeLeave:Ee,onLeave:Ee,onAfterLeave:Ee,onLeaveCancelled:Ee,onBeforeAppear:Ee,onAppear:Ee,onAfterAppear:Ee,onAppearCancelled:Ee},Hl={name:"BaseTransition",props:Ti,setup(e,{slots:t}){const n=Qt(),r=Bl();let s;return()=>{const i=t.default&&Si(t.default(),!0);if(!i||!i.length)return;let o=i[0];if(i.length>1){for(const T of i)if(T.type!==me){o=T;break}}const l=z(e),{mode:c}=l;if(r.isLeaving)return Kn(o);const a=ps(o);if(!a)return Kn(o);const f=ur(a,l,r,n);fr(a,f);const d=n.subTree,p=d&&ps(d);let y=!1;const{getTransitionKey:w}=a.type;if(w){const T=w();s===void 0?s=T:T!==s&&(s=T,y=!0)}if(p&&p.type!==me&&(!Me(a,p)||y)){const T=ur(p,l,r,n);if(fr(p,T),c==="out-in")return r.isLeaving=!0,T.afterLeave=()=>{r.isLeaving=!1,n.update.active!==!1&&n.update()},Kn(o);c==="in-out"&&a.type!==me&&(T.delayLeave=(L,v,_)=>{const j=Ai(r,p);j[String(p.key)]=p,L._leaveCb=()=>{v(),L._leaveCb=void 0,delete f.delayedLeave},f.delayedLeave=_})}return o}}},jl=Hl;function Ai(e,t){const{leavingVNodes:n}=e;let r=n.get(t.type);return r||(r=Object.create(null),n.set(t.type,r)),r}function ur(e,t,n,r){const{appear:s,mode:i,persisted:o=!1,onBeforeEnter:l,onEnter:c,onAfterEnter:a,onEnterCancelled:f,onBeforeLeave:d,onLeave:p,onAfterLeave:y,onLeaveCancelled:w,onBeforeAppear:T,onAppear:L,onAfterAppear:v,onAppearCancelled:_}=t,j=String(e.key),m=Ai(n,e),R=(b,M)=>{b&&Ae(b,r,9,M)},U=(b,M)=>{const A=M[1];R(b,M),K(b)?b.every(N=>N.length<=1)&&A():b.length<=1&&A()},B={mode:i,persisted:o,beforeEnter(b){let M=l;if(!n.isMounted)if(s)M=T||l;else return;b._leaveCb&&b._leaveCb(!0);const A=m[j];A&&Me(e,A)&&A.el._leaveCb&&A.el._leaveCb(),R(M,[b])},enter(b){let M=c,A=a,N=f;if(!n.isMounted)if(s)M=L||c,A=v||a,N=_||f;else return;let F=!1;const q=b._enterCb=$=>{F||(F=!0,$?R(N,[b]):R(A,[b]),B.delayedLeave&&B.delayedLeave(),b._enterCb=void 0)};M?U(M,[b,q]):q()},leave(b,M){const A=String(e.key);if(b._enterCb&&b._enterCb(!0),n.isUnmounting)return M();R(d,[b]);let N=!1;const F=b._leaveCb=q=>{N||(N=!0,M(),q?R(w,[b]):R(y,[b]),b._leaveCb=void 0,m[A]===e&&delete m[A])};m[A]=e,p?U(p,[b,F]):F()},clone(b){return ur(b,t,n,r)}};return B}function Kn(e){if(Jt(e))return e=Ze(e),e.children=null,e}function ps(e){return Jt(e)?e.children?e.children[0]:void 0:e}function fr(e,t){e.shapeFlag&6&&e.component?fr(e.component.subTree,t):e.shapeFlag&128?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function Si(e,t=!1,n){let r=[],s=0;for(let i=0;i1)for(let i=0;i!!e.type.__asyncLoader;function ou(e){W(e)&&(e={loader:e});const{loader:t,loadingComponent:n,errorComponent:r,delay:s=200,timeout:i,suspensible:o=!0,onError:l}=e;let c=null,a,f=0;const d=()=>(f++,c=null,p()),p=()=>{let y;return c||(y=c=t().catch(w=>{if(w=w instanceof Error?w:new Error(String(w)),l)return new Promise((T,L)=>{l(w,()=>T(d()),()=>L(w),f+1)});throw w}).then(w=>y!==c&&c?c:(w&&(w.__esModule||w[Symbol.toStringTag]==="Module")&&(w=w.default),a=w,w)))};return Ur({name:"AsyncComponentWrapper",__asyncLoader:p,get __asyncResolved(){return a},setup(){const y=ae;if(a)return()=>Wn(a,y);const w=_=>{c=null,Rt(_,y,13,!r)};if(o&&y.suspense||Tt)return p().then(_=>()=>Wn(_,y)).catch(_=>(w(_),()=>r?ie(r,{error:_}):null));const T=se(!1),L=se(),v=se(!!s);return s&&setTimeout(()=>{v.value=!1},s),i!=null&&setTimeout(()=>{if(!T.value&&!L.value){const _=new Error(`Async component timed out after ${i}ms.`);w(_),L.value=_}},i),p().then(()=>{T.value=!0,y.parent&&Jt(y.parent.vnode)&&Pn(y.parent.update)}).catch(_=>{w(_),L.value=_}),()=>{if(T.value&&a)return Wn(a,y);if(L.value&&r)return ie(r,{error:L.value});if(n&&!v.value)return ie(n)}}})}function Wn(e,t){const{ref:n,props:r,children:s,ce:i}=t.vnode,o=ie(e,r,s);return o.ref=n,o.ce=i,delete t.vnode.ce,o}const Jt=e=>e.type.__isKeepAlive;function kl(e,t){Oi(e,"a",t)}function Dl(e,t){Oi(e,"da",t)}function Oi(e,t,n=ae){const r=e.__wdc||(e.__wdc=()=>{let s=n;for(;s;){if(s.isDeactivated)return;s=s.parent}return e()});if($n(t,r,n),n){let s=n.parent;for(;s&&s.parent;)Jt(s.parent.vnode)&&Ul(r,t,n,s),s=s.parent}}function Ul(e,t,n,r){const s=$n(t,e,r,!0);Bn(()=>{Er(r[t],s)},n)}function $n(e,t,n=ae,r=!1){if(n){const s=n[e]||(n[e]=[]),i=t.__weh||(t.__weh=(...o)=>{if(n.isUnmounted)return;St(),Ge(n);const l=Ae(t,n,e,o);return Je(),Ot(),l});return r?s.unshift(i):s.push(i),i}}const Ue=e=>(t,n=ae)=>(!Tt||e==="sp")&&$n(e,(...r)=>t(...r),n),Kl=Ue("bm"),It=Ue("m"),Wl=Ue("bu"),Vl=Ue("u"),Ri=Ue("bum"),Bn=Ue("um"),ql=Ue("sp"),Yl=Ue("rtg"),Xl=Ue("rtc");function zl(e,t=ae){$n("ec",e,t)}const Ii="components";function lu(e,t){return Pi(Ii,e,!0,t)||e}const Fi=Symbol.for("v-ndc");function cu(e){return oe(e)?Pi(Ii,e,!1)||e:e||Fi}function Pi(e,t,n=!0,r=!1){const s=fe||ae;if(s){const i=s.type;{const l=Sc(i,!1);if(l&&(l===t||l===He(t)||l===Sn(He(t))))return i}const o=gs(s[e]||i[e],t)||gs(s.appContext[e],t);return!o&&r?i:o}}function gs(e,t){return e&&(e[t]||e[He(t)]||e[Sn(He(t))])}function au(e,t,n,r){let s;const i=n;if(K(e)||oe(e)){s=new Array(e.length);for(let o=0,l=e.length;ot(o,l,void 0,i));else{const o=Object.keys(e);s=new Array(o.length);for(let l=0,c=o.length;lYt(t)?!(t.type===me||t.type===ye&&!Li(t.children)):!0)?e:null}function fu(e,t){const n={};for(const r in e)n[/[A-Z]/.test(r)?`on:${r}`:hn(r)]=e[r];return n}const dr=e=>e?zi(e)?jn(e)||e.proxy:dr(e.parent):null,Bt=ce(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>dr(e.parent),$root:e=>dr(e.root),$emit:e=>e.emit,$options:e=>Kr(e),$forceUpdate:e=>e.f||(e.f=()=>Pn(e.update)),$nextTick:e=>e.n||(e.n=Fn.bind(e.proxy)),$watch:e=>$l.bind(e)}),Vn=(e,t)=>e!==ne&&!e.__isScriptSetup&&X(e,t),Jl={get({_:e},t){const{ctx:n,setupState:r,data:s,props:i,accessCache:o,type:l,appContext:c}=e;let a;if(t[0]!=="$"){const y=o[t];if(y!==void 0)switch(y){case 1:return r[t];case 2:return s[t];case 4:return n[t];case 3:return i[t]}else{if(Vn(r,t))return o[t]=1,r[t];if(s!==ne&&X(s,t))return o[t]=2,s[t];if((a=e.propsOptions[0])&&X(a,t))return o[t]=3,i[t];if(n!==ne&&X(n,t))return o[t]=4,n[t];hr&&(o[t]=0)}}const f=Bt[t];let d,p;if(f)return t==="$attrs"&&ve(e,"get",t),f(e);if((d=l.__cssModules)&&(d=d[t]))return d;if(n!==ne&&X(n,t))return o[t]=4,n[t];if(p=c.config.globalProperties,X(p,t))return p[t]},set({_:e},t,n){const{data:r,setupState:s,ctx:i}=e;return Vn(s,t)?(s[t]=n,!0):r!==ne&&X(r,t)?(r[t]=n,!0):X(e.props,t)||t[0]==="$"&&t.slice(1)in e?!1:(i[t]=n,!0)},has({_:{data:e,setupState:t,accessCache:n,ctx:r,appContext:s,propsOptions:i}},o){let l;return!!n[o]||e!==ne&&X(e,o)||Vn(t,o)||(l=i[0])&&X(l,o)||X(r,o)||X(Bt,o)||X(s.config.globalProperties,o)},defineProperty(e,t,n){return n.get!=null?e._.accessCache[t]=0:X(n,"value")&&this.set(e,t,n.value,null),Reflect.defineProperty(e,t,n)}};function du(){return Ql().slots}function Ql(){const e=Qt();return e.setupContext||(e.setupContext=Qi(e))}function ms(e){return K(e)?e.reduce((t,n)=>(t[n]=null,t),{}):e}function hu(e){const t=Qt();let n=e();return Je(),xr(n)&&(n=n.catch(r=>{throw Ge(t),r})),[n,()=>Ge(t)]}let hr=!0;function Zl(e){const t=Kr(e),n=e.proxy,r=e.ctx;hr=!1,t.beforeCreate&&_s(t.beforeCreate,e,"bc");const{data:s,computed:i,methods:o,watch:l,provide:c,inject:a,created:f,beforeMount:d,mounted:p,beforeUpdate:y,updated:w,activated:T,deactivated:L,beforeDestroy:v,beforeUnmount:_,destroyed:j,unmounted:m,render:R,renderTracked:U,renderTriggered:B,errorCaptured:b,serverPrefetch:M,expose:A,inheritAttrs:N,components:F,directives:q,filters:$}=t;if(a&&Gl(a,r,null),o)for(const Z in o){const G=o[Z];W(G)&&(r[Z]=G.bind(n))}if(s){const Z=s.call(n,n);te(Z)&&(e.data=Rn(Z))}if(hr=!0,i)for(const Z in i){const G=i[Z],et=W(G)?G.bind(n,n):W(G.get)?G.get.bind(n,n):Ne,Zt=!W(G)&&W(G.set)?G.set.bind(n):Ne,tt=re({get:et,set:Zt});Object.defineProperty(r,Z,{enumerable:!0,configurable:!0,get:()=>tt.value,set:Ie=>tt.value=Ie})}if(l)for(const Z in l)Mi(l[Z],r,n,Z);if(c){const Z=W(c)?c.call(n):c;Reflect.ownKeys(Z).forEach(G=>{ic(G,Z[G])})}f&&_s(f,e,"c");function J(Z,G){K(G)?G.forEach(et=>Z(et.bind(n))):G&&Z(G.bind(n))}if(J(Kl,d),J(It,p),J(Wl,y),J(Vl,w),J(kl,T),J(Dl,L),J(zl,b),J(Xl,U),J(Yl,B),J(Ri,_),J(Bn,m),J(ql,M),K(A))if(A.length){const Z=e.exposed||(e.exposed={});A.forEach(G=>{Object.defineProperty(Z,G,{get:()=>n[G],set:et=>n[G]=et})})}else e.exposed||(e.exposed={});R&&e.render===Ne&&(e.render=R),N!=null&&(e.inheritAttrs=N),F&&(e.components=F),q&&(e.directives=q)}function Gl(e,t,n=Ne){K(e)&&(e=pr(e));for(const r in e){const s=e[r];let i;te(s)?"default"in s?i=wt(s.from||r,s.default,!0):i=wt(s.from||r):i=wt(s),ue(i)?Object.defineProperty(t,r,{enumerable:!0,configurable:!0,get:()=>i.value,set:o=>i.value=o}):t[r]=i}}function _s(e,t,n){Ae(K(e)?e.map(r=>r.bind(t.proxy)):e.bind(t.proxy),t,n)}function Mi(e,t,n,r){const s=r.includes(".")?xi(n,r):()=>n[r];if(oe(e)){const i=t[e];W(i)&&$e(s,i)}else if(W(e))$e(s,e.bind(n));else if(te(e))if(K(e))e.forEach(i=>Mi(i,t,n,r));else{const i=W(e.handler)?e.handler.bind(n):t[e.handler];W(i)&&$e(s,i,e)}}function Kr(e){const t=e.type,{mixins:n,extends:r}=t,{mixins:s,optionsCache:i,config:{optionMergeStrategies:o}}=e.appContext,l=i.get(t);let c;return l?c=l:!s.length&&!n&&!r?c=t:(c={},s.length&&s.forEach(a=>En(c,a,o,!0)),En(c,t,o)),te(t)&&i.set(t,c),c}function En(e,t,n,r=!1){const{mixins:s,extends:i}=t;i&&En(e,i,n,!0),s&&s.forEach(o=>En(e,o,n,!0));for(const o in t)if(!(r&&o==="expose")){const l=ec[o]||n&&n[o];e[o]=l?l(e[o],t[o]):t[o]}return e}const ec={data:ys,props:vs,emits:vs,methods:Mt,computed:Mt,beforeCreate:ge,created:ge,beforeMount:ge,mounted:ge,beforeUpdate:ge,updated:ge,beforeDestroy:ge,beforeUnmount:ge,destroyed:ge,unmounted:ge,activated:ge,deactivated:ge,errorCaptured:ge,serverPrefetch:ge,components:Mt,directives:Mt,watch:nc,provide:ys,inject:tc};function ys(e,t){return t?e?function(){return ce(W(e)?e.call(this,this):e,W(t)?t.call(this,this):t)}:t:e}function tc(e,t){return Mt(pr(e),pr(t))}function pr(e){if(K(e)){const t={};for(let n=0;n1)return n&&W(t)?t.call(r&&r.proxy):t}}function oc(e,t,n,r=!1){const s={},i={};_n(i,Hn,1),e.propsDefaults=Object.create(null),$i(e,t,s,i);for(const o in e.propsOptions[0])o in s||(s[o]=void 0);n?e.props=r?s:al(s):e.type.props?e.props=s:e.props=i,e.attrs=i}function lc(e,t,n,r){const{props:s,attrs:i,vnode:{patchFlag:o}}=e,l=z(s),[c]=e.propsOptions;let a=!1;if((r||o>0)&&!(o&16)){if(o&8){const f=e.vnode.dynamicProps;for(let d=0;d{c=!0;const[p,y]=Bi(d,t,!0);ce(o,p),y&&l.push(...y)};!n&&t.mixins.length&&t.mixins.forEach(f),e.extends&&f(e.extends),e.mixins&&e.mixins.forEach(f)}if(!i&&!c)return te(e)&&r.set(e,gt),gt;if(K(i))for(let f=0;f-1,y[1]=T<0||w-1||X(y,"default"))&&l.push(d)}}}const a=[o,l];return te(e)&&r.set(e,a),a}function bs(e){return e[0]!=="$"}function ws(e){const t=e&&e.toString().match(/^\s*(function|class) (\w+)/);return t?t[2]:e===null?"null":""}function Es(e,t){return ws(e)===ws(t)}function Cs(e,t){return K(t)?t.findIndex(n=>Es(n,e)):W(t)&&Es(t,e)?0:-1}const Hi=e=>e[0]==="_"||e==="$stable",Wr=e=>K(e)?e.map(xe):[xe(e)],cc=(e,t,n)=>{if(t._n)return t;const r=xl((...s)=>Wr(t(...s)),n);return r._c=!1,r},ji=(e,t,n)=>{const r=e._ctx;for(const s in e){if(Hi(s))continue;const i=e[s];if(W(i))t[s]=cc(s,i,r);else if(i!=null){const o=Wr(i);t[s]=()=>o}}},ki=(e,t)=>{const n=Wr(t);e.slots.default=()=>n},ac=(e,t)=>{if(e.vnode.shapeFlag&32){const n=t._;n?(e.slots=z(t),_n(t,"_",n)):ji(t,e.slots={})}else e.slots={},t&&ki(e,t);_n(e.slots,Hn,1)},uc=(e,t,n)=>{const{vnode:r,slots:s}=e;let i=!0,o=ne;if(r.shapeFlag&32){const l=t._;l?n&&l===1?i=!1:(ce(s,t),!n&&l===1&&delete s._):(i=!t.$stable,ji(t,s)),o=t}else t&&(ki(e,t),o={default:1});if(i)for(const l in s)!Hi(l)&&!(l in o)&&delete s[l]};function xn(e,t,n,r,s=!1){if(K(e)){e.forEach((p,y)=>xn(p,t&&(K(t)?t[y]:t),n,r,s));return}if(bt(r)&&!s)return;const i=r.shapeFlag&4?jn(r.component)||r.component.proxy:r.el,o=s?null:i,{i:l,r:c}=e,a=t&&t.r,f=l.refs===ne?l.refs={}:l.refs,d=l.setupState;if(a!=null&&a!==c&&(oe(a)?(f[a]=null,X(d,a)&&(d[a]=null)):ue(a)&&(a.value=null)),W(c))ze(c,l,12,[o,f]);else{const p=oe(c),y=ue(c);if(p||y){const w=()=>{if(e.f){const T=p?X(d,c)?d[c]:f[c]:c.value;s?K(T)&&Er(T,i):K(T)?T.includes(i)||T.push(i):p?(f[c]=[i],X(d,c)&&(d[c]=f[c])):(c.value=[i],e.k&&(f[e.k]=c.value))}else p?(f[c]=o,X(d,c)&&(d[c]=o)):y&&(c.value=o,e.k&&(f[e.k]=o))};o?(w.id=-1,_e(w,n)):w()}}}let We=!1;const ln=e=>/svg/.test(e.namespaceURI)&&e.tagName!=="foreignObject",cn=e=>e.nodeType===8;function fc(e){const{mt:t,p:n,o:{patchProp:r,createText:s,nextSibling:i,parentNode:o,remove:l,insert:c,createComment:a}}=e,f=(v,_)=>{if(!_.hasChildNodes()){n(null,v,_),bn(),_._vnode=v;return}We=!1,d(_.firstChild,v,null,null,null),bn(),_._vnode=v,We&&console.error("Hydration completed but contains mismatches.")},d=(v,_,j,m,R,U=!1)=>{const B=cn(v)&&v.data==="[",b=()=>T(v,_,j,m,R,B),{type:M,ref:A,shapeFlag:N,patchFlag:F}=_;let q=v.nodeType;_.el=v,F===-2&&(U=!1,_.dynamicChildren=null);let $=null;switch(M){case Ct:q!==3?_.children===""?(c(_.el=s(""),o(v),v),$=v):$=b():(v.data!==_.children&&(We=!0,v.data=_.children),$=i(v));break;case me:q!==8||B?$=b():$=i(v);break;case jt:if(B&&(v=i(v),q=v.nodeType),q===1||q===3){$=v;const de=!_.children.length;for(let J=0;J<_.staticCount;J++)de&&(_.children+=$.nodeType===1?$.outerHTML:$.data),J===_.staticCount-1&&(_.anchor=$),$=i($);return B?i($):$}else b();break;case ye:B?$=w(v,_,j,m,R,U):$=b();break;default:if(N&1)q!==1||_.type.toLowerCase()!==v.tagName.toLowerCase()?$=b():$=p(v,_,j,m,R,U);else if(N&6){_.slotScopeIds=R;const de=o(v);if(t(_,de,null,j,m,ln(de),U),$=B?L(v):i(v),$&&cn($)&&$.data==="teleport end"&&($=i($)),bt(_)){let J;B?(J=ie(ye),J.anchor=$?$.previousSibling:de.lastChild):J=v.nodeType===3?Xi(""):ie("div"),J.el=v,_.component.subTree=J}}else N&64?q!==8?$=b():$=_.type.hydrate(v,_,j,m,R,U,e,y):N&128&&($=_.type.hydrate(v,_,j,m,ln(o(v)),R,U,e,d))}return A!=null&&xn(A,null,m,_),$},p=(v,_,j,m,R,U)=>{U=U||!!_.dynamicChildren;const{type:B,props:b,patchFlag:M,shapeFlag:A,dirs:N}=_,F=B==="input"&&N||B==="option";if(F||M!==-1){if(N&&Pe(_,null,j,"created"),b)if(F||!U||M&48)for(const $ in b)(F&&$.endsWith("value")||zt($)&&!Nt($))&&r(v,$,null,b[$],!1,void 0,j);else b.onClick&&r(v,"onClick",null,b.onClick,!1,void 0,j);let q;if((q=b&&b.onVnodeBeforeMount)&&Ce(q,j,_),N&&Pe(_,null,j,"beforeMount"),((q=b&&b.onVnodeMounted)||N)&&Ci(()=>{q&&Ce(q,j,_),N&&Pe(_,null,j,"mounted")},m),A&16&&!(b&&(b.innerHTML||b.textContent))){let $=y(v.firstChild,_,v,j,m,R,U);for(;$;){We=!0;const de=$;$=$.nextSibling,l(de)}}else A&8&&v.textContent!==_.children&&(We=!0,v.textContent=_.children)}return v.nextSibling},y=(v,_,j,m,R,U,B)=>{B=B||!!_.dynamicChildren;const b=_.children,M=b.length;for(let A=0;A{const{slotScopeIds:B}=_;B&&(R=R?R.concat(B):B);const b=o(v),M=y(i(v),_,b,j,m,R,U);return M&&cn(M)&&M.data==="]"?i(_.anchor=M):(We=!0,c(_.anchor=a("]"),b,M),M)},T=(v,_,j,m,R,U)=>{if(We=!0,_.el=null,U){const M=L(v);for(;;){const A=i(v);if(A&&A!==M)l(A);else break}}const B=i(v),b=o(v);return l(v),n(null,_,b,B,j,m,ln(b),R),B},L=v=>{let _=0;for(;v;)if(v=i(v),v&&cn(v)&&(v.data==="["&&_++,v.data==="]")){if(_===0)return i(v);_--}return v};return[f,d]}const _e=Ci;function dc(e){return Di(e)}function hc(e){return Di(e,fc)}function Di(e,t){const n=ir();n.__VUE__=!0;const{insert:r,remove:s,patchProp:i,createElement:o,createText:l,createComment:c,setText:a,setElementText:f,parentNode:d,nextSibling:p,setScopeId:y=Ne,insertStaticContent:w}=e,T=(u,h,g,C=null,E=null,O=null,P=!1,S=null,I=!!h.dynamicChildren)=>{if(u===h)return;u&&!Me(u,h)&&(C=Gt(u),Ie(u,E,O,!0),u=null),h.patchFlag===-2&&(I=!1,h.dynamicChildren=null);const{type:x,ref:k,shapeFlag:H}=h;switch(x){case Ct:L(u,h,g,C);break;case me:v(u,h,g,C);break;case jt:u==null&&_(h,g,C,P);break;case ye:F(u,h,g,C,E,O,P,S,I);break;default:H&1?R(u,h,g,C,E,O,P,S,I):H&6?q(u,h,g,C,E,O,P,S,I):(H&64||H&128)&&x.process(u,h,g,C,E,O,P,S,I,ft)}k!=null&&E&&xn(k,u&&u.ref,O,h||u,!h)},L=(u,h,g,C)=>{if(u==null)r(h.el=l(h.children),g,C);else{const E=h.el=u.el;h.children!==u.children&&a(E,h.children)}},v=(u,h,g,C)=>{u==null?r(h.el=c(h.children||""),g,C):h.el=u.el},_=(u,h,g,C)=>{[u.el,u.anchor]=w(u.children,h,g,C,u.el,u.anchor)},j=({el:u,anchor:h},g,C)=>{let E;for(;u&&u!==h;)E=p(u),r(u,g,C),u=E;r(h,g,C)},m=({el:u,anchor:h})=>{let g;for(;u&&u!==h;)g=p(u),s(u),u=g;s(h)},R=(u,h,g,C,E,O,P,S,I)=>{P=P||h.type==="svg",u==null?U(h,g,C,E,O,P,S,I):M(u,h,E,O,P,S,I)},U=(u,h,g,C,E,O,P,S)=>{let I,x;const{type:k,props:H,shapeFlag:D,transition:V,dirs:Y}=u;if(I=u.el=o(u.type,O,H&&H.is,H),D&8?f(I,u.children):D&16&&b(u.children,I,null,C,E,O&&k!=="foreignObject",P,S),Y&&Pe(u,null,C,"created"),B(I,u,u.scopeId,P,C),H){for(const Q in H)Q!=="value"&&!Nt(Q)&&i(I,Q,null,H[Q],O,u.children,C,E,je);"value"in H&&i(I,"value",null,H.value),(x=H.onVnodeBeforeMount)&&Ce(x,C,u)}Y&&Pe(u,null,C,"beforeMount");const ee=(!E||E&&!E.pendingBranch)&&V&&!V.persisted;ee&&V.beforeEnter(I),r(I,h,g),((x=H&&H.onVnodeMounted)||ee||Y)&&_e(()=>{x&&Ce(x,C,u),ee&&V.enter(I),Y&&Pe(u,null,C,"mounted")},E)},B=(u,h,g,C,E)=>{if(g&&y(u,g),C)for(let O=0;O{for(let x=I;x{const S=h.el=u.el;let{patchFlag:I,dynamicChildren:x,dirs:k}=h;I|=u.patchFlag&16;const H=u.props||ne,D=h.props||ne;let V;g&&nt(g,!1),(V=D.onVnodeBeforeUpdate)&&Ce(V,g,h,u),k&&Pe(h,u,g,"beforeUpdate"),g&&nt(g,!0);const Y=E&&h.type!=="foreignObject";if(x?A(u.dynamicChildren,x,S,g,C,Y,O):P||G(u,h,S,null,g,C,Y,O,!1),I>0){if(I&16)N(S,h,H,D,g,C,E);else if(I&2&&H.class!==D.class&&i(S,"class",null,D.class,E),I&4&&i(S,"style",H.style,D.style,E),I&8){const ee=h.dynamicProps;for(let Q=0;Q{V&&Ce(V,g,h,u),k&&Pe(h,u,g,"updated")},C)},A=(u,h,g,C,E,O,P)=>{for(let S=0;S{if(g!==C){if(g!==ne)for(const S in g)!Nt(S)&&!(S in C)&&i(u,S,g[S],null,P,h.children,E,O,je);for(const S in C){if(Nt(S))continue;const I=C[S],x=g[S];I!==x&&S!=="value"&&i(u,S,x,I,P,h.children,E,O,je)}"value"in C&&i(u,"value",g.value,C.value)}},F=(u,h,g,C,E,O,P,S,I)=>{const x=h.el=u?u.el:l(""),k=h.anchor=u?u.anchor:l("");let{patchFlag:H,dynamicChildren:D,slotScopeIds:V}=h;V&&(S=S?S.concat(V):V),u==null?(r(x,g,C),r(k,g,C),b(h.children,g,k,E,O,P,S,I)):H>0&&H&64&&D&&u.dynamicChildren?(A(u.dynamicChildren,D,g,E,O,P,S),(h.key!=null||E&&h===E.subTree)&&Vr(u,h,!0)):G(u,h,g,k,E,O,P,S,I)},q=(u,h,g,C,E,O,P,S,I)=>{h.slotScopeIds=S,u==null?h.shapeFlag&512?E.ctx.activate(h,g,C,P,I):$(h,g,C,E,O,P,I):de(u,h,I)},$=(u,h,g,C,E,O,P)=>{const S=u.component=Cc(u,C,E);if(Jt(u)&&(S.ctx.renderer=ft),xc(S),S.asyncDep){if(E&&E.registerDep(S,J),!u.el){const I=S.subTree=ie(me);v(null,I,h,g)}return}J(S,u,h,g,E,O,P)},de=(u,h,g)=>{const C=h.component=u.component;if(Ol(u,h,g))if(C.asyncDep&&!C.asyncResolved){Z(C,h,g);return}else C.next=h,wl(C.update),C.update();else h.el=u.el,C.vnode=h},J=(u,h,g,C,E,O,P)=>{const S=()=>{if(u.isMounted){let{next:k,bu:H,u:D,parent:V,vnode:Y}=u,ee=k,Q;nt(u,!1),k?(k.el=Y.el,Z(u,k,P)):k=Y,H&&pn(H),(Q=k.props&&k.props.onVnodeBeforeUpdate)&&Ce(Q,V,k,Y),nt(u,!0);const le=Un(u),Se=u.subTree;u.subTree=le,T(Se,le,d(Se.el),Gt(Se),u,E,O),k.el=le.el,ee===null&&jr(u,le.el),D&&_e(D,E),(Q=k.props&&k.props.onVnodeUpdated)&&_e(()=>Ce(Q,V,k,Y),E)}else{let k;const{el:H,props:D}=h,{bm:V,m:Y,parent:ee}=u,Q=bt(h);if(nt(u,!1),V&&pn(V),!Q&&(k=D&&D.onVnodeBeforeMount)&&Ce(k,ee,h),nt(u,!0),H&&Dn){const le=()=>{u.subTree=Un(u),Dn(H,u.subTree,u,E,null)};Q?h.type.__asyncLoader().then(()=>!u.isUnmounted&&le()):le()}else{const le=u.subTree=Un(u);T(null,le,g,C,u,E,O),h.el=le.el}if(Y&&_e(Y,E),!Q&&(k=D&&D.onVnodeMounted)){const le=h;_e(()=>Ce(k,ee,le),E)}(h.shapeFlag&256||ee&&bt(ee.vnode)&&ee.vnode.shapeFlag&256)&&u.a&&_e(u.a,E),u.isMounted=!0,h=g=C=null}},I=u.effect=new Rr(S,()=>Pn(x),u.scope),x=u.update=()=>I.run();x.id=u.uid,nt(u,!0),x()},Z=(u,h,g)=>{h.component=u;const C=u.vnode.props;u.vnode=h,u.next=null,lc(u,h.props,C,g),uc(u,h.children,g),St(),fs(),Ot()},G=(u,h,g,C,E,O,P,S,I=!1)=>{const x=u&&u.children,k=u?u.shapeFlag:0,H=h.children,{patchFlag:D,shapeFlag:V}=h;if(D>0){if(D&128){Zt(x,H,g,C,E,O,P,S,I);return}else if(D&256){et(x,H,g,C,E,O,P,S,I);return}}V&8?(k&16&&je(x,E,O),H!==x&&f(g,H)):k&16?V&16?Zt(x,H,g,C,E,O,P,S,I):je(x,E,O,!0):(k&8&&f(g,""),V&16&&b(H,g,C,E,O,P,S,I))},et=(u,h,g,C,E,O,P,S,I)=>{u=u||gt,h=h||gt;const x=u.length,k=h.length,H=Math.min(x,k);let D;for(D=0;Dk?je(u,E,O,!0,!1,H):b(h,g,C,E,O,P,S,I,H)},Zt=(u,h,g,C,E,O,P,S,I)=>{let x=0;const k=h.length;let H=u.length-1,D=k-1;for(;x<=H&&x<=D;){const V=u[x],Y=h[x]=I?Ye(h[x]):xe(h[x]);if(Me(V,Y))T(V,Y,g,null,E,O,P,S,I);else break;x++}for(;x<=H&&x<=D;){const V=u[H],Y=h[D]=I?Ye(h[D]):xe(h[D]);if(Me(V,Y))T(V,Y,g,null,E,O,P,S,I);else break;H--,D--}if(x>H){if(x<=D){const V=D+1,Y=VD)for(;x<=H;)Ie(u[x],E,O,!0),x++;else{const V=x,Y=x,ee=new Map;for(x=Y;x<=D;x++){const be=h[x]=I?Ye(h[x]):xe(h[x]);be.key!=null&&ee.set(be.key,x)}let Q,le=0;const Se=D-Y+1;let dt=!1,es=0;const Ft=new Array(Se);for(x=0;x=Se){Ie(be,E,O,!0);continue}let Fe;if(be.key!=null)Fe=ee.get(be.key);else for(Q=Y;Q<=D;Q++)if(Ft[Q-Y]===0&&Me(be,h[Q])){Fe=Q;break}Fe===void 0?Ie(be,E,O,!0):(Ft[Fe-Y]=x+1,Fe>=es?es=Fe:dt=!0,T(be,h[Fe],g,null,E,O,P,S,I),le++)}const ts=dt?pc(Ft):gt;for(Q=ts.length-1,x=Se-1;x>=0;x--){const be=Y+x,Fe=h[be],ns=be+1{const{el:O,type:P,transition:S,children:I,shapeFlag:x}=u;if(x&6){tt(u.component.subTree,h,g,C);return}if(x&128){u.suspense.move(h,g,C);return}if(x&64){P.move(u,h,g,ft);return}if(P===ye){r(O,h,g);for(let H=0;HS.enter(O),E);else{const{leave:H,delayLeave:D,afterLeave:V}=S,Y=()=>r(O,h,g),ee=()=>{H(O,()=>{Y(),V&&V()})};D?D(O,Y,ee):ee()}else r(O,h,g)},Ie=(u,h,g,C=!1,E=!1)=>{const{type:O,props:P,ref:S,children:I,dynamicChildren:x,shapeFlag:k,patchFlag:H,dirs:D}=u;if(S!=null&&xn(S,null,g,u,!0),k&256){h.ctx.deactivate(u);return}const V=k&1&&D,Y=!bt(u);let ee;if(Y&&(ee=P&&P.onVnodeBeforeUnmount)&&Ce(ee,h,u),k&6)bo(u.component,g,C);else{if(k&128){u.suspense.unmount(g,C);return}V&&Pe(u,null,h,"beforeUnmount"),k&64?u.type.remove(u,h,g,E,ft,C):x&&(O!==ye||H>0&&H&64)?je(x,h,g,!1,!0):(O===ye&&H&384||!E&&k&16)&&je(I,h,g),C&&Zr(u)}(Y&&(ee=P&&P.onVnodeUnmounted)||V)&&_e(()=>{ee&&Ce(ee,h,u),V&&Pe(u,null,h,"unmounted")},g)},Zr=u=>{const{type:h,el:g,anchor:C,transition:E}=u;if(h===ye){vo(g,C);return}if(h===jt){m(u);return}const O=()=>{s(g),E&&!E.persisted&&E.afterLeave&&E.afterLeave()};if(u.shapeFlag&1&&E&&!E.persisted){const{leave:P,delayLeave:S}=E,I=()=>P(g,O);S?S(u.el,O,I):I()}else O()},vo=(u,h)=>{let g;for(;u!==h;)g=p(u),s(u),u=g;s(h)},bo=(u,h,g)=>{const{bum:C,scope:E,update:O,subTree:P,um:S}=u;C&&pn(C),E.stop(),O&&(O.active=!1,Ie(P,u,h,g)),S&&_e(S,h),_e(()=>{u.isUnmounted=!0},h),h&&h.pendingBranch&&!h.isUnmounted&&u.asyncDep&&!u.asyncResolved&&u.suspenseId===h.pendingId&&(h.deps--,h.deps===0&&h.resolve())},je=(u,h,g,C=!1,E=!1,O=0)=>{for(let P=O;Pu.shapeFlag&6?Gt(u.component.subTree):u.shapeFlag&128?u.suspense.next():p(u.anchor||u.el),Gr=(u,h,g)=>{u==null?h._vnode&&Ie(h._vnode,null,null,!0):T(h._vnode||null,u,h,null,null,null,g),fs(),bn(),h._vnode=u},ft={p:T,um:Ie,m:tt,r:Zr,mt:$,mc:b,pc:G,pbc:A,n:Gt,o:e};let kn,Dn;return t&&([kn,Dn]=t(ft)),{render:Gr,hydrate:kn,createApp:sc(Gr,kn)}}function nt({effect:e,update:t},n){e.allowRecurse=t.allowRecurse=n}function Vr(e,t,n=!1){const r=e.children,s=t.children;if(K(r)&&K(s))for(let i=0;i>1,e[n[l]]0&&(t[r]=n[i-1]),n[i]=r)}}for(i=n.length,o=n[i-1];i-- >0;)n[i]=o,o=t[o];return n}const gc=e=>e.__isTeleport,Ht=e=>e&&(e.disabled||e.disabled===""),xs=e=>typeof SVGElement<"u"&&e instanceof SVGElement,mr=(e,t)=>{const n=e&&e.to;return oe(n)?t?t(n):null:n},mc={__isTeleport:!0,process(e,t,n,r,s,i,o,l,c,a){const{mc:f,pc:d,pbc:p,o:{insert:y,querySelector:w,createText:T,createComment:L}}=a,v=Ht(t.props);let{shapeFlag:_,children:j,dynamicChildren:m}=t;if(e==null){const R=t.el=T(""),U=t.anchor=T("");y(R,n,r),y(U,n,r);const B=t.target=mr(t.props,w),b=t.targetAnchor=T("");B&&(y(b,B),o=o||xs(B));const M=(A,N)=>{_&16&&f(j,A,N,s,i,o,l,c)};v?M(n,U):B&&M(B,b)}else{t.el=e.el;const R=t.anchor=e.anchor,U=t.target=e.target,B=t.targetAnchor=e.targetAnchor,b=Ht(e.props),M=b?n:U,A=b?R:B;if(o=o||xs(U),m?(p(e.dynamicChildren,m,M,s,i,o,l),Vr(e,t,!0)):c||d(e,t,M,A,s,i,o,l,!1),v)b||an(t,n,R,a,1);else if((t.props&&t.props.to)!==(e.props&&e.props.to)){const N=t.target=mr(t.props,w);N&&an(t,N,null,a,0)}else b&&an(t,U,B,a,1)}Ui(t)},remove(e,t,n,r,{um:s,o:{remove:i}},o){const{shapeFlag:l,children:c,anchor:a,targetAnchor:f,target:d,props:p}=e;if(d&&i(f),(o||!Ht(p))&&(i(a),l&16))for(let y=0;y0?Te||gt:null,Ki(),xt>0&&Te&&Te.push(e),e}function gu(e,t,n,r,s,i){return Wi(Yi(e,t,n,r,s,i,!0))}function Vi(e,t,n,r,s){return Wi(ie(e,t,n,r,s,!0))}function Yt(e){return e?e.__v_isVNode===!0:!1}function Me(e,t){return e.type===t.type&&e.key===t.key}const Hn="__vInternal",qi=({key:e})=>e??null,gn=({ref:e,ref_key:t,ref_for:n})=>(typeof e=="number"&&(e=""+e),e!=null?oe(e)||ue(e)||W(e)?{i:fe,r:e,k:t,f:!!n}:e:null);function Yi(e,t=null,n=null,r=0,s=null,i=e===ye?0:1,o=!1,l=!1){const c={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&qi(t),ref:t&&gn(t),scopeId:Mn,slotScopeIds:null,children:n,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetAnchor:null,staticCount:0,shapeFlag:i,patchFlag:r,dynamicProps:s,dynamicChildren:null,appContext:null,ctx:fe};return l?(Yr(c,n),i&128&&e.normalize(c)):n&&(c.shapeFlag|=oe(n)?8:16),xt>0&&!o&&Te&&(c.patchFlag>0||i&6)&&c.patchFlag!==32&&Te.push(c),c}const ie=yc;function yc(e,t=null,n=null,r=0,s=null,i=!1){if((!e||e===Fi)&&(e=me),Yt(e)){const l=Ze(e,t,!0);return n&&Yr(l,n),xt>0&&!i&&Te&&(l.shapeFlag&6?Te[Te.indexOf(e)]=l:Te.push(l)),l.patchFlag|=-2,l}if(Oc(e)&&(e=e.__vccOpts),t){t=vc(t);let{class:l,style:c}=t;l&&!oe(l)&&(t.class=Sr(l)),te(c)&&(hi(c)&&!K(c)&&(c=ce({},c)),t.style=Ar(c))}const o=oe(e)?1:Rl(e)?128:gc(e)?64:te(e)?4:W(e)?2:0;return Yi(e,t,n,r,s,o,i,!0)}function vc(e){return e?hi(e)||Hn in e?ce({},e):e:null}function Ze(e,t,n=!1){const{props:r,ref:s,patchFlag:i,children:o}=e,l=t?bc(r||{},t):r;return{__v_isVNode:!0,__v_skip:!0,type:e.type,props:l,key:l&&qi(l),ref:t&&t.ref?n&&s?K(s)?s.concat(gn(t)):[s,gn(t)]:gn(t):s,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:o,target:e.target,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==ye?i===-1?16:i|16:i,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:e.transition,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&Ze(e.ssContent),ssFallback:e.ssFallback&&Ze(e.ssFallback),el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce}}function Xi(e=" ",t=0){return ie(Ct,null,e,t)}function mu(e,t){const n=ie(jt,null,e);return n.staticCount=t,n}function _u(e="",t=!1){return t?(qr(),Vi(me,null,e)):ie(me,null,e)}function xe(e){return e==null||typeof e=="boolean"?ie(me):K(e)?ie(ye,null,e.slice()):typeof e=="object"?Ye(e):ie(Ct,null,String(e))}function Ye(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:Ze(e)}function Yr(e,t){let n=0;const{shapeFlag:r}=e;if(t==null)t=null;else if(K(t))n=16;else if(typeof t=="object")if(r&65){const s=t.default;s&&(s._c&&(s._d=!1),Yr(e,s()),s._c&&(s._d=!0));return}else{n=32;const s=t._;!s&&!(Hn in t)?t._ctx=fe:s===3&&fe&&(fe.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else W(t)?(t={default:t,_ctx:fe},n=32):(t=String(t),r&64?(n=16,t=[Xi(t)]):n=8);e.children=t,e.shapeFlag|=n}function bc(...e){const t={};for(let n=0;nae||fe;let Xr,ht,As="__VUE_INSTANCE_SETTERS__";(ht=ir()[As])||(ht=ir()[As]=[]),ht.push(e=>ae=e),Xr=e=>{ht.length>1?ht.forEach(t=>t(e)):ht[0](e)};const Ge=e=>{Xr(e),e.scope.on()},Je=()=>{ae&&ae.scope.off(),Xr(null)};function zi(e){return e.vnode.shapeFlag&4}let Tt=!1;function xc(e,t=!1){Tt=t;const{props:n,children:r}=e.vnode,s=zi(e);oc(e,n,s,t),ac(e,r);const i=s?Tc(e,t):void 0;return Tt=!1,i}function Tc(e,t){const n=e.type;e.accessCache=Object.create(null),e.proxy=$t(new Proxy(e.ctx,Jl));const{setup:r}=n;if(r){const s=e.setupContext=r.length>1?Qi(e):null;Ge(e),St();const i=ze(r,e,0,[e.props,s]);if(Ot(),Je(),xr(i)){if(i.then(Je,Je),t)return i.then(o=>{_r(e,o,t)}).catch(o=>{Rt(o,e,0)});e.asyncDep=i}else _r(e,i,t)}else Ji(e,t)}function _r(e,t,n){W(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:te(t)&&(e.setupState=mi(t)),Ji(e,n)}let Ss;function Ji(e,t,n){const r=e.type;if(!e.render){if(!t&&Ss&&!r.render){const s=r.template||Kr(e).template;if(s){const{isCustomElement:i,compilerOptions:o}=e.appContext.config,{delimiters:l,compilerOptions:c}=r,a=ce(ce({isCustomElement:i,delimiters:l},o),c);r.render=Ss(s,a)}}e.render=r.render||Ne}Ge(e),St(),Zl(e),Ot(),Je()}function Ac(e){return e.attrsProxy||(e.attrsProxy=new Proxy(e.attrs,{get(t,n){return ve(e,"get","$attrs"),t[n]}}))}function Qi(e){const t=n=>{e.exposed=n||{}};return{get attrs(){return Ac(e)},slots:e.slots,emit:e.emit,expose:t}}function jn(e){if(e.exposed)return e.exposeProxy||(e.exposeProxy=new Proxy(mi($t(e.exposed)),{get(t,n){if(n in t)return t[n];if(n in Bt)return Bt[n](e)},has(t,n){return n in t||n in Bt}}))}function Sc(e,t=!0){return W(e)?e.displayName||e.name:e.name||t&&e.__name}function Oc(e){return W(e)&&"__vccOpts"in e}const re=(e,t)=>yl(e,t,Tt);function yr(e,t,n){const r=arguments.length;return r===2?te(t)&&!K(t)?Yt(t)?ie(e,null,[t]):ie(e,t):ie(e,null,t):(r>3?n=Array.prototype.slice.call(arguments,2):r===3&&Yt(n)&&(n=[n]),ie(e,t,n))}const Rc=Symbol.for("v-scx"),Ic=()=>wt(Rc),Fc="3.3.4",Pc="http://www.w3.org/2000/svg",ot=typeof document<"u"?document:null,Os=ot&&ot.createElement("template"),Lc={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,r)=>{const s=t?ot.createElementNS(Pc,e):ot.createElement(e,n?{is:n}:void 0);return e==="select"&&r&&r.multiple!=null&&s.setAttribute("multiple",r.multiple),s},createText:e=>ot.createTextNode(e),createComment:e=>ot.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>ot.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,r,s,i){const o=n?n.previousSibling:t.lastChild;if(s&&(s===i||s.nextSibling))for(;t.insertBefore(s.cloneNode(!0),n),!(s===i||!(s=s.nextSibling)););else{Os.innerHTML=r?`${e}`:e;const l=Os.content;if(r){const c=l.firstChild;for(;c.firstChild;)l.appendChild(c.firstChild);l.removeChild(c)}t.insertBefore(l,n)}return[o?o.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}};function Mc(e,t,n){const r=e._vtc;r&&(t=(t?[t,...r]:[...r]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}function Nc(e,t,n){const r=e.style,s=oe(n);if(n&&!s){if(t&&!oe(t))for(const i in t)n[i]==null&&vr(r,i,"");for(const i in n)vr(r,i,n[i])}else{const i=r.display;s?t!==n&&(r.cssText=n):t&&e.removeAttribute("style"),"_vod"in e&&(r.display=i)}}const Rs=/\s*!important$/;function vr(e,t,n){if(K(n))n.forEach(r=>vr(e,t,r));else if(n==null&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{const r=$c(e,t);Rs.test(n)?e.setProperty(ut(r),n.replace(Rs,""),"important"):e[r]=n}}const Is=["Webkit","Moz","ms"],qn={};function $c(e,t){const n=qn[t];if(n)return n;let r=He(t);if(r!=="filter"&&r in e)return qn[t]=r;r=Sn(r);for(let s=0;sYn||(Uc.then(()=>Yn=0),Yn=Date.now());function Wc(e,t){const n=r=>{if(!r._vts)r._vts=Date.now();else if(r._vts<=n.attached)return;Ae(Vc(r,n.value),t,5,[r])};return n.value=e,n.attached=Kc(),n}function Vc(e,t){if(K(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(r=>s=>!s._stopped&&r&&r(s))}else return t}const Ls=/^on[a-z]/,qc=(e,t,n,r,s=!1,i,o,l,c)=>{t==="class"?Mc(e,r,s):t==="style"?Nc(e,n,r):zt(t)?wr(t)||kc(e,t,n,r,o):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):Yc(e,t,r,s))?Hc(e,t,r,i,o,l,c):(t==="true-value"?e._trueValue=r:t==="false-value"&&(e._falseValue=r),Bc(e,t,r,s))};function Yc(e,t,n,r){return r?!!(t==="innerHTML"||t==="textContent"||t in e&&Ls.test(t)&&W(n)):t==="spellcheck"||t==="draggable"||t==="translate"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA"||Ls.test(t)&&oe(n)?!1:t in e}const Ve="transition",Pt="animation",Zi=(e,{slots:t})=>yr(jl,Xc(e),t);Zi.displayName="Transition";const Gi={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String};Zi.props=ce({},Ti,Gi);const rt=(e,t=[])=>{K(e)?e.forEach(n=>n(...t)):e&&e(...t)},Ms=e=>e?K(e)?e.some(t=>t.length>1):e.length>1:!1;function Xc(e){const t={};for(const F in e)F in Gi||(t[F]=e[F]);if(e.css===!1)return t;const{name:n="v",type:r,duration:s,enterFromClass:i=`${n}-enter-from`,enterActiveClass:o=`${n}-enter-active`,enterToClass:l=`${n}-enter-to`,appearFromClass:c=i,appearActiveClass:a=o,appearToClass:f=l,leaveFromClass:d=`${n}-leave-from`,leaveActiveClass:p=`${n}-leave-active`,leaveToClass:y=`${n}-leave-to`}=e,w=zc(s),T=w&&w[0],L=w&&w[1],{onBeforeEnter:v,onEnter:_,onEnterCancelled:j,onLeave:m,onLeaveCancelled:R,onBeforeAppear:U=v,onAppear:B=_,onAppearCancelled:b=j}=t,M=(F,q,$)=>{st(F,q?f:l),st(F,q?a:o),$&&$()},A=(F,q)=>{F._isLeaving=!1,st(F,d),st(F,y),st(F,p),q&&q()},N=F=>(q,$)=>{const de=F?B:_,J=()=>M(q,F,$);rt(de,[q,J]),Ns(()=>{st(q,F?c:i),qe(q,F?f:l),Ms(de)||$s(q,r,T,J)})};return ce(t,{onBeforeEnter(F){rt(v,[F]),qe(F,i),qe(F,o)},onBeforeAppear(F){rt(U,[F]),qe(F,c),qe(F,a)},onEnter:N(!1),onAppear:N(!0),onLeave(F,q){F._isLeaving=!0;const $=()=>A(F,q);qe(F,d),Zc(),qe(F,p),Ns(()=>{F._isLeaving&&(st(F,d),qe(F,y),Ms(m)||$s(F,r,L,$))}),rt(m,[F,$])},onEnterCancelled(F){M(F,!1),rt(j,[F])},onAppearCancelled(F){M(F,!0),rt(b,[F])},onLeaveCancelled(F){A(F),rt(R,[F])}})}function zc(e){if(e==null)return null;if(te(e))return[Xn(e.enter),Xn(e.leave)];{const t=Xn(e);return[t,t]}}function Xn(e){return Gs(e)}function qe(e,t){t.split(/\s+/).forEach(n=>n&&e.classList.add(n)),(e._vtc||(e._vtc=new Set)).add(t)}function st(e,t){t.split(/\s+/).forEach(r=>r&&e.classList.remove(r));const{_vtc:n}=e;n&&(n.delete(t),n.size||(e._vtc=void 0))}function Ns(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let Jc=0;function $s(e,t,n,r){const s=e._endId=++Jc,i=()=>{s===e._endId&&r()};if(n)return setTimeout(i,n);const{type:o,timeout:l,propCount:c}=Qc(e,t);if(!o)return r();const a=o+"end";let f=0;const d=()=>{e.removeEventListener(a,p),i()},p=y=>{y.target===e&&++f>=c&&d()};setTimeout(()=>{f(n[w]||"").split(", "),s=r(`${Ve}Delay`),i=r(`${Ve}Duration`),o=Bs(s,i),l=r(`${Pt}Delay`),c=r(`${Pt}Duration`),a=Bs(l,c);let f=null,d=0,p=0;t===Ve?o>0&&(f=Ve,d=o,p=i.length):t===Pt?a>0&&(f=Pt,d=a,p=c.length):(d=Math.max(o,a),f=d>0?o>a?Ve:Pt:null,p=f?f===Ve?i.length:c.length:0);const y=f===Ve&&/\b(transform|all)(,|$)/.test(r(`${Ve}Property`).toString());return{type:f,timeout:d,propCount:p,hasTransform:y}}function Bs(e,t){for(;e.lengthHs(n)+Hs(e[r])))}function Hs(e){return Number(e.slice(0,-1).replace(",","."))*1e3}function Zc(){return document.body.offsetHeight}const js=e=>{const t=e.props["onUpdate:modelValue"]||!1;return K(t)?n=>pn(t,n):t};function Gc(e){e.target.composing=!0}function ks(e){const t=e.target;t.composing&&(t.composing=!1,t.dispatchEvent(new Event("input")))}const yu={created(e,{modifiers:{lazy:t,trim:n,number:r}},s){e._assign=js(s);const i=r||s.props&&s.props.type==="number";pt(e,t?"change":"input",o=>{if(o.target.composing)return;let l=e.value;n&&(l=l.trim()),i&&(l=sr(l)),e._assign(l)}),n&&pt(e,"change",()=>{e.value=e.value.trim()}),t||(pt(e,"compositionstart",Gc),pt(e,"compositionend",ks),pt(e,"change",ks))},mounted(e,{value:t}){e.value=t??""},beforeUpdate(e,{value:t,modifiers:{lazy:n,trim:r,number:s}},i){if(e._assign=js(i),e.composing||document.activeElement===e&&e.type!=="range"&&(n||r&&e.value.trim()===t||(s||e.type==="number")&&sr(e.value)===t))return;const o=t??"";e.value!==o&&(e.value=o)}},ea=["ctrl","shift","alt","meta"],ta={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&e.button!==0,middle:e=>"button"in e&&e.button!==1,right:e=>"button"in e&&e.button!==2,exact:(e,t)=>ea.some(n=>e[`${n}Key`]&&!t.includes(n))},vu=(e,t)=>(n,...r)=>{for(let s=0;sn=>{if(!("key"in n))return;const r=ut(n.key);if(t.some(s=>s===r||na[s]===r))return e(n)},eo=ce({patchProp:qc},Lc);let Dt,Ds=!1;function ra(){return Dt||(Dt=dc(eo))}function sa(){return Dt=Ds?Dt:hc(eo),Ds=!0,Dt}const wu=(...e)=>{const t=ra().createApp(...e),{mount:n}=t;return t.mount=r=>{const s=to(r);if(!s)return;const i=t._component;!W(i)&&!i.render&&!i.template&&(i.template=s.innerHTML),s.innerHTML="";const o=n(s,!1,s instanceof SVGElement);return s instanceof Element&&(s.removeAttribute("v-cloak"),s.setAttribute("data-v-app","")),o},t},Eu=(...e)=>{const t=sa().createApp(...e),{mount:n}=t;return t.mount=r=>{const s=to(r);if(s)return n(s,!0,s instanceof SVGElement)},t};function to(e){return oe(e)?document.querySelector(e):e}const Cu="/me.jpg",xu=(e,t)=>{const n=e.__vccOpts||e;for(const[r,s]of t)n[r]=s;return n},ia=window.__VP_SITE_DATA__;function zr(e){return ni()?(No(e),!0):!1}function Be(e){return typeof e=="function"?e():gi(e)}const no=typeof window<"u"&&typeof document<"u";typeof WorkerGlobalScope<"u"&&globalThis instanceof WorkerGlobalScope;const oa=Object.prototype.toString,la=e=>oa.call(e)==="[object Object]",Xt=()=>{},Us=ca();function ca(){var e,t;return no&&((e=window==null?void 0:window.navigator)==null?void 0:e.userAgent)&&(/iP(?:ad|hone|od)/.test(window.navigator.userAgent)||((t=window==null?void 0:window.navigator)==null?void 0:t.maxTouchPoints)>2&&/iPad|Macintosh/.test(window==null?void 0:window.navigator.userAgent))}function aa(e,t){function n(...r){return new Promise((s,i)=>{Promise.resolve(e(()=>t.apply(this,r),{fn:t,thisArg:this,args:r})).then(s).catch(i)})}return n}const ro=e=>e();function ua(e,t={}){let n,r,s=Xt;const i=l=>{clearTimeout(l),s(),s=Xt};return l=>{const c=Be(e),a=Be(t.maxWait);return n&&i(n),c<=0||a!==void 0&&a<=0?(r&&(i(r),r=null),Promise.resolve(l())):new Promise((f,d)=>{s=t.rejectOnCancel?d:f,a&&!r&&(r=setTimeout(()=>{n&&i(n),r=null,f(l())},a)),n=setTimeout(()=>{r&&i(r),r=null,f(l())},c)})}}function fa(e=ro){const t=se(!0);function n(){t.value=!1}function r(){t.value=!0}const s=(...i)=>{t.value&&e(...i)};return{isActive:In(t),pause:n,resume:r,eventFilter:s}}function da(e){return Qt()}function so(...e){if(e.length!==1)return ml(...e);const t=e[0];return typeof t=="function"?In(hl(()=>({get:t,set:Xt}))):se(t)}function io(e,t,n={}){const{eventFilter:r=ro,...s}=n;return $e(e,aa(r,t),s)}function ha(e,t,n={}){const{eventFilter:r,...s}=n,{eventFilter:i,pause:o,resume:l,isActive:c}=fa(r);return{stop:io(e,t,{...s,eventFilter:i}),pause:o,resume:l,isActive:c}}function Jr(e,t=!0,n){da()?It(e,n):t?e():Fn(e)}function Tu(e,t,n={}){const{debounce:r=0,maxWait:s=void 0,...i}=n;return io(e,t,{...i,eventFilter:ua(r,{maxWait:s})})}function Au(e,t,n){let r;ue(n)?r={evaluating:n}:r={};const{lazy:s=!1,evaluating:i=void 0,shallow:o=!0,onError:l=Xt}=r,c=se(!s),a=o?Br(t):se(t);let f=0;return Dr(async d=>{if(!c.value)return;f++;const p=f;let y=!1;i&&Promise.resolve().then(()=>{i.value=!0});try{const w=await e(T=>{d(()=>{i&&(i.value=!1),y||T()})});p===f&&(a.value=w)}catch(w){l(w)}finally{i&&p===f&&(i.value=!1),y=!0}}),s?re(()=>(c.value=!0,a.value)):a}function oo(e){var t;const n=Be(e);return(t=n==null?void 0:n.$el)!=null?t:n}const Re=no?window:void 0;function At(...e){let t,n,r,s;if(typeof e[0]=="string"||Array.isArray(e[0])?([n,r,s]=e,t=Re):[t,n,r,s]=e,!t)return Xt;Array.isArray(n)||(n=[n]),Array.isArray(r)||(r=[r]);const i=[],o=()=>{i.forEach(f=>f()),i.length=0},l=(f,d,p,y)=>(f.addEventListener(d,p,y),()=>f.removeEventListener(d,p,y)),c=$e(()=>[oo(t),Be(s)],([f,d])=>{if(o(),!f)return;const p=la(d)?{...d}:d;i.push(...n.flatMap(y=>r.map(w=>l(f,y,w,p))))},{immediate:!0,flush:"post"}),a=()=>{c(),o()};return zr(a),a}function pa(e){return typeof e=="function"?e:typeof e=="string"?t=>t.key===e:Array.isArray(e)?t=>e.includes(t.key):()=>!0}function Su(...e){let t,n,r={};e.length===3?(t=e[0],n=e[1],r=e[2]):e.length===2?typeof e[1]=="object"?(t=!0,n=e[0],r=e[1]):(t=e[0],n=e[1]):(t=!0,n=e[0]);const{target:s=Re,eventName:i="keydown",passive:o=!1,dedupe:l=!1}=r,c=pa(t);return At(s,i,f=>{f.repeat&&Be(l)||c(f)&&n(f)},o)}function ga(){const e=se(!1),t=Qt();return t&&It(()=>{e.value=!0},t),e}function ma(e){const t=ga();return re(()=>(t.value,!!e()))}function lo(e,t={}){const{window:n=Re}=t,r=ma(()=>n&&"matchMedia"in n&&typeof n.matchMedia=="function");let s;const i=se(!1),o=a=>{i.value=a.matches},l=()=>{s&&("removeEventListener"in s?s.removeEventListener("change",o):s.removeListener(o))},c=Dr(()=>{r.value&&(l(),s=n.matchMedia(Be(e)),"addEventListener"in s?s.addEventListener("change",o):s.addListener(o),i.value=s.matches)});return zr(()=>{c(),l(),s=void 0}),i}const un=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{},fn="__vueuse_ssr_handlers__",_a=ya();function ya(){return fn in un||(un[fn]=un[fn]||{}),un[fn]}function co(e,t){return _a[e]||t}function va(e){return e==null?"any":e instanceof Set?"set":e instanceof Map?"map":e instanceof Date?"date":typeof e=="boolean"?"boolean":typeof e=="string"?"string":typeof e=="object"?"object":Number.isNaN(e)?"any":"number"}const ba={boolean:{read:e=>e==="true",write:e=>String(e)},object:{read:e=>JSON.parse(e),write:e=>JSON.stringify(e)},number:{read:e=>Number.parseFloat(e),write:e=>String(e)},any:{read:e=>e,write:e=>String(e)},string:{read:e=>e,write:e=>String(e)},map:{read:e=>new Map(JSON.parse(e)),write:e=>JSON.stringify(Array.from(e.entries()))},set:{read:e=>new Set(JSON.parse(e)),write:e=>JSON.stringify(Array.from(e))},date:{read:e=>new Date(e),write:e=>e.toISOString()}},Ks="vueuse-storage";function Qr(e,t,n,r={}){var s;const{flush:i="pre",deep:o=!0,listenToStorageChanges:l=!0,writeDefaults:c=!0,mergeDefaults:a=!1,shallow:f,window:d=Re,eventFilter:p,onError:y=A=>{console.error(A)},initOnMounted:w}=r,T=(f?Br:se)(typeof t=="function"?t():t);if(!n)try{n=co("getDefaultStorage",()=>{var A;return(A=Re)==null?void 0:A.localStorage})()}catch(A){y(A)}if(!n)return T;const L=Be(t),v=va(L),_=(s=r.serializer)!=null?s:ba[v],{pause:j,resume:m}=ha(T,()=>U(T.value),{flush:i,deep:o,eventFilter:p});d&&l&&Jr(()=>{At(d,"storage",b),At(d,Ks,M),w&&b()}),w||b();function R(A,N){d&&d.dispatchEvent(new CustomEvent(Ks,{detail:{key:e,oldValue:A,newValue:N,storageArea:n}}))}function U(A){try{const N=n.getItem(e);if(A==null)R(N,null),n.removeItem(e);else{const F=_.write(A);N!==F&&(n.setItem(e,F),R(N,F))}}catch(N){y(N)}}function B(A){const N=A?A.newValue:n.getItem(e);if(N==null)return c&&L!=null&&n.setItem(e,_.write(L)),L;if(!A&&a){const F=_.read(N);return typeof a=="function"?a(F,L):v==="object"&&!Array.isArray(F)?{...L,...F}:F}else return typeof N!="string"?N:_.read(N)}function b(A){if(!(A&&A.storageArea!==n)){if(A&&A.key==null){T.value=L;return}if(!(A&&A.key!==e)){j();try{(A==null?void 0:A.newValue)!==_.write(T.value)&&(T.value=B(A))}catch(N){y(N)}finally{A?Fn(m):m()}}}}function M(A){b(A.detail)}return T}function ao(e){return lo("(prefers-color-scheme: dark)",e)}function wa(e={}){const{selector:t="html",attribute:n="class",initialValue:r="auto",window:s=Re,storage:i,storageKey:o="vueuse-color-scheme",listenToStorageChanges:l=!0,storageRef:c,emitAuto:a,disableTransition:f=!0}=e,d={auto:"",light:"light",dark:"dark",...e.modes||{}},p=ao({window:s}),y=re(()=>p.value?"dark":"light"),w=c||(o==null?so(r):Qr(o,r,i,{window:s,listenToStorageChanges:l})),T=re(()=>w.value==="auto"?y.value:w.value),L=co("updateHTMLAttrs",(m,R,U)=>{const B=typeof m=="string"?s==null?void 0:s.document.querySelector(m):oo(m);if(!B)return;let b;if(f&&(b=s.document.createElement("style"),b.appendChild(document.createTextNode("*,*::before,*::after{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}")),s.document.head.appendChild(b)),R==="class"){const M=U.split(/\s/g);Object.values(d).flatMap(A=>(A||"").split(/\s/g)).filter(Boolean).forEach(A=>{M.includes(A)?B.classList.add(A):B.classList.remove(A)})}else B.setAttribute(R,U);f&&(s.getComputedStyle(b).opacity,document.head.removeChild(b))});function v(m){var R;L(t,n,(R=d[m])!=null?R:m)}function _(m){e.onChanged?e.onChanged(m,v):v(m)}$e(T,_,{flush:"post",immediate:!0}),Jr(()=>_(T.value));const j=re({get(){return a?w.value:T.value},set(m){w.value=m}});try{return Object.assign(j,{store:w,system:y,state:T})}catch{return j}}function Ea(e={}){const{valueDark:t="dark",valueLight:n="",window:r=Re}=e,s=wa({...e,onChanged:(l,c)=>{var a;e.onChanged?(a=e.onChanged)==null||a.call(e,l==="dark",c,l):c(l)},modes:{dark:t,light:n}}),i=re(()=>s.system?s.system.value:ao({window:r}).value?"dark":"light");return re({get(){return s.value==="dark"},set(l){const c=l?"dark":"light";i.value===c?s.value="auto":s.value=c}})}function zn(e){return typeof Window<"u"&&e instanceof Window?e.document.documentElement:typeof Document<"u"&&e instanceof Document?e.documentElement:e}function Ou(e,t,n={}){const{window:r=Re}=n;return Qr(e,t,r==null?void 0:r.localStorage,n)}function uo(e){const t=window.getComputedStyle(e);if(t.overflowX==="scroll"||t.overflowY==="scroll"||t.overflowX==="auto"&&e.clientWidth1?!0:(t.preventDefault&&t.preventDefault(),!1)}const Jn=new WeakMap;function Ru(e,t=!1){const n=se(t);let r=null,s="";$e(so(e),l=>{const c=zn(Be(l));if(c){const a=c;if(Jn.get(a)||Jn.set(a,a.style.overflow),a.style.overflow!=="hidden"&&(s=a.style.overflow),a.style.overflow==="hidden")return n.value=!0;if(n.value)return a.style.overflow="hidden"}},{immediate:!0});const i=()=>{const l=zn(Be(e));!l||n.value||(Us&&(r=At(l,"touchmove",c=>{Ca(c)},{passive:!1})),l.style.overflow="hidden",n.value=!0)},o=()=>{const l=zn(Be(e));!l||!n.value||(Us&&(r==null||r()),l.style.overflow=s,Jn.delete(l),n.value=!1)};return zr(o),re({get(){return n.value},set(l){l?i():o()}})}function Iu(e,t,n={}){const{window:r=Re}=n;return Qr(e,t,r==null?void 0:r.sessionStorage,n)}function Fu(e={}){const{window:t=Re,behavior:n="auto"}=e;if(!t)return{x:se(0),y:se(0)};const r=se(t.scrollX),s=se(t.scrollY),i=re({get(){return r.value},set(l){scrollTo({left:l,behavior:n})}}),o=re({get(){return s.value},set(l){scrollTo({top:l,behavior:n})}});return At(t,"scroll",()=>{r.value=t.scrollX,s.value=t.scrollY},{capture:!1,passive:!0}),{x:i,y:o}}function Pu(e={}){const{window:t=Re,initialWidth:n=Number.POSITIVE_INFINITY,initialHeight:r=Number.POSITIVE_INFINITY,listenOrientation:s=!0,includeScrollbar:i=!0}=e,o=se(n),l=se(r),c=()=>{t&&(i?(o.value=t.innerWidth,l.value=t.innerHeight):(o.value=t.document.documentElement.clientWidth,l.value=t.document.documentElement.clientHeight))};if(c(),Jr(c),At("resize",c,{passive:!0}),s){const a=lo("(orientation: portrait)");$e(a,()=>c())}return{width:o,height:l}}var Qn={BASE_URL:"/",MODE:"production",DEV:!1,PROD:!0,SSR:!1},Zn={};const fo=/^(?:[a-z]+:|\/\/)/i,xa="vitepress-theme-appearance",Ta=/#.*$/,Aa=/[?#].*$/,Sa=/(?:(^|\/)index)?\.(?:md|html)$/,he=typeof document<"u",ho={relativePath:"404.md",filePath:"",title:"404",description:"Not Found",headers:[],frontmatter:{sidebar:!1,layout:"page"},lastUpdated:0,isNotFound:!0};function Oa(e,t,n=!1){if(t===void 0)return!1;if(e=Ws(`/${e}`),n)return new RegExp(t).test(e);if(Ws(t)!==e)return!1;const r=t.match(Ta);return r?(he?location.hash:"")===r[0]:!0}function Ws(e){return decodeURI(e).replace(Aa,"").replace(Sa,"$1")}function Ra(e){return fo.test(e)}function Ia(e,t){return Object.keys((e==null?void 0:e.locales)||{}).find(n=>n!=="root"&&!Ra(n)&&Oa(t,`/${n}/`,!0))||"root"}function Fa(e,t){var r,s,i,o,l,c,a;const n=Ia(e,t);return Object.assign({},e,{localeIndex:n,lang:((r=e.locales[n])==null?void 0:r.lang)??e.lang,dir:((s=e.locales[n])==null?void 0:s.dir)??e.dir,title:((i=e.locales[n])==null?void 0:i.title)??e.title,titleTemplate:((o=e.locales[n])==null?void 0:o.titleTemplate)??e.titleTemplate,description:((l=e.locales[n])==null?void 0:l.description)??e.description,head:go(e.head,((c=e.locales[n])==null?void 0:c.head)??[]),themeConfig:{...e.themeConfig,...(a=e.locales[n])==null?void 0:a.themeConfig}})}function po(e,t){const n=t.title||e.title,r=t.titleTemplate??e.titleTemplate;if(typeof r=="string"&&r.includes(":title"))return r.replace(/:title/g,n);const s=Pa(e.title,r);return n===s.slice(3)?n:`${n}${s}`}function Pa(e,t){return t===!1?"":t===!0||t===void 0?` | ${e}`:e===t?"":` | ${t}`}function La(e,t){const[n,r]=t;if(n!=="meta")return!1;const s=Object.entries(r)[0];return s==null?!1:e.some(([i,o])=>i===n&&o[s[0]]===s[1])}function go(e,t){return[...e.filter(n=>!La(t,n)),...t]}const Ma=/[\u0000-\u001F"#$&*+,:;<=>?[\]^`{|}\u007F]/g,Na=/^[a-z]:/i;function Vs(e){const t=Na.exec(e),n=t?t[0]:"";return n+e.slice(n.length).replace(Ma,"_").replace(/(^|\/)_+(?=[^/]*$)/,"$1")}const Gn=new Set;function $a(e){if(Gn.size===0){const n=typeof process=="object"&&(Zn==null?void 0:Zn.VITE_EXTRA_EXTENSIONS)||(Qn==null?void 0:Qn.VITE_EXTRA_EXTENSIONS)||"";("3g2,3gp,aac,ai,apng,au,avif,bin,bmp,cer,class,conf,crl,css,csv,dll,doc,eps,epub,exe,gif,gz,ics,ief,jar,jpe,jpeg,jpg,js,json,jsonld,m4a,man,mid,midi,mjs,mov,mp2,mp3,mp4,mpe,mpeg,mpg,mpp,oga,ogg,ogv,ogx,opus,otf,p10,p7c,p7m,p7s,pdf,png,ps,qt,roff,rtf,rtx,ser,svg,t,tif,tiff,tr,ts,tsv,ttf,txt,vtt,wav,weba,webm,webp,woff,woff2,xhtml,xml,yaml,yml,zip"+(n&&typeof n=="string"?","+n:"")).split(",").forEach(r=>Gn.add(r))}const t=e.split(".").pop();return t==null||!Gn.has(t.toLowerCase())}function Lu(e){return e.replace(/[|\\{}()[\]^$+*?.]/g,"\\$&").replace(/-/g,"\\x2d")}const Ba=Symbol(),at=Br(ia);function Mu(e){const t=re(()=>Fa(at.value,e.data.relativePath)),n=t.value.appearance,r=n==="force-dark"?se(!0):n?Ea({storageKey:xa,initialValue:()=>typeof n=="string"?n:"auto",...typeof n=="object"?n:{}}):se(!1),s=se(he?location.hash:"");return he&&window.addEventListener("hashchange",()=>{s.value=location.hash}),$e(()=>e.data,()=>{s.value=he?location.hash:""}),{site:t,theme:re(()=>t.value.themeConfig),page:re(()=>e.data),frontmatter:re(()=>e.data.frontmatter),params:re(()=>e.data.params),lang:re(()=>t.value.lang),dir:re(()=>e.data.frontmatter.dir||t.value.dir),localeIndex:re(()=>t.value.localeIndex||"root"),title:re(()=>po(t.value,e.data)),description:re(()=>e.data.description||t.value.description),isDark:r,hash:re(()=>s.value)}}function Ha(){const e=wt(Ba);if(!e)throw new Error("vitepress data not properly injected in app");return e}function ja(e,t){return`${e}${t}`.replace(/\/+/g,"/")}function qs(e){return fo.test(e)||!e.startsWith("/")?e:ja(at.value.base,e)}function ka(e){let t=e.replace(/\.html$/,"");if(t=decodeURIComponent(t),t=t.replace(/\/$/,"/index"),he){const n="/";t=Vs(t.slice(n.length).replace(/\//g,"_")||"index")+".md";let r=__VP_HASH_MAP__[t.toLowerCase()];if(r||(t=t.endsWith("_index.md")?t.slice(0,-9)+".md":t.slice(0,-3)+"_index.md",r=__VP_HASH_MAP__[t.toLowerCase()]),!r)return null;t=`${n}assets/${t}.${r}.js`}else t=`./${Vs(t.slice(1).replace(/\//g,"_"))}.md.js`;return t}let mn=[];function Nu(e){mn.push(e),Bn(()=>{mn=mn.filter(t=>t!==e)})}function Da(){let e=at.value.scrollOffset,t=0,n=24;if(typeof e=="object"&&"padding"in e&&(n=e.padding,e=e.selector),typeof e=="number")t=e;else if(typeof e=="string")t=Ys(e,n);else if(Array.isArray(e))for(const r of e){const s=Ys(r,n);if(s){t=s;break}}return t}function Ys(e,t){const n=document.querySelector(e);if(!n)return 0;const r=n.getBoundingClientRect().bottom;return r<0?0:r+t}const Ua=Symbol(),mo="http://a.com",Ka=()=>({path:"/",component:null,data:ho});function $u(e,t){const n=Rn(Ka()),r={route:n,go:s};async function s(l=he?location.href:"/"){var c,a;l=er(l),await((c=r.onBeforeRouteChange)==null?void 0:c.call(r,l))!==!1&&(he&&l!==er(location.href)&&(history.replaceState({scrollPosition:window.scrollY},""),history.pushState({},"",l)),await o(l),await((a=r.onAfterRouteChanged)==null?void 0:a.call(r,l)))}let i=null;async function o(l,c=0,a=!1){var p;if(await((p=r.onBeforePageLoad)==null?void 0:p.call(r,l))===!1)return;const f=new URL(l,mo),d=i=f.pathname;try{let y=await e(d);if(!y)throw new Error(`Page not found: ${d}`);if(i===d){i=null;const{default:w,__pageData:T}=y;if(!w)throw new Error(`Invalid route component: ${w}`);n.path=he?d:qs(d),n.component=$t(w),n.data=$t(T),he&&Fn(()=>{let L=at.value.base+T.relativePath.replace(/(?:(^|\/)index)?\.md$/,"$1");if(!at.value.cleanUrls&&!L.endsWith("/")&&(L+=".html"),L!==f.pathname&&(f.pathname=L,l=L+f.search+f.hash,history.replaceState({},"",l)),f.hash&&!c){let v=null;try{v=document.getElementById(decodeURIComponent(f.hash).slice(1))}catch(_){console.warn(_)}if(v){Xs(v,f.hash);return}}window.scrollTo(0,c)})}}catch(y){if(!/fetch|Page not found/.test(y.message)&&!/^\/404(\.html|\/)?$/.test(l)&&console.error(y),!a)try{const w=await fetch(at.value.base+"hashmap.json");window.__VP_HASH_MAP__=await w.json(),await o(l,c,!0);return}catch{}if(i===d){i=null,n.path=he?d:qs(d),n.component=t?$t(t):null;const w=he?d.replace(/(^|\/)$/,"$1index").replace(/(\.html)?$/,".md").replace(/^\//,""):"404.md";n.data={...ho,relativePath:w}}}}return he&&(history.state===null&&history.replaceState({},""),window.addEventListener("click",l=>{if(l.target.closest("button"))return;const a=l.target.closest("a");if(a&&!a.closest(".vp-raw")&&(a instanceof SVGElement||!a.download)){const{target:f}=a,{href:d,origin:p,pathname:y,hash:w,search:T}=new URL(a.href instanceof SVGAnimatedString?a.href.animVal:a.href,a.baseURI),L=new URL(location.href);!l.ctrlKey&&!l.shiftKey&&!l.altKey&&!l.metaKey&&!f&&p===L.origin&&$a(y)&&(l.preventDefault(),y===L.pathname&&T===L.search?(w!==L.hash&&(history.pushState({},"",d),window.dispatchEvent(new HashChangeEvent("hashchange",{oldURL:L.href,newURL:d}))),w?Xs(a,w,a.classList.contains("header-anchor")):window.scrollTo(0,0)):s(d))}},{capture:!0}),window.addEventListener("popstate",async l=>{var c;l.state!==null&&(await o(er(location.href),l.state&&l.state.scrollPosition||0),(c=r.onAfterRouteChanged)==null||c.call(r,location.href))}),window.addEventListener("hashchange",l=>{l.preventDefault()})),r}function Wa(){const e=wt(Ua);if(!e)throw new Error("useRouter() is called without provider.");return e}function _o(){return Wa().route}function Xs(e,t,n=!1){let r=null;try{r=e.classList.contains("header-anchor")?e:document.getElementById(decodeURIComponent(t).slice(1))}catch(s){console.warn(s)}if(r){let s=function(){!n||Math.abs(o-window.scrollY)>window.innerHeight?window.scrollTo(0,o):window.scrollTo({left:0,top:o,behavior:"smooth"})};const i=parseInt(window.getComputedStyle(r).paddingTop,10),o=window.scrollY+r.getBoundingClientRect().top-Da()+i;requestAnimationFrame(s)}}function er(e){const t=new URL(e,mo);return t.pathname=t.pathname.replace(/(^|\/)index(\.html)?$/,"$1"),at.value.cleanUrls?t.pathname=t.pathname.replace(/\.html$/,""):!t.pathname.endsWith("/")&&!t.pathname.endsWith(".html")&&(t.pathname+=".html"),t.pathname+t.search+t.hash}const tr=()=>mn.forEach(e=>e()),Bu=Ur({name:"VitePressContent",props:{as:{type:[Object,String],default:"div"}},setup(e){const t=_o(),{site:n}=Ha();return()=>yr(e.as,n.value.contentProps??{style:{position:"relative"}},[t.component?yr(t.component,{onVnodeMounted:tr,onVnodeUpdated:tr,onVnodeUnmounted:tr}):"404 Page Not Found"])}}),Hu="/garden/screenshot_1717381273245_0.png",ju="/garden/da2_1717378483173_0.png",ku="/garden/editors_1717378509527_0.png",Du="/garden/simulator_1717378525890_0.jpg",Uu="/garden/da1_1717378469912_0.png",Ku="/garden/da6_1717379962786_0.png",Wu="/garden/da7_1717379991458_0.png",Vu="/garden/da8_1717380011914_0.png",qu="/garden/da3_1717380046653_0.png",Yu="/garden/da9_1717380177060_0.png",Xu="/garden/6346b024-885e-45e0-9df6-5ee0311133f7_1718332409063_0.png",zu="/garden/ce7b2612-2ddb-423e-82eb-95c2ed08c4da_1718332277410_0.png",Ju="/garden/system-architecture-600_1717384793933_0.jpg",Qu="/garden/new-interface_1717384734845_0.png",Zu="/garden/documentation_1717384823218_0.png",Gu="/garden/unittests_1717384825666_0.png",ef="/garden/screenshot_1717383987886_0.png",tf="/garden/debug_1717384018620_0.png",nf="/garden/sandsoftime_1717383994964_0.png",rf="/paperpilot.png",Va="modulepreload",qa=function(e){return"/"+e},zs={},sf=function(t,n,r){let s=Promise.resolve();if(n&&n.length>0){document.getElementsByTagName("link");const i=document.querySelector("meta[property=csp-nonce]"),o=(i==null?void 0:i.nonce)||(i==null?void 0:i.getAttribute("nonce"));s=Promise.all(n.map(l=>{if(l=qa(l),l in zs)return;zs[l]=!0;const c=l.endsWith(".css"),a=c?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${l}"]${a}`))return;const f=document.createElement("link");if(f.rel=c?"stylesheet":Va,c||(f.as="script",f.crossOrigin=""),f.href=l,o&&f.setAttribute("nonce",o),document.head.appendChild(f),c)return new Promise((d,p)=>{f.addEventListener("load",d),f.addEventListener("error",()=>p(new Error(`Unable to preload CSS for ${l}`)))})}))}return s.then(()=>t()).catch(i=>{const o=new Event("vite:preloadError",{cancelable:!0});if(o.payload=i,window.dispatchEvent(o),!o.defaultPrevented)throw i})},of=Ur({setup(e,{slots:t}){const n=se(!1);return It(()=>{n.value=!0}),()=>n.value&&t.default?t.default():null}});function lf(){he&&window.addEventListener("click",e=>{var n;const t=e.target;if(t.matches(".vp-code-group input")){const r=(n=t.parentElement)==null?void 0:n.parentElement;if(!r)return;const s=Array.from(r.querySelectorAll("input")).indexOf(t);if(s<0)return;const i=r.querySelector(".blocks");if(!i)return;const o=Array.from(i.children).find(a=>a.classList.contains("active"));if(!o)return;const l=i.children[s];if(!l||o===l)return;o.classList.remove("active"),l.classList.add("active");const c=r==null?void 0:r.querySelector(`label[for="${t.id}"]`);c==null||c.scrollIntoView({block:"nearest"})}})}function cf(){if(he){const e=new WeakMap;window.addEventListener("click",t=>{var r;const n=t.target;if(n.matches('div[class*="language-"] > button.copy')){const s=n.parentElement,i=(r=n.nextElementSibling)==null?void 0:r.nextElementSibling;if(!s||!i)return;const o=/language-(shellscript|shell|bash|sh|zsh)/.test(s.className),l=[".vp-copy-ignore",".diff.remove"],c=i.cloneNode(!0);c.querySelectorAll(l.join(",")).forEach(f=>f.remove());let a=c.textContent||"";o&&(a=a.replace(/^ *(\$|>) /gm,"").trim()),Ya(a).then(()=>{n.classList.add("copied"),clearTimeout(e.get(n));const f=setTimeout(()=>{n.classList.remove("copied"),n.blur(),e.delete(n)},2e3);e.set(n,f)})}})}}async function Ya(e){try{return navigator.clipboard.writeText(e)}catch{const t=document.createElement("textarea"),n=document.activeElement;t.value=e,t.setAttribute("readonly",""),t.style.contain="strict",t.style.position="absolute",t.style.left="-9999px",t.style.fontSize="12pt";const r=document.getSelection(),s=r?r.rangeCount>0&&r.getRangeAt(0):null;document.body.appendChild(t),t.select(),t.selectionStart=0,t.selectionEnd=e.length,document.execCommand("copy"),document.body.removeChild(t),s&&(r.removeAllRanges(),r.addRange(s)),n&&n.focus()}}function af(e,t){let n=!0,r=[];const s=i=>{if(n){n=!1,i.forEach(l=>{const c=nr(l);for(const a of document.head.children)if(a.isEqualNode(c)){r.push(a);return}});return}const o=i.map(nr);r.forEach((l,c)=>{const a=o.findIndex(f=>f==null?void 0:f.isEqualNode(l??null));a!==-1?delete o[a]:(l==null||l.remove(),delete r[c])}),o.forEach(l=>l&&document.head.appendChild(l)),r=[...r,...o].filter(Boolean)};Dr(()=>{const i=e.data,o=t.value,l=i&&i.description,c=i&&i.frontmatter.head||[],a=po(o,i);a!==document.title&&(document.title=a);const f=l||o.description;let d=document.querySelector("meta[name=description]");d?d.getAttribute("content")!==f&&d.setAttribute("content",f):nr(["meta",{name:"description",content:f}]),s(go(o.head,za(c)))})}function nr([e,t,n]){const r=document.createElement(e);for(const s in t)r.setAttribute(s,t[s]);return n&&(r.innerHTML=n),e==="script"&&!t.async&&(r.async=!1),r}function Xa(e){return e[0]==="meta"&&e[1]&&e[1].name==="description"}function za(e){return e.filter(t=>!Xa(t))}const rr=new Set,yo=()=>document.createElement("link"),Ja=e=>{const t=yo();t.rel="prefetch",t.href=e,document.head.appendChild(t)},Qa=e=>{const t=new XMLHttpRequest;t.open("GET",e,t.withCredentials=!0),t.send()};let dn;const Za=he&&(dn=yo())&&dn.relList&&dn.relList.supports&&dn.relList.supports("prefetch")?Ja:Qa;function uf(){if(!he||!window.IntersectionObserver)return;let e;if((e=navigator.connection)&&(e.saveData||/2g/.test(e.effectiveType)))return;const t=window.requestIdleCallback||setTimeout;let n=null;const r=()=>{n&&n.disconnect(),n=new IntersectionObserver(i=>{i.forEach(o=>{if(o.isIntersecting){const l=o.target;n.unobserve(l);const{pathname:c}=l;if(!rr.has(c)){rr.add(c);const a=ka(c);a&&Za(a)}}})}),t(()=>{document.querySelectorAll("#app a").forEach(i=>{const{hostname:o,pathname:l}=new URL(i.href instanceof SVGAnimatedString?i.href.animVal:i.href,i.baseURI),c=l.match(/\.\w+$/);c&&c[0]!==".html"||i.target!=="_blank"&&o===location.hostname&&(l!==location.pathname?n.observe(i):rr.add(l))})})};It(r);const s=_o();$e(()=>s.path,r),Bn(()=>{n&&n.disconnect()})}export{bu as $,su as A,Vl as B,Da as C,lu as D,au as E,ye as F,Br as G,Nu as H,ie as I,cu as J,fo as K,_o as L,bc as M,wt as N,Pu as O,Ar as P,Su as Q,Fn as R,Fu as S,Zi as T,he as U,In as V,ou as W,sf as X,Ru as Y,ic as Z,xu as _,Xi as a,Lu as a$,fu as a0,vu as a1,du as a2,At as a3,ue as a4,ni as a5,No as a6,eu as a7,hl as a8,Qt as a9,rf as aA,af as aB,Ua as aC,Mu as aD,Ba as aE,Bu as aF,of as aG,at as aH,Eu as aI,$u as aJ,ka as aK,uf as aL,cf as aM,lf as aN,oo as aO,zr as aP,Au as aQ,Iu as aR,Ou as aS,Tu as aT,Wa as aU,Ri as aV,iu as aW,yu as aX,pu as aY,$t as aZ,wu as a_,Rn as aa,dc as ab,yr as ac,hu as ad,ru as ae,Cu as af,mu as ag,Hu as ah,ju as ai,ku as aj,Du as ak,Uu as al,Ku as am,Wu as an,Vu as ao,qu as ap,Yu as aq,Xu as ar,zu as as,Ju as at,Qu as au,Zu as av,Gu as aw,ef as ax,tf as ay,nf as az,Vi as b,gu as c,Ur as d,_u as e,$a as f,qs as g,re as h,Ra as i,Yi as j,gi as k,nu as l,Oa as m,Sr as n,qr as o,tu as p,lo as q,uu as r,se as s,Ga as t,Ha as u,$e as v,xl as w,Dr as x,It as y,Bn as z}; diff --git a/assets/chunks/theme.Bb5kJd_v.js b/assets/chunks/theme.Bb5kJd_v.js new file mode 100644 index 00000000..cc85daf0 --- /dev/null +++ b/assets/chunks/theme.Bb5kJd_v.js @@ -0,0 +1,3948 @@ +const __vite__fileDeps=["assets/chunks/VPLocalSearchBox.hF612Jrh.js","assets/chunks/framework.DvHfxfnp.js"],__vite__mapDeps=i=>i.map(i=>__vite__fileDeps[i]); +import{u as j,r as Ge,w as Ct,i as $d,t as Vm,c as Hm,o as Nn,n as qc,g as Gm,a as Wm,b as ma,d as gr,e as ke,f as Ri,h as zr,j as $m,k as Be,l as Xd,s as Rn,m as Wn,p as Y,q as fe,v as yt,x as Yc,y as vr,z as Xm,A as eh,F as xt,B as qm,C as cn,D as $e,E as ye,G as Jt,H as De,I as Fe,J as ue,K as Ht,L as ft,T as Zc,_ as Ye,M as Ym,N as Zm,O as Jm,P as Jc,Q as me,R as Wt,S as $t,U as is,V as Kl,W as qd,X as Km,Y as jm,Z as Aa,$ as Bs,a0 as Yd,a1 as Vr,a2 as ia,a3 as Qm,a4 as jl,a5 as Zd,a6 as Ta,a7 as eg,a8 as tg,a9 as Jd,aa as ng,ab as ig,ac as sg,ad as rg,ae as og,af as ag}from"./framework.DvHfxfnp.js";/** + * @license + * Copyright 2010-2024 Three.js Authors + * SPDX-License-Identifier: MIT + */const Hr="165",lg={LEFT:0,MIDDLE:1,RIGHT:2,ROTATE:0,DOLLY:1,PAN:2},cg={ROTATE:0,PAN:1,DOLLY_PAN:2,DOLLY_ROTATE:3},Kd=0,Ql=1,jd=2,ug=3,hg=0,Kc=1,jc=2,kn=3,oi=0,nn=1,En=2,si=0,es=1,ga=2,ec=3,tc=4,Qd=5,Ai=100,ef=101,tf=102,nf=103,sf=104,rf=200,of=201,af=202,lf=203,va=204,_a=205,cf=206,uf=207,hf=208,df=209,ff=210,pf=211,mf=212,gf=213,vf=214,_f=0,yf=1,xf=2,_r=3,Mf=4,bf=5,Sf=6,wf=7,Gr=0,Af=1,Tf=2,Hn=0,Ef=1,Cf=2,Pf=3,Ea=4,Rf=5,If=6,Lf=7,nc="attached",Nf="detached",Ca=300,ai=301,Ci=302,yr=303,xr=304,Ws=306,Mr=1e3,Mn=1001,br=1002,Gt=1003,Qc=1004,dg=1004,Ds=1005,fg=1005,Ot=1006,hr=1007,pg=1007,zn=1008,mg=1008,li=1009,Df=1010,Uf=1011,Sr=1012,eu=1013,ss=1014,gn=1015,Wr=1016,tu=1017,nu=1018,rs=1020,Of=35902,Ff=1021,kf=1022,un=1023,Bf=1024,zf=1025,ts=1026,os=1027,iu=1028,su=1029,Vf=1030,ru=1031,ou=1033,sa=33776,ra=33777,oa=33778,aa=33779,ic=35840,sc=35841,rc=35842,oc=35843,ac=36196,lc=37492,cc=37496,uc=37808,hc=37809,dc=37810,fc=37811,pc=37812,mc=37813,gc=37814,vc=37815,_c=37816,yc=37817,xc=37818,Mc=37819,bc=37820,Sc=37821,la=36492,wc=36494,Ac=36495,Hf=36283,Tc=36284,Ec=36285,Cc=36286,Gf=2200,Wf=2201,$f=2202,wr=2300,ya=2301,ca=2302,Ji=2400,Ki=2401,Ar=2402,Pa=2500,au=2501,gg=0,vg=1,_g=2,Xf=3200,qf=3201,Ii=0,Yf=1,ti="",ln="srgb",ci="srgb-linear",Ra="display-p3",$r="display-p3-linear",Tr="linear",Mt="srgb",Er="rec709",Cr="p3",yg=0,Bn=7680,xg=7681,Mg=7682,bg=7683,Sg=34055,wg=34056,Ag=5386,Tg=512,Eg=513,Zf=514,Cg=515,Pg=516,Rg=517,Ig=518,Pc=519,Jf=512,Kf=513,jf=514,lu=515,Qf=516,ep=517,tp=518,np=519,Pr=35044,Lg=35048,Ng=35040,Dg=35045,Ug=35049,Og=35041,Fg=35046,kg=35050,Bg=35042,zg="100",Rc="300 es",Vn=2e3,Rr=2001;class ui{addEventListener(e,t){this._listeners===void 0&&(this._listeners={});const n=this._listeners;n[e]===void 0&&(n[e]=[]),n[e].indexOf(t)===-1&&n[e].push(t)}hasEventListener(e,t){if(this._listeners===void 0)return!1;const n=this._listeners;return n[e]!==void 0&&n[e].indexOf(t)!==-1}removeEventListener(e,t){if(this._listeners===void 0)return;const i=this._listeners[e];if(i!==void 0){const r=i.indexOf(t);r!==-1&&i.splice(r,1)}}dispatchEvent(e){if(this._listeners===void 0)return;const n=this._listeners[e.type];if(n!==void 0){e.target=this;const i=n.slice(0);for(let r=0,o=i.length;r>8&255]+Xt[s>>16&255]+Xt[s>>24&255]+"-"+Xt[e&255]+Xt[e>>8&255]+"-"+Xt[e>>16&15|64]+Xt[e>>24&255]+"-"+Xt[t&63|128]+Xt[t>>8&255]+"-"+Xt[t>>16&255]+Xt[t>>24&255]+Xt[n&255]+Xt[n>>8&255]+Xt[n>>16&255]+Xt[n>>24&255]).toLowerCase()}function Et(s,e,t){return Math.max(e,Math.min(t,s))}function cu(s,e){return(s%e+e)%e}function Vg(s,e,t,n,i){return n+(s-e)*(i-n)/(t-e)}function Hg(s,e,t){return s!==e?(t-s)/(e-s):0}function dr(s,e,t){return(1-t)*s+t*e}function Gg(s,e,t,n){return dr(s,e,1-Math.exp(-t*n))}function Wg(s,e=1){return e-Math.abs(cu(s,e*2)-e)}function $g(s,e,t){return s<=e?0:s>=t?1:(s=(s-e)/(t-e),s*s*(3-2*s))}function Xg(s,e,t){return s<=e?0:s>=t?1:(s=(s-e)/(t-e),s*s*s*(s*(s*6-15)+10))}function qg(s,e){return s+Math.floor(Math.random()*(e-s+1))}function Yg(s,e){return s+Math.random()*(e-s)}function Zg(s){return s*(.5-Math.random())}function Jg(s){s!==void 0&&(th=s);let e=th+=1831565813;return e=Math.imul(e^e>>>15,e|1),e^=e+Math.imul(e^e>>>7,e|61),((e^e>>>14)>>>0)/4294967296}function Kg(s){return s*ns}function jg(s){return s*Vs}function Qg(s){return(s&s-1)===0&&s!==0}function ev(s){return Math.pow(2,Math.ceil(Math.log(s)/Math.LN2))}function tv(s){return Math.pow(2,Math.floor(Math.log(s)/Math.LN2))}function nv(s,e,t,n,i){const r=Math.cos,o=Math.sin,a=r(t/2),l=o(t/2),c=r((e+n)/2),u=o((e+n)/2),h=r((e-n)/2),d=o((e-n)/2),f=r((n-e)/2),g=o((n-e)/2);switch(i){case"XYX":s.set(a*u,l*h,l*d,a*c);break;case"YZY":s.set(l*d,a*u,l*h,a*c);break;case"ZXZ":s.set(l*h,l*d,a*u,a*c);break;case"XZX":s.set(a*u,l*g,l*f,a*c);break;case"YXY":s.set(l*f,a*u,l*g,a*c);break;case"ZYZ":s.set(l*g,l*f,a*u,a*c);break;default:console.warn("THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: "+i)}}function tn(s,e){switch(e.constructor){case Float32Array:return s;case Uint32Array:return s/4294967295;case Uint16Array:return s/65535;case Uint8Array:return s/255;case Int32Array:return Math.max(s/2147483647,-1);case Int16Array:return Math.max(s/32767,-1);case Int8Array:return Math.max(s/127,-1);default:throw new Error("Invalid component type.")}}function tt(s,e){switch(e.constructor){case Float32Array:return s;case Uint32Array:return Math.round(s*4294967295);case Uint16Array:return Math.round(s*65535);case Uint8Array:return Math.round(s*255);case Int32Array:return Math.round(s*2147483647);case Int16Array:return Math.round(s*32767);case Int8Array:return Math.round(s*127);default:throw new Error("Invalid component type.")}}const ip={DEG2RAD:ns,RAD2DEG:Vs,generateUUID:vn,clamp:Et,euclideanModulo:cu,mapLinear:Vg,inverseLerp:Hg,lerp:dr,damp:Gg,pingpong:Wg,smoothstep:$g,smootherstep:Xg,randInt:qg,randFloat:Yg,randFloatSpread:Zg,seededRandom:Jg,degToRad:Kg,radToDeg:jg,isPowerOfTwo:Qg,ceilPowerOfTwo:ev,floorPowerOfTwo:tv,setQuaternionFromProperEuler:nv,normalize:tt,denormalize:tn};class se{constructor(e=0,t=0){se.prototype.isVector2=!0,this.x=e,this.y=t}get width(){return this.x}set width(e){this.x=e}get height(){return this.y}set height(e){this.y=e}set(e,t){return this.x=e,this.y=t,this}setScalar(e){return this.x=e,this.y=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y)}copy(e){return this.x=e.x,this.y=e.y,this}add(e){return this.x+=e.x,this.y+=e.y,this}addScalar(e){return this.x+=e,this.y+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this}subScalar(e){return this.x-=e,this.y-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this}multiply(e){return this.x*=e.x,this.y*=e.y,this}multiplyScalar(e){return this.x*=e,this.y*=e,this}divide(e){return this.x/=e.x,this.y/=e.y,this}divideScalar(e){return this.multiplyScalar(1/e)}applyMatrix3(e){const t=this.x,n=this.y,i=e.elements;return this.x=i[0]*t+i[3]*n+i[6],this.y=i[1]*t+i[4]*n+i[7],this}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this}clamp(e,t){return this.x=Math.max(e.x,Math.min(t.x,this.x)),this.y=Math.max(e.y,Math.min(t.y,this.y)),this}clampScalar(e,t){return this.x=Math.max(e,Math.min(t,this.x)),this.y=Math.max(e,Math.min(t,this.y)),this}clampLength(e,t){const n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(e,Math.min(t,n)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this}negate(){return this.x=-this.x,this.y=-this.y,this}dot(e){return this.x*e.x+this.y*e.y}cross(e){return this.x*e.y-this.y*e.x}lengthSq(){return this.x*this.x+this.y*this.y}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)}normalize(){return this.divideScalar(this.length()||1)}angle(){return Math.atan2(-this.y,-this.x)+Math.PI}angleTo(e){const t=Math.sqrt(this.lengthSq()*e.lengthSq());if(t===0)return Math.PI/2;const n=this.dot(e)/t;return Math.acos(Et(n,-1,1))}distanceTo(e){return Math.sqrt(this.distanceToSquared(e))}distanceToSquared(e){const t=this.x-e.x,n=this.y-e.y;return t*t+n*n}manhattanDistanceTo(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this}lerpVectors(e,t,n){return this.x=e.x+(t.x-e.x)*n,this.y=e.y+(t.y-e.y)*n,this}equals(e){return e.x===this.x&&e.y===this.y}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this}rotateAround(e,t){const n=Math.cos(t),i=Math.sin(t),r=this.x-e.x,o=this.y-e.y;return this.x=r*n-o*i+e.x,this.y=r*i+o*n+e.y,this}random(){return this.x=Math.random(),this.y=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y}}class Ze{constructor(e,t,n,i,r,o,a,l,c){Ze.prototype.isMatrix3=!0,this.elements=[1,0,0,0,1,0,0,0,1],e!==void 0&&this.set(e,t,n,i,r,o,a,l,c)}set(e,t,n,i,r,o,a,l,c){const u=this.elements;return u[0]=e,u[1]=i,u[2]=a,u[3]=t,u[4]=r,u[5]=l,u[6]=n,u[7]=o,u[8]=c,this}identity(){return this.set(1,0,0,0,1,0,0,0,1),this}copy(e){const t=this.elements,n=e.elements;return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],this}extractBasis(e,t,n){return e.setFromMatrix3Column(this,0),t.setFromMatrix3Column(this,1),n.setFromMatrix3Column(this,2),this}setFromMatrix4(e){const t=e.elements;return this.set(t[0],t[4],t[8],t[1],t[5],t[9],t[2],t[6],t[10]),this}multiply(e){return this.multiplyMatrices(this,e)}premultiply(e){return this.multiplyMatrices(e,this)}multiplyMatrices(e,t){const n=e.elements,i=t.elements,r=this.elements,o=n[0],a=n[3],l=n[6],c=n[1],u=n[4],h=n[7],d=n[2],f=n[5],g=n[8],v=i[0],m=i[3],p=i[6],y=i[1],_=i[4],x=i[7],A=i[2],b=i[5],E=i[8];return r[0]=o*v+a*y+l*A,r[3]=o*m+a*_+l*b,r[6]=o*p+a*x+l*E,r[1]=c*v+u*y+h*A,r[4]=c*m+u*_+h*b,r[7]=c*p+u*x+h*E,r[2]=d*v+f*y+g*A,r[5]=d*m+f*_+g*b,r[8]=d*p+f*x+g*E,this}multiplyScalar(e){const t=this.elements;return t[0]*=e,t[3]*=e,t[6]*=e,t[1]*=e,t[4]*=e,t[7]*=e,t[2]*=e,t[5]*=e,t[8]*=e,this}determinant(){const e=this.elements,t=e[0],n=e[1],i=e[2],r=e[3],o=e[4],a=e[5],l=e[6],c=e[7],u=e[8];return t*o*u-t*a*c-n*r*u+n*a*l+i*r*c-i*o*l}invert(){const e=this.elements,t=e[0],n=e[1],i=e[2],r=e[3],o=e[4],a=e[5],l=e[6],c=e[7],u=e[8],h=u*o-a*c,d=a*l-u*r,f=c*r-o*l,g=t*h+n*d+i*f;if(g===0)return this.set(0,0,0,0,0,0,0,0,0);const v=1/g;return e[0]=h*v,e[1]=(i*c-u*n)*v,e[2]=(a*n-i*o)*v,e[3]=d*v,e[4]=(u*t-i*l)*v,e[5]=(i*r-a*t)*v,e[6]=f*v,e[7]=(n*l-c*t)*v,e[8]=(o*t-n*r)*v,this}transpose(){let e;const t=this.elements;return e=t[1],t[1]=t[3],t[3]=e,e=t[2],t[2]=t[6],t[6]=e,e=t[5],t[5]=t[7],t[7]=e,this}getNormalMatrix(e){return this.setFromMatrix4(e).invert().transpose()}transposeIntoArray(e){const t=this.elements;return e[0]=t[0],e[1]=t[3],e[2]=t[6],e[3]=t[1],e[4]=t[4],e[5]=t[7],e[6]=t[2],e[7]=t[5],e[8]=t[8],this}setUvTransform(e,t,n,i,r,o,a){const l=Math.cos(r),c=Math.sin(r);return this.set(n*l,n*c,-n*(l*o+c*a)+o+e,-i*c,i*l,-i*(-c*o+l*a)+a+t,0,0,1),this}scale(e,t){return this.premultiply(cl.makeScale(e,t)),this}rotate(e){return this.premultiply(cl.makeRotation(-e)),this}translate(e,t){return this.premultiply(cl.makeTranslation(e,t)),this}makeTranslation(e,t){return e.isVector2?this.set(1,0,e.x,0,1,e.y,0,0,1):this.set(1,0,e,0,1,t,0,0,1),this}makeRotation(e){const t=Math.cos(e),n=Math.sin(e);return this.set(t,-n,0,n,t,0,0,0,1),this}makeScale(e,t){return this.set(e,0,0,0,t,0,0,0,1),this}equals(e){const t=this.elements,n=e.elements;for(let i=0;i<9;i++)if(t[i]!==n[i])return!1;return!0}fromArray(e,t=0){for(let n=0;n<9;n++)this.elements[n]=e[n+t];return this}toArray(e=[],t=0){const n=this.elements;return e[t]=n[0],e[t+1]=n[1],e[t+2]=n[2],e[t+3]=n[3],e[t+4]=n[4],e[t+5]=n[5],e[t+6]=n[6],e[t+7]=n[7],e[t+8]=n[8],e}clone(){return new this.constructor().fromArray(this.elements)}}const cl=new Ze;function sp(s){for(let e=s.length-1;e>=0;--e)if(s[e]>=65535)return!0;return!1}const iv={Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array};function Us(s,e){return new iv[s](e)}function Ir(s){return document.createElementNS("http://www.w3.org/1999/xhtml",s)}function rp(){const s=Ir("canvas");return s.style.display="block",s}const nh={};function uu(s){s in nh||(nh[s]=!0,console.warn(s))}function sv(s,e,t){return new Promise(function(n,i){function r(){switch(s.clientWaitSync(e,s.SYNC_FLUSH_COMMANDS_BIT,0)){case s.WAIT_FAILED:i();break;case s.TIMEOUT_EXPIRED:setTimeout(r,t);break;default:n()}}setTimeout(r,t)})}const ih=new Ze().set(.8224621,.177538,0,.0331941,.9668058,0,.0170827,.0723974,.9105199),sh=new Ze().set(1.2249401,-.2249404,0,-.0420569,1.0420571,0,-.0196376,-.0786361,1.0982735),oo={[ci]:{transfer:Tr,primaries:Er,toReference:s=>s,fromReference:s=>s},[ln]:{transfer:Mt,primaries:Er,toReference:s=>s.convertSRGBToLinear(),fromReference:s=>s.convertLinearToSRGB()},[$r]:{transfer:Tr,primaries:Cr,toReference:s=>s.applyMatrix3(sh),fromReference:s=>s.applyMatrix3(ih)},[Ra]:{transfer:Mt,primaries:Cr,toReference:s=>s.convertSRGBToLinear().applyMatrix3(sh),fromReference:s=>s.applyMatrix3(ih).convertLinearToSRGB()}},rv=new Set([ci,$r]),ht={enabled:!0,_workingColorSpace:ci,get workingColorSpace(){return this._workingColorSpace},set workingColorSpace(s){if(!rv.has(s))throw new Error(`Unsupported working color space, "${s}".`);this._workingColorSpace=s},convert:function(s,e,t){if(this.enabled===!1||e===t||!e||!t)return s;const n=oo[e].toReference,i=oo[t].fromReference;return i(n(s))},fromWorkingColorSpace:function(s,e){return this.convert(s,this._workingColorSpace,e)},toWorkingColorSpace:function(s,e){return this.convert(s,e,this._workingColorSpace)},getPrimaries:function(s){return oo[s].primaries},getTransfer:function(s){return s===ti?Tr:oo[s].transfer}};function zs(s){return s<.04045?s*.0773993808:Math.pow(s*.9478672986+.0521327014,2.4)}function ul(s){return s<.0031308?s*12.92:1.055*Math.pow(s,.41666)-.055}let ds;class op{static getDataURL(e){if(/^data:/i.test(e.src)||typeof HTMLCanvasElement>"u")return e.src;let t;if(e instanceof HTMLCanvasElement)t=e;else{ds===void 0&&(ds=Ir("canvas")),ds.width=e.width,ds.height=e.height;const n=ds.getContext("2d");e instanceof ImageData?n.putImageData(e,0,0):n.drawImage(e,0,0,e.width,e.height),t=ds}return t.width>2048||t.height>2048?(console.warn("THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons",e),t.toDataURL("image/jpeg",.6)):t.toDataURL("image/png")}static sRGBToLinear(e){if(typeof HTMLImageElement<"u"&&e instanceof HTMLImageElement||typeof HTMLCanvasElement<"u"&&e instanceof HTMLCanvasElement||typeof ImageBitmap<"u"&&e instanceof ImageBitmap){const t=Ir("canvas");t.width=e.width,t.height=e.height;const n=t.getContext("2d");n.drawImage(e,0,0,e.width,e.height);const i=n.getImageData(0,0,e.width,e.height),r=i.data;for(let o=0;o0&&(n.userData=this.userData),t||(e.textures[this.uuid]=n),n}dispose(){this.dispatchEvent({type:"dispose"})}transformUv(e){if(this.mapping!==Ca)return e;if(e.applyMatrix3(this.matrix),e.x<0||e.x>1)switch(this.wrapS){case Mr:e.x=e.x-Math.floor(e.x);break;case Mn:e.x=e.x<0?0:1;break;case br:Math.abs(Math.floor(e.x)%2)===1?e.x=Math.ceil(e.x)-e.x:e.x=e.x-Math.floor(e.x);break}if(e.y<0||e.y>1)switch(this.wrapT){case Mr:e.y=e.y-Math.floor(e.y);break;case Mn:e.y=e.y<0?0:1;break;case br:Math.abs(Math.floor(e.y)%2)===1?e.y=Math.ceil(e.y)-e.y:e.y=e.y-Math.floor(e.y);break}return this.flipY&&(e.y=1-e.y),e}set needsUpdate(e){e===!0&&(this.version++,this.source.needsUpdate=!0)}set needsPMREMUpdate(e){e===!0&&this.pmremVersion++}}Pt.DEFAULT_IMAGE=null;Pt.DEFAULT_MAPPING=Ca;Pt.DEFAULT_ANISOTROPY=1;class gt{constructor(e=0,t=0,n=0,i=1){gt.prototype.isVector4=!0,this.x=e,this.y=t,this.z=n,this.w=i}get width(){return this.z}set width(e){this.z=e}get height(){return this.w}set height(e){this.w=e}set(e,t,n,i){return this.x=e,this.y=t,this.z=n,this.w=i,this}setScalar(e){return this.x=e,this.y=e,this.z=e,this.w=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setZ(e){return this.z=e,this}setW(e){return this.w=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;case 3:this.w=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y,this.z,this.w)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this.w=e.w!==void 0?e.w:1,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this.w+=e.w,this}addScalar(e){return this.x+=e,this.y+=e,this.z+=e,this.w+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this.w=e.w+t.w,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this.w+=e.w*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this.w-=e.w,this}subScalar(e){return this.x-=e,this.y-=e,this.z-=e,this.w-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this.w=e.w-t.w,this}multiply(e){return this.x*=e.x,this.y*=e.y,this.z*=e.z,this.w*=e.w,this}multiplyScalar(e){return this.x*=e,this.y*=e,this.z*=e,this.w*=e,this}applyMatrix4(e){const t=this.x,n=this.y,i=this.z,r=this.w,o=e.elements;return this.x=o[0]*t+o[4]*n+o[8]*i+o[12]*r,this.y=o[1]*t+o[5]*n+o[9]*i+o[13]*r,this.z=o[2]*t+o[6]*n+o[10]*i+o[14]*r,this.w=o[3]*t+o[7]*n+o[11]*i+o[15]*r,this}divideScalar(e){return this.multiplyScalar(1/e)}setAxisAngleFromQuaternion(e){this.w=2*Math.acos(e.w);const t=Math.sqrt(1-e.w*e.w);return t<1e-4?(this.x=1,this.y=0,this.z=0):(this.x=e.x/t,this.y=e.y/t,this.z=e.z/t),this}setAxisAngleFromRotationMatrix(e){let t,n,i,r;const l=e.elements,c=l[0],u=l[4],h=l[8],d=l[1],f=l[5],g=l[9],v=l[2],m=l[6],p=l[10];if(Math.abs(u-d)<.01&&Math.abs(h-v)<.01&&Math.abs(g-m)<.01){if(Math.abs(u+d)<.1&&Math.abs(h+v)<.1&&Math.abs(g+m)<.1&&Math.abs(c+f+p-3)<.1)return this.set(1,0,0,0),this;t=Math.PI;const _=(c+1)/2,x=(f+1)/2,A=(p+1)/2,b=(u+d)/4,E=(h+v)/4,I=(g+m)/4;return _>x&&_>A?_<.01?(n=0,i=.707106781,r=.707106781):(n=Math.sqrt(_),i=b/n,r=E/n):x>A?x<.01?(n=.707106781,i=0,r=.707106781):(i=Math.sqrt(x),n=b/i,r=I/i):A<.01?(n=.707106781,i=.707106781,r=0):(r=Math.sqrt(A),n=E/r,i=I/r),this.set(n,i,r,t),this}let y=Math.sqrt((m-g)*(m-g)+(h-v)*(h-v)+(d-u)*(d-u));return Math.abs(y)<.001&&(y=1),this.x=(m-g)/y,this.y=(h-v)/y,this.z=(d-u)/y,this.w=Math.acos((c+f+p-1)/2),this}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this.z=Math.min(this.z,e.z),this.w=Math.min(this.w,e.w),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this.z=Math.max(this.z,e.z),this.w=Math.max(this.w,e.w),this}clamp(e,t){return this.x=Math.max(e.x,Math.min(t.x,this.x)),this.y=Math.max(e.y,Math.min(t.y,this.y)),this.z=Math.max(e.z,Math.min(t.z,this.z)),this.w=Math.max(e.w,Math.min(t.w,this.w)),this}clampScalar(e,t){return this.x=Math.max(e,Math.min(t,this.x)),this.y=Math.max(e,Math.min(t,this.y)),this.z=Math.max(e,Math.min(t,this.z)),this.w=Math.max(e,Math.min(t,this.w)),this}clampLength(e,t){const n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(e,Math.min(t,n)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this.w=Math.floor(this.w),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this.w=Math.ceil(this.w),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this.w=Math.round(this.w),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this.w=Math.trunc(this.w),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this.w=-this.w,this}dot(e){return this.x*e.x+this.y*e.y+this.z*e.z+this.w*e.w}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)}normalize(){return this.divideScalar(this.length()||1)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this.z+=(e.z-this.z)*t,this.w+=(e.w-this.w)*t,this}lerpVectors(e,t,n){return this.x=e.x+(t.x-e.x)*n,this.y=e.y+(t.y-e.y)*n,this.z=e.z+(t.z-e.z)*n,this.w=e.w+(t.w-e.w)*n,this}equals(e){return e.x===this.x&&e.y===this.y&&e.z===this.z&&e.w===this.w}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this.z=e[t+2],this.w=e[t+3],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e[t+2]=this.z,e[t+3]=this.w,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this.z=e.getZ(t),this.w=e.getW(t),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this.w=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z,yield this.w}}class ap extends ui{constructor(e=1,t=1,n={}){super(),this.isRenderTarget=!0,this.width=e,this.height=t,this.depth=1,this.scissor=new gt(0,0,e,t),this.scissorTest=!1,this.viewport=new gt(0,0,e,t);const i={width:e,height:t,depth:1};n=Object.assign({generateMipmaps:!1,internalFormat:null,minFilter:Ot,depthBuffer:!0,stencilBuffer:!1,resolveDepthBuffer:!0,resolveStencilBuffer:!0,depthTexture:null,samples:0,count:1},n);const r=new Pt(i,n.mapping,n.wrapS,n.wrapT,n.magFilter,n.minFilter,n.format,n.type,n.anisotropy,n.colorSpace);r.flipY=!1,r.generateMipmaps=n.generateMipmaps,r.internalFormat=n.internalFormat,this.textures=[];const o=n.count;for(let a=0;a=0?1:-1,_=1-p*p;if(_>Number.EPSILON){const A=Math.sqrt(_),b=Math.atan2(A,p*y);m=Math.sin(m*b)/A,a=Math.sin(a*b)/A}const x=a*y;if(l=l*m+d*x,c=c*m+f*x,u=u*m+g*x,h=h*m+v*x,m===1-a){const A=1/Math.sqrt(l*l+c*c+u*u+h*h);l*=A,c*=A,u*=A,h*=A}}e[t]=l,e[t+1]=c,e[t+2]=u,e[t+3]=h}static multiplyQuaternionsFlat(e,t,n,i,r,o){const a=n[i],l=n[i+1],c=n[i+2],u=n[i+3],h=r[o],d=r[o+1],f=r[o+2],g=r[o+3];return e[t]=a*g+u*h+l*f-c*d,e[t+1]=l*g+u*d+c*h-a*f,e[t+2]=c*g+u*f+a*d-l*h,e[t+3]=u*g-a*h-l*d-c*f,e}get x(){return this._x}set x(e){this._x=e,this._onChangeCallback()}get y(){return this._y}set y(e){this._y=e,this._onChangeCallback()}get z(){return this._z}set z(e){this._z=e,this._onChangeCallback()}get w(){return this._w}set w(e){this._w=e,this._onChangeCallback()}set(e,t,n,i){return this._x=e,this._y=t,this._z=n,this._w=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._w)}copy(e){return this._x=e.x,this._y=e.y,this._z=e.z,this._w=e.w,this._onChangeCallback(),this}setFromEuler(e,t=!0){const n=e._x,i=e._y,r=e._z,o=e._order,a=Math.cos,l=Math.sin,c=a(n/2),u=a(i/2),h=a(r/2),d=l(n/2),f=l(i/2),g=l(r/2);switch(o){case"XYZ":this._x=d*u*h+c*f*g,this._y=c*f*h-d*u*g,this._z=c*u*g+d*f*h,this._w=c*u*h-d*f*g;break;case"YXZ":this._x=d*u*h+c*f*g,this._y=c*f*h-d*u*g,this._z=c*u*g-d*f*h,this._w=c*u*h+d*f*g;break;case"ZXY":this._x=d*u*h-c*f*g,this._y=c*f*h+d*u*g,this._z=c*u*g+d*f*h,this._w=c*u*h-d*f*g;break;case"ZYX":this._x=d*u*h-c*f*g,this._y=c*f*h+d*u*g,this._z=c*u*g-d*f*h,this._w=c*u*h+d*f*g;break;case"YZX":this._x=d*u*h+c*f*g,this._y=c*f*h+d*u*g,this._z=c*u*g-d*f*h,this._w=c*u*h-d*f*g;break;case"XZY":this._x=d*u*h-c*f*g,this._y=c*f*h-d*u*g,this._z=c*u*g+d*f*h,this._w=c*u*h+d*f*g;break;default:console.warn("THREE.Quaternion: .setFromEuler() encountered an unknown order: "+o)}return t===!0&&this._onChangeCallback(),this}setFromAxisAngle(e,t){const n=t/2,i=Math.sin(n);return this._x=e.x*i,this._y=e.y*i,this._z=e.z*i,this._w=Math.cos(n),this._onChangeCallback(),this}setFromRotationMatrix(e){const t=e.elements,n=t[0],i=t[4],r=t[8],o=t[1],a=t[5],l=t[9],c=t[2],u=t[6],h=t[10],d=n+a+h;if(d>0){const f=.5/Math.sqrt(d+1);this._w=.25/f,this._x=(u-l)*f,this._y=(r-c)*f,this._z=(o-i)*f}else if(n>a&&n>h){const f=2*Math.sqrt(1+n-a-h);this._w=(u-l)/f,this._x=.25*f,this._y=(i+o)/f,this._z=(r+c)/f}else if(a>h){const f=2*Math.sqrt(1+a-n-h);this._w=(r-c)/f,this._x=(i+o)/f,this._y=.25*f,this._z=(l+u)/f}else{const f=2*Math.sqrt(1+h-n-a);this._w=(o-i)/f,this._x=(r+c)/f,this._y=(l+u)/f,this._z=.25*f}return this._onChangeCallback(),this}setFromUnitVectors(e,t){let n=e.dot(t)+1;return nMath.abs(e.z)?(this._x=-e.y,this._y=e.x,this._z=0,this._w=n):(this._x=0,this._y=-e.z,this._z=e.y,this._w=n)):(this._x=e.y*t.z-e.z*t.y,this._y=e.z*t.x-e.x*t.z,this._z=e.x*t.y-e.y*t.x,this._w=n),this.normalize()}angleTo(e){return 2*Math.acos(Math.abs(Et(this.dot(e),-1,1)))}rotateTowards(e,t){const n=this.angleTo(e);if(n===0)return this;const i=Math.min(1,t/n);return this.slerp(e,i),this}identity(){return this.set(0,0,0,1)}invert(){return this.conjugate()}conjugate(){return this._x*=-1,this._y*=-1,this._z*=-1,this._onChangeCallback(),this}dot(e){return this._x*e._x+this._y*e._y+this._z*e._z+this._w*e._w}lengthSq(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w}length(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)}normalize(){let e=this.length();return e===0?(this._x=0,this._y=0,this._z=0,this._w=1):(e=1/e,this._x=this._x*e,this._y=this._y*e,this._z=this._z*e,this._w=this._w*e),this._onChangeCallback(),this}multiply(e){return this.multiplyQuaternions(this,e)}premultiply(e){return this.multiplyQuaternions(e,this)}multiplyQuaternions(e,t){const n=e._x,i=e._y,r=e._z,o=e._w,a=t._x,l=t._y,c=t._z,u=t._w;return this._x=n*u+o*a+i*c-r*l,this._y=i*u+o*l+r*a-n*c,this._z=r*u+o*c+n*l-i*a,this._w=o*u-n*a-i*l-r*c,this._onChangeCallback(),this}slerp(e,t){if(t===0)return this;if(t===1)return this.copy(e);const n=this._x,i=this._y,r=this._z,o=this._w;let a=o*e._w+n*e._x+i*e._y+r*e._z;if(a<0?(this._w=-e._w,this._x=-e._x,this._y=-e._y,this._z=-e._z,a=-a):this.copy(e),a>=1)return this._w=o,this._x=n,this._y=i,this._z=r,this;const l=1-a*a;if(l<=Number.EPSILON){const f=1-t;return this._w=f*o+t*this._w,this._x=f*n+t*this._x,this._y=f*i+t*this._y,this._z=f*r+t*this._z,this.normalize(),this}const c=Math.sqrt(l),u=Math.atan2(c,a),h=Math.sin((1-t)*u)/c,d=Math.sin(t*u)/c;return this._w=o*h+this._w*d,this._x=n*h+this._x*d,this._y=i*h+this._y*d,this._z=r*h+this._z*d,this._onChangeCallback(),this}slerpQuaternions(e,t,n){return this.copy(e).slerp(t,n)}random(){const e=2*Math.PI*Math.random(),t=2*Math.PI*Math.random(),n=Math.random(),i=Math.sqrt(1-n),r=Math.sqrt(n);return this.set(i*Math.sin(e),i*Math.cos(e),r*Math.sin(t),r*Math.cos(t))}equals(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._w===this._w}fromArray(e,t=0){return this._x=e[t],this._y=e[t+1],this._z=e[t+2],this._w=e[t+3],this._onChangeCallback(),this}toArray(e=[],t=0){return e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._w,e}fromBufferAttribute(e,t){return this._x=e.getX(t),this._y=e.getY(t),this._z=e.getZ(t),this._w=e.getW(t),this._onChangeCallback(),this}toJSON(){return this.toArray()}_onChange(e){return this._onChangeCallback=e,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._w}}class N{constructor(e=0,t=0,n=0){N.prototype.isVector3=!0,this.x=e,this.y=t,this.z=n}set(e,t,n){return n===void 0&&(n=this.z),this.x=e,this.y=t,this.z=n,this}setScalar(e){return this.x=e,this.y=e,this.z=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setZ(e){return this.z=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y,this.z)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this}addScalar(e){return this.x+=e,this.y+=e,this.z+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this}subScalar(e){return this.x-=e,this.y-=e,this.z-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this}multiply(e){return this.x*=e.x,this.y*=e.y,this.z*=e.z,this}multiplyScalar(e){return this.x*=e,this.y*=e,this.z*=e,this}multiplyVectors(e,t){return this.x=e.x*t.x,this.y=e.y*t.y,this.z=e.z*t.z,this}applyEuler(e){return this.applyQuaternion(rh.setFromEuler(e))}applyAxisAngle(e,t){return this.applyQuaternion(rh.setFromAxisAngle(e,t))}applyMatrix3(e){const t=this.x,n=this.y,i=this.z,r=e.elements;return this.x=r[0]*t+r[3]*n+r[6]*i,this.y=r[1]*t+r[4]*n+r[7]*i,this.z=r[2]*t+r[5]*n+r[8]*i,this}applyNormalMatrix(e){return this.applyMatrix3(e).normalize()}applyMatrix4(e){const t=this.x,n=this.y,i=this.z,r=e.elements,o=1/(r[3]*t+r[7]*n+r[11]*i+r[15]);return this.x=(r[0]*t+r[4]*n+r[8]*i+r[12])*o,this.y=(r[1]*t+r[5]*n+r[9]*i+r[13])*o,this.z=(r[2]*t+r[6]*n+r[10]*i+r[14])*o,this}applyQuaternion(e){const t=this.x,n=this.y,i=this.z,r=e.x,o=e.y,a=e.z,l=e.w,c=2*(o*i-a*n),u=2*(a*t-r*i),h=2*(r*n-o*t);return this.x=t+l*c+o*h-a*u,this.y=n+l*u+a*c-r*h,this.z=i+l*h+r*u-o*c,this}project(e){return this.applyMatrix4(e.matrixWorldInverse).applyMatrix4(e.projectionMatrix)}unproject(e){return this.applyMatrix4(e.projectionMatrixInverse).applyMatrix4(e.matrixWorld)}transformDirection(e){const t=this.x,n=this.y,i=this.z,r=e.elements;return this.x=r[0]*t+r[4]*n+r[8]*i,this.y=r[1]*t+r[5]*n+r[9]*i,this.z=r[2]*t+r[6]*n+r[10]*i,this.normalize()}divide(e){return this.x/=e.x,this.y/=e.y,this.z/=e.z,this}divideScalar(e){return this.multiplyScalar(1/e)}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this.z=Math.min(this.z,e.z),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this.z=Math.max(this.z,e.z),this}clamp(e,t){return this.x=Math.max(e.x,Math.min(t.x,this.x)),this.y=Math.max(e.y,Math.min(t.y,this.y)),this.z=Math.max(e.z,Math.min(t.z,this.z)),this}clampScalar(e,t){return this.x=Math.max(e,Math.min(t,this.x)),this.y=Math.max(e,Math.min(t,this.y)),this.z=Math.max(e,Math.min(t,this.z)),this}clampLength(e,t){const n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(e,Math.min(t,n)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this}dot(e){return this.x*e.x+this.y*e.y+this.z*e.z}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)}normalize(){return this.divideScalar(this.length()||1)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this.z+=(e.z-this.z)*t,this}lerpVectors(e,t,n){return this.x=e.x+(t.x-e.x)*n,this.y=e.y+(t.y-e.y)*n,this.z=e.z+(t.z-e.z)*n,this}cross(e){return this.crossVectors(this,e)}crossVectors(e,t){const n=e.x,i=e.y,r=e.z,o=t.x,a=t.y,l=t.z;return this.x=i*l-r*a,this.y=r*o-n*l,this.z=n*a-i*o,this}projectOnVector(e){const t=e.lengthSq();if(t===0)return this.set(0,0,0);const n=e.dot(this)/t;return this.copy(e).multiplyScalar(n)}projectOnPlane(e){return dl.copy(this).projectOnVector(e),this.sub(dl)}reflect(e){return this.sub(dl.copy(e).multiplyScalar(2*this.dot(e)))}angleTo(e){const t=Math.sqrt(this.lengthSq()*e.lengthSq());if(t===0)return Math.PI/2;const n=this.dot(e)/t;return Math.acos(Et(n,-1,1))}distanceTo(e){return Math.sqrt(this.distanceToSquared(e))}distanceToSquared(e){const t=this.x-e.x,n=this.y-e.y,i=this.z-e.z;return t*t+n*n+i*i}manhattanDistanceTo(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)+Math.abs(this.z-e.z)}setFromSpherical(e){return this.setFromSphericalCoords(e.radius,e.phi,e.theta)}setFromSphericalCoords(e,t,n){const i=Math.sin(t)*e;return this.x=i*Math.sin(n),this.y=Math.cos(t)*e,this.z=i*Math.cos(n),this}setFromCylindrical(e){return this.setFromCylindricalCoords(e.radius,e.theta,e.y)}setFromCylindricalCoords(e,t,n){return this.x=e*Math.sin(t),this.y=n,this.z=e*Math.cos(t),this}setFromMatrixPosition(e){const t=e.elements;return this.x=t[12],this.y=t[13],this.z=t[14],this}setFromMatrixScale(e){const t=this.setFromMatrixColumn(e,0).length(),n=this.setFromMatrixColumn(e,1).length(),i=this.setFromMatrixColumn(e,2).length();return this.x=t,this.y=n,this.z=i,this}setFromMatrixColumn(e,t){return this.fromArray(e.elements,t*4)}setFromMatrix3Column(e,t){return this.fromArray(e.elements,t*3)}setFromEuler(e){return this.x=e._x,this.y=e._y,this.z=e._z,this}setFromColor(e){return this.x=e.r,this.y=e.g,this.z=e.b,this}equals(e){return e.x===this.x&&e.y===this.y&&e.z===this.z}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this.z=e[t+2],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e[t+2]=this.z,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this.z=e.getZ(t),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this}randomDirection(){const e=Math.random()*Math.PI*2,t=Math.random()*2-1,n=Math.sqrt(1-t*t);return this.x=n*Math.cos(e),this.y=t,this.z=n*Math.sin(e),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z}}const dl=new N,rh=new hn;class sn{constructor(e=new N(1/0,1/0,1/0),t=new N(-1/0,-1/0,-1/0)){this.isBox3=!0,this.min=e,this.max=t}set(e,t){return this.min.copy(e),this.max.copy(t),this}setFromArray(e){this.makeEmpty();for(let t=0,n=e.length;tthis.max.x||e.ythis.max.y||e.zthis.max.z)}containsBox(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y&&this.min.z<=e.min.z&&e.max.z<=this.max.z}getParameter(e,t){return t.set((e.x-this.min.x)/(this.max.x-this.min.x),(e.y-this.min.y)/(this.max.y-this.min.y),(e.z-this.min.z)/(this.max.z-this.min.z))}intersectsBox(e){return!(e.max.xthis.max.x||e.max.ythis.max.y||e.max.zthis.max.z)}intersectsSphere(e){return this.clampPoint(e.center,bn),bn.distanceToSquared(e.center)<=e.radius*e.radius}intersectsPlane(e){let t,n;return e.normal.x>0?(t=e.normal.x*this.min.x,n=e.normal.x*this.max.x):(t=e.normal.x*this.max.x,n=e.normal.x*this.min.x),e.normal.y>0?(t+=e.normal.y*this.min.y,n+=e.normal.y*this.max.y):(t+=e.normal.y*this.max.y,n+=e.normal.y*this.min.y),e.normal.z>0?(t+=e.normal.z*this.min.z,n+=e.normal.z*this.max.z):(t+=e.normal.z*this.max.z,n+=e.normal.z*this.min.z),t<=-e.constant&&n>=-e.constant}intersectsTriangle(e){if(this.isEmpty())return!1;this.getCenter(Zs),lo.subVectors(this.max,Zs),fs.subVectors(e.a,Zs),ps.subVectors(e.b,Zs),ms.subVectors(e.c,Zs),mi.subVectors(ps,fs),gi.subVectors(ms,ps),Oi.subVectors(fs,ms);let t=[0,-mi.z,mi.y,0,-gi.z,gi.y,0,-Oi.z,Oi.y,mi.z,0,-mi.x,gi.z,0,-gi.x,Oi.z,0,-Oi.x,-mi.y,mi.x,0,-gi.y,gi.x,0,-Oi.y,Oi.x,0];return!fl(t,fs,ps,ms,lo)||(t=[1,0,0,0,1,0,0,0,1],!fl(t,fs,ps,ms,lo))?!1:(co.crossVectors(mi,gi),t=[co.x,co.y,co.z],fl(t,fs,ps,ms,lo))}clampPoint(e,t){return t.copy(e).clamp(this.min,this.max)}distanceToPoint(e){return this.clampPoint(e,bn).distanceTo(e)}getBoundingSphere(e){return this.isEmpty()?e.makeEmpty():(this.getCenter(e.center),e.radius=this.getSize(bn).length()*.5),e}intersect(e){return this.min.max(e.min),this.max.min(e.max),this.isEmpty()&&this.makeEmpty(),this}union(e){return this.min.min(e.min),this.max.max(e.max),this}applyMatrix4(e){return this.isEmpty()?this:(Zn[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(e),Zn[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(e),Zn[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(e),Zn[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(e),Zn[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(e),Zn[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(e),Zn[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(e),Zn[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(e),this.setFromPoints(Zn),this)}translate(e){return this.min.add(e),this.max.add(e),this}equals(e){return e.min.equals(this.min)&&e.max.equals(this.max)}}const Zn=[new N,new N,new N,new N,new N,new N,new N,new N],bn=new N,ao=new sn,fs=new N,ps=new N,ms=new N,mi=new N,gi=new N,Oi=new N,Zs=new N,lo=new N,co=new N,Fi=new N;function fl(s,e,t,n,i){for(let r=0,o=s.length-3;r<=o;r+=3){Fi.fromArray(s,r);const a=i.x*Math.abs(Fi.x)+i.y*Math.abs(Fi.y)+i.z*Math.abs(Fi.z),l=e.dot(Fi),c=t.dot(Fi),u=n.dot(Fi);if(Math.max(-Math.max(l,c,u),Math.min(l,c,u))>a)return!1}return!0}const uv=new sn,Js=new N,pl=new N;class Zt{constructor(e=new N,t=-1){this.isSphere=!0,this.center=e,this.radius=t}set(e,t){return this.center.copy(e),this.radius=t,this}setFromPoints(e,t){const n=this.center;t!==void 0?n.copy(t):uv.setFromPoints(e).getCenter(n);let i=0;for(let r=0,o=e.length;rthis.radius*this.radius&&(t.sub(this.center).normalize(),t.multiplyScalar(this.radius).add(this.center)),t}getBoundingBox(e){return this.isEmpty()?(e.makeEmpty(),e):(e.set(this.center,this.center),e.expandByScalar(this.radius),e)}applyMatrix4(e){return this.center.applyMatrix4(e),this.radius=this.radius*e.getMaxScaleOnAxis(),this}translate(e){return this.center.add(e),this}expandByPoint(e){if(this.isEmpty())return this.center.copy(e),this.radius=0,this;Js.subVectors(e,this.center);const t=Js.lengthSq();if(t>this.radius*this.radius){const n=Math.sqrt(t),i=(n-this.radius)*.5;this.center.addScaledVector(Js,i/n),this.radius+=i}return this}union(e){return e.isEmpty()?this:this.isEmpty()?(this.copy(e),this):(this.center.equals(e.center)===!0?this.radius=Math.max(this.radius,e.radius):(pl.subVectors(e.center,this.center).setLength(e.radius),this.expandByPoint(Js.copy(e.center).add(pl)),this.expandByPoint(Js.copy(e.center).sub(pl))),this)}equals(e){return e.center.equals(this.center)&&e.radius===this.radius}clone(){return new this.constructor().copy(this)}}const Jn=new N,ml=new N,uo=new N,vi=new N,gl=new N,ho=new N,vl=new N;class $s{constructor(e=new N,t=new N(0,0,-1)){this.origin=e,this.direction=t}set(e,t){return this.origin.copy(e),this.direction.copy(t),this}copy(e){return this.origin.copy(e.origin),this.direction.copy(e.direction),this}at(e,t){return t.copy(this.origin).addScaledVector(this.direction,e)}lookAt(e){return this.direction.copy(e).sub(this.origin).normalize(),this}recast(e){return this.origin.copy(this.at(e,Jn)),this}closestPointToPoint(e,t){t.subVectors(e,this.origin);const n=t.dot(this.direction);return n<0?t.copy(this.origin):t.copy(this.origin).addScaledVector(this.direction,n)}distanceToPoint(e){return Math.sqrt(this.distanceSqToPoint(e))}distanceSqToPoint(e){const t=Jn.subVectors(e,this.origin).dot(this.direction);return t<0?this.origin.distanceToSquared(e):(Jn.copy(this.origin).addScaledVector(this.direction,t),Jn.distanceToSquared(e))}distanceSqToSegment(e,t,n,i){ml.copy(e).add(t).multiplyScalar(.5),uo.copy(t).sub(e).normalize(),vi.copy(this.origin).sub(ml);const r=e.distanceTo(t)*.5,o=-this.direction.dot(uo),a=vi.dot(this.direction),l=-vi.dot(uo),c=vi.lengthSq(),u=Math.abs(1-o*o);let h,d,f,g;if(u>0)if(h=o*l-a,d=o*a-l,g=r*u,h>=0)if(d>=-g)if(d<=g){const v=1/u;h*=v,d*=v,f=h*(h+o*d+2*a)+d*(o*h+d+2*l)+c}else d=r,h=Math.max(0,-(o*d+a)),f=-h*h+d*(d+2*l)+c;else d=-r,h=Math.max(0,-(o*d+a)),f=-h*h+d*(d+2*l)+c;else d<=-g?(h=Math.max(0,-(-o*r+a)),d=h>0?-r:Math.min(Math.max(-r,-l),r),f=-h*h+d*(d+2*l)+c):d<=g?(h=0,d=Math.min(Math.max(-r,-l),r),f=d*(d+2*l)+c):(h=Math.max(0,-(o*r+a)),d=h>0?r:Math.min(Math.max(-r,-l),r),f=-h*h+d*(d+2*l)+c);else d=o>0?-r:r,h=Math.max(0,-(o*d+a)),f=-h*h+d*(d+2*l)+c;return n&&n.copy(this.origin).addScaledVector(this.direction,h),i&&i.copy(ml).addScaledVector(uo,d),f}intersectSphere(e,t){Jn.subVectors(e.center,this.origin);const n=Jn.dot(this.direction),i=Jn.dot(Jn)-n*n,r=e.radius*e.radius;if(i>r)return null;const o=Math.sqrt(r-i),a=n-o,l=n+o;return l<0?null:a<0?this.at(l,t):this.at(a,t)}intersectsSphere(e){return this.distanceSqToPoint(e.center)<=e.radius*e.radius}distanceToPlane(e){const t=e.normal.dot(this.direction);if(t===0)return e.distanceToPoint(this.origin)===0?0:null;const n=-(this.origin.dot(e.normal)+e.constant)/t;return n>=0?n:null}intersectPlane(e,t){const n=this.distanceToPlane(e);return n===null?null:this.at(n,t)}intersectsPlane(e){const t=e.distanceToPoint(this.origin);return t===0||e.normal.dot(this.direction)*t<0}intersectBox(e,t){let n,i,r,o,a,l;const c=1/this.direction.x,u=1/this.direction.y,h=1/this.direction.z,d=this.origin;return c>=0?(n=(e.min.x-d.x)*c,i=(e.max.x-d.x)*c):(n=(e.max.x-d.x)*c,i=(e.min.x-d.x)*c),u>=0?(r=(e.min.y-d.y)*u,o=(e.max.y-d.y)*u):(r=(e.max.y-d.y)*u,o=(e.min.y-d.y)*u),n>o||r>i||((r>n||isNaN(n))&&(n=r),(o=0?(a=(e.min.z-d.z)*h,l=(e.max.z-d.z)*h):(a=(e.max.z-d.z)*h,l=(e.min.z-d.z)*h),n>l||a>i)||((a>n||n!==n)&&(n=a),(l=0?n:i,t)}intersectsBox(e){return this.intersectBox(e,Jn)!==null}intersectTriangle(e,t,n,i,r){gl.subVectors(t,e),ho.subVectors(n,e),vl.crossVectors(gl,ho);let o=this.direction.dot(vl),a;if(o>0){if(i)return null;a=1}else if(o<0)a=-1,o=-o;else return null;vi.subVectors(this.origin,e);const l=a*this.direction.dot(ho.crossVectors(vi,ho));if(l<0)return null;const c=a*this.direction.dot(gl.cross(vi));if(c<0||l+c>o)return null;const u=-a*vi.dot(vl);return u<0?null:this.at(u/o,r)}applyMatrix4(e){return this.origin.applyMatrix4(e),this.direction.transformDirection(e),this}equals(e){return e.origin.equals(this.origin)&&e.direction.equals(this.direction)}clone(){return new this.constructor().copy(this)}}class qe{constructor(e,t,n,i,r,o,a,l,c,u,h,d,f,g,v,m){qe.prototype.isMatrix4=!0,this.elements=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],e!==void 0&&this.set(e,t,n,i,r,o,a,l,c,u,h,d,f,g,v,m)}set(e,t,n,i,r,o,a,l,c,u,h,d,f,g,v,m){const p=this.elements;return p[0]=e,p[4]=t,p[8]=n,p[12]=i,p[1]=r,p[5]=o,p[9]=a,p[13]=l,p[2]=c,p[6]=u,p[10]=h,p[14]=d,p[3]=f,p[7]=g,p[11]=v,p[15]=m,this}identity(){return this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1),this}clone(){return new qe().fromArray(this.elements)}copy(e){const t=this.elements,n=e.elements;return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],this}copyPosition(e){const t=this.elements,n=e.elements;return t[12]=n[12],t[13]=n[13],t[14]=n[14],this}setFromMatrix3(e){const t=e.elements;return this.set(t[0],t[3],t[6],0,t[1],t[4],t[7],0,t[2],t[5],t[8],0,0,0,0,1),this}extractBasis(e,t,n){return e.setFromMatrixColumn(this,0),t.setFromMatrixColumn(this,1),n.setFromMatrixColumn(this,2),this}makeBasis(e,t,n){return this.set(e.x,t.x,n.x,0,e.y,t.y,n.y,0,e.z,t.z,n.z,0,0,0,0,1),this}extractRotation(e){const t=this.elements,n=e.elements,i=1/gs.setFromMatrixColumn(e,0).length(),r=1/gs.setFromMatrixColumn(e,1).length(),o=1/gs.setFromMatrixColumn(e,2).length();return t[0]=n[0]*i,t[1]=n[1]*i,t[2]=n[2]*i,t[3]=0,t[4]=n[4]*r,t[5]=n[5]*r,t[6]=n[6]*r,t[7]=0,t[8]=n[8]*o,t[9]=n[9]*o,t[10]=n[10]*o,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this}makeRotationFromEuler(e){const t=this.elements,n=e.x,i=e.y,r=e.z,o=Math.cos(n),a=Math.sin(n),l=Math.cos(i),c=Math.sin(i),u=Math.cos(r),h=Math.sin(r);if(e.order==="XYZ"){const d=o*u,f=o*h,g=a*u,v=a*h;t[0]=l*u,t[4]=-l*h,t[8]=c,t[1]=f+g*c,t[5]=d-v*c,t[9]=-a*l,t[2]=v-d*c,t[6]=g+f*c,t[10]=o*l}else if(e.order==="YXZ"){const d=l*u,f=l*h,g=c*u,v=c*h;t[0]=d+v*a,t[4]=g*a-f,t[8]=o*c,t[1]=o*h,t[5]=o*u,t[9]=-a,t[2]=f*a-g,t[6]=v+d*a,t[10]=o*l}else if(e.order==="ZXY"){const d=l*u,f=l*h,g=c*u,v=c*h;t[0]=d-v*a,t[4]=-o*h,t[8]=g+f*a,t[1]=f+g*a,t[5]=o*u,t[9]=v-d*a,t[2]=-o*c,t[6]=a,t[10]=o*l}else if(e.order==="ZYX"){const d=o*u,f=o*h,g=a*u,v=a*h;t[0]=l*u,t[4]=g*c-f,t[8]=d*c+v,t[1]=l*h,t[5]=v*c+d,t[9]=f*c-g,t[2]=-c,t[6]=a*l,t[10]=o*l}else if(e.order==="YZX"){const d=o*l,f=o*c,g=a*l,v=a*c;t[0]=l*u,t[4]=v-d*h,t[8]=g*h+f,t[1]=h,t[5]=o*u,t[9]=-a*u,t[2]=-c*u,t[6]=f*h+g,t[10]=d-v*h}else if(e.order==="XZY"){const d=o*l,f=o*c,g=a*l,v=a*c;t[0]=l*u,t[4]=-h,t[8]=c*u,t[1]=d*h+v,t[5]=o*u,t[9]=f*h-g,t[2]=g*h-f,t[6]=a*u,t[10]=v*h+d}return t[3]=0,t[7]=0,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this}makeRotationFromQuaternion(e){return this.compose(hv,e,dv)}lookAt(e,t,n){const i=this.elements;return fn.subVectors(e,t),fn.lengthSq()===0&&(fn.z=1),fn.normalize(),_i.crossVectors(n,fn),_i.lengthSq()===0&&(Math.abs(n.z)===1?fn.x+=1e-4:fn.z+=1e-4,fn.normalize(),_i.crossVectors(n,fn)),_i.normalize(),fo.crossVectors(fn,_i),i[0]=_i.x,i[4]=fo.x,i[8]=fn.x,i[1]=_i.y,i[5]=fo.y,i[9]=fn.y,i[2]=_i.z,i[6]=fo.z,i[10]=fn.z,this}multiply(e){return this.multiplyMatrices(this,e)}premultiply(e){return this.multiplyMatrices(e,this)}multiplyMatrices(e,t){const n=e.elements,i=t.elements,r=this.elements,o=n[0],a=n[4],l=n[8],c=n[12],u=n[1],h=n[5],d=n[9],f=n[13],g=n[2],v=n[6],m=n[10],p=n[14],y=n[3],_=n[7],x=n[11],A=n[15],b=i[0],E=i[4],I=i[8],w=i[12],M=i[1],F=i[5],V=i[9],G=i[13],q=i[2],ae=i[6],Q=i[10],oe=i[14],B=i[3],Me=i[7],be=i[11],Ae=i[15];return r[0]=o*b+a*M+l*q+c*B,r[4]=o*E+a*F+l*ae+c*Me,r[8]=o*I+a*V+l*Q+c*be,r[12]=o*w+a*G+l*oe+c*Ae,r[1]=u*b+h*M+d*q+f*B,r[5]=u*E+h*F+d*ae+f*Me,r[9]=u*I+h*V+d*Q+f*be,r[13]=u*w+h*G+d*oe+f*Ae,r[2]=g*b+v*M+m*q+p*B,r[6]=g*E+v*F+m*ae+p*Me,r[10]=g*I+v*V+m*Q+p*be,r[14]=g*w+v*G+m*oe+p*Ae,r[3]=y*b+_*M+x*q+A*B,r[7]=y*E+_*F+x*ae+A*Me,r[11]=y*I+_*V+x*Q+A*be,r[15]=y*w+_*G+x*oe+A*Ae,this}multiplyScalar(e){const t=this.elements;return t[0]*=e,t[4]*=e,t[8]*=e,t[12]*=e,t[1]*=e,t[5]*=e,t[9]*=e,t[13]*=e,t[2]*=e,t[6]*=e,t[10]*=e,t[14]*=e,t[3]*=e,t[7]*=e,t[11]*=e,t[15]*=e,this}determinant(){const e=this.elements,t=e[0],n=e[4],i=e[8],r=e[12],o=e[1],a=e[5],l=e[9],c=e[13],u=e[2],h=e[6],d=e[10],f=e[14],g=e[3],v=e[7],m=e[11],p=e[15];return g*(+r*l*h-i*c*h-r*a*d+n*c*d+i*a*f-n*l*f)+v*(+t*l*f-t*c*d+r*o*d-i*o*f+i*c*u-r*l*u)+m*(+t*c*h-t*a*f-r*o*h+n*o*f+r*a*u-n*c*u)+p*(-i*a*u-t*l*h+t*a*d+i*o*h-n*o*d+n*l*u)}transpose(){const e=this.elements;let t;return t=e[1],e[1]=e[4],e[4]=t,t=e[2],e[2]=e[8],e[8]=t,t=e[6],e[6]=e[9],e[9]=t,t=e[3],e[3]=e[12],e[12]=t,t=e[7],e[7]=e[13],e[13]=t,t=e[11],e[11]=e[14],e[14]=t,this}setPosition(e,t,n){const i=this.elements;return e.isVector3?(i[12]=e.x,i[13]=e.y,i[14]=e.z):(i[12]=e,i[13]=t,i[14]=n),this}invert(){const e=this.elements,t=e[0],n=e[1],i=e[2],r=e[3],o=e[4],a=e[5],l=e[6],c=e[7],u=e[8],h=e[9],d=e[10],f=e[11],g=e[12],v=e[13],m=e[14],p=e[15],y=h*m*c-v*d*c+v*l*f-a*m*f-h*l*p+a*d*p,_=g*d*c-u*m*c-g*l*f+o*m*f+u*l*p-o*d*p,x=u*v*c-g*h*c+g*a*f-o*v*f-u*a*p+o*h*p,A=g*h*l-u*v*l-g*a*d+o*v*d+u*a*m-o*h*m,b=t*y+n*_+i*x+r*A;if(b===0)return this.set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);const E=1/b;return e[0]=y*E,e[1]=(v*d*r-h*m*r-v*i*f+n*m*f+h*i*p-n*d*p)*E,e[2]=(a*m*r-v*l*r+v*i*c-n*m*c-a*i*p+n*l*p)*E,e[3]=(h*l*r-a*d*r-h*i*c+n*d*c+a*i*f-n*l*f)*E,e[4]=_*E,e[5]=(u*m*r-g*d*r+g*i*f-t*m*f-u*i*p+t*d*p)*E,e[6]=(g*l*r-o*m*r-g*i*c+t*m*c+o*i*p-t*l*p)*E,e[7]=(o*d*r-u*l*r+u*i*c-t*d*c-o*i*f+t*l*f)*E,e[8]=x*E,e[9]=(g*h*r-u*v*r-g*n*f+t*v*f+u*n*p-t*h*p)*E,e[10]=(o*v*r-g*a*r+g*n*c-t*v*c-o*n*p+t*a*p)*E,e[11]=(u*a*r-o*h*r-u*n*c+t*h*c+o*n*f-t*a*f)*E,e[12]=A*E,e[13]=(u*v*i-g*h*i+g*n*d-t*v*d-u*n*m+t*h*m)*E,e[14]=(g*a*i-o*v*i-g*n*l+t*v*l+o*n*m-t*a*m)*E,e[15]=(o*h*i-u*a*i+u*n*l-t*h*l-o*n*d+t*a*d)*E,this}scale(e){const t=this.elements,n=e.x,i=e.y,r=e.z;return t[0]*=n,t[4]*=i,t[8]*=r,t[1]*=n,t[5]*=i,t[9]*=r,t[2]*=n,t[6]*=i,t[10]*=r,t[3]*=n,t[7]*=i,t[11]*=r,this}getMaxScaleOnAxis(){const e=this.elements,t=e[0]*e[0]+e[1]*e[1]+e[2]*e[2],n=e[4]*e[4]+e[5]*e[5]+e[6]*e[6],i=e[8]*e[8]+e[9]*e[9]+e[10]*e[10];return Math.sqrt(Math.max(t,n,i))}makeTranslation(e,t,n){return e.isVector3?this.set(1,0,0,e.x,0,1,0,e.y,0,0,1,e.z,0,0,0,1):this.set(1,0,0,e,0,1,0,t,0,0,1,n,0,0,0,1),this}makeRotationX(e){const t=Math.cos(e),n=Math.sin(e);return this.set(1,0,0,0,0,t,-n,0,0,n,t,0,0,0,0,1),this}makeRotationY(e){const t=Math.cos(e),n=Math.sin(e);return this.set(t,0,n,0,0,1,0,0,-n,0,t,0,0,0,0,1),this}makeRotationZ(e){const t=Math.cos(e),n=Math.sin(e);return this.set(t,-n,0,0,n,t,0,0,0,0,1,0,0,0,0,1),this}makeRotationAxis(e,t){const n=Math.cos(t),i=Math.sin(t),r=1-n,o=e.x,a=e.y,l=e.z,c=r*o,u=r*a;return this.set(c*o+n,c*a-i*l,c*l+i*a,0,c*a+i*l,u*a+n,u*l-i*o,0,c*l-i*a,u*l+i*o,r*l*l+n,0,0,0,0,1),this}makeScale(e,t,n){return this.set(e,0,0,0,0,t,0,0,0,0,n,0,0,0,0,1),this}makeShear(e,t,n,i,r,o){return this.set(1,n,r,0,e,1,o,0,t,i,1,0,0,0,0,1),this}compose(e,t,n){const i=this.elements,r=t._x,o=t._y,a=t._z,l=t._w,c=r+r,u=o+o,h=a+a,d=r*c,f=r*u,g=r*h,v=o*u,m=o*h,p=a*h,y=l*c,_=l*u,x=l*h,A=n.x,b=n.y,E=n.z;return i[0]=(1-(v+p))*A,i[1]=(f+x)*A,i[2]=(g-_)*A,i[3]=0,i[4]=(f-x)*b,i[5]=(1-(d+p))*b,i[6]=(m+y)*b,i[7]=0,i[8]=(g+_)*E,i[9]=(m-y)*E,i[10]=(1-(d+v))*E,i[11]=0,i[12]=e.x,i[13]=e.y,i[14]=e.z,i[15]=1,this}decompose(e,t,n){const i=this.elements;let r=gs.set(i[0],i[1],i[2]).length();const o=gs.set(i[4],i[5],i[6]).length(),a=gs.set(i[8],i[9],i[10]).length();this.determinant()<0&&(r=-r),e.x=i[12],e.y=i[13],e.z=i[14],Sn.copy(this);const c=1/r,u=1/o,h=1/a;return Sn.elements[0]*=c,Sn.elements[1]*=c,Sn.elements[2]*=c,Sn.elements[4]*=u,Sn.elements[5]*=u,Sn.elements[6]*=u,Sn.elements[8]*=h,Sn.elements[9]*=h,Sn.elements[10]*=h,t.setFromRotationMatrix(Sn),n.x=r,n.y=o,n.z=a,this}makePerspective(e,t,n,i,r,o,a=Vn){const l=this.elements,c=2*r/(t-e),u=2*r/(n-i),h=(t+e)/(t-e),d=(n+i)/(n-i);let f,g;if(a===Vn)f=-(o+r)/(o-r),g=-2*o*r/(o-r);else if(a===Rr)f=-o/(o-r),g=-o*r/(o-r);else throw new Error("THREE.Matrix4.makePerspective(): Invalid coordinate system: "+a);return l[0]=c,l[4]=0,l[8]=h,l[12]=0,l[1]=0,l[5]=u,l[9]=d,l[13]=0,l[2]=0,l[6]=0,l[10]=f,l[14]=g,l[3]=0,l[7]=0,l[11]=-1,l[15]=0,this}makeOrthographic(e,t,n,i,r,o,a=Vn){const l=this.elements,c=1/(t-e),u=1/(n-i),h=1/(o-r),d=(t+e)*c,f=(n+i)*u;let g,v;if(a===Vn)g=(o+r)*h,v=-2*h;else if(a===Rr)g=r*h,v=-1*h;else throw new Error("THREE.Matrix4.makeOrthographic(): Invalid coordinate system: "+a);return l[0]=2*c,l[4]=0,l[8]=0,l[12]=-d,l[1]=0,l[5]=2*u,l[9]=0,l[13]=-f,l[2]=0,l[6]=0,l[10]=v,l[14]=-g,l[3]=0,l[7]=0,l[11]=0,l[15]=1,this}equals(e){const t=this.elements,n=e.elements;for(let i=0;i<16;i++)if(t[i]!==n[i])return!1;return!0}fromArray(e,t=0){for(let n=0;n<16;n++)this.elements[n]=e[n+t];return this}toArray(e=[],t=0){const n=this.elements;return e[t]=n[0],e[t+1]=n[1],e[t+2]=n[2],e[t+3]=n[3],e[t+4]=n[4],e[t+5]=n[5],e[t+6]=n[6],e[t+7]=n[7],e[t+8]=n[8],e[t+9]=n[9],e[t+10]=n[10],e[t+11]=n[11],e[t+12]=n[12],e[t+13]=n[13],e[t+14]=n[14],e[t+15]=n[15],e}}const gs=new N,Sn=new qe,hv=new N(0,0,0),dv=new N(1,1,1),_i=new N,fo=new N,fn=new N,oh=new qe,ah=new hn;class _n{constructor(e=0,t=0,n=0,i=_n.DEFAULT_ORDER){this.isEuler=!0,this._x=e,this._y=t,this._z=n,this._order=i}get x(){return this._x}set x(e){this._x=e,this._onChangeCallback()}get y(){return this._y}set y(e){this._y=e,this._onChangeCallback()}get z(){return this._z}set z(e){this._z=e,this._onChangeCallback()}get order(){return this._order}set order(e){this._order=e,this._onChangeCallback()}set(e,t,n,i=this._order){return this._x=e,this._y=t,this._z=n,this._order=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._order)}copy(e){return this._x=e._x,this._y=e._y,this._z=e._z,this._order=e._order,this._onChangeCallback(),this}setFromRotationMatrix(e,t=this._order,n=!0){const i=e.elements,r=i[0],o=i[4],a=i[8],l=i[1],c=i[5],u=i[9],h=i[2],d=i[6],f=i[10];switch(t){case"XYZ":this._y=Math.asin(Et(a,-1,1)),Math.abs(a)<.9999999?(this._x=Math.atan2(-u,f),this._z=Math.atan2(-o,r)):(this._x=Math.atan2(d,c),this._z=0);break;case"YXZ":this._x=Math.asin(-Et(u,-1,1)),Math.abs(u)<.9999999?(this._y=Math.atan2(a,f),this._z=Math.atan2(l,c)):(this._y=Math.atan2(-h,r),this._z=0);break;case"ZXY":this._x=Math.asin(Et(d,-1,1)),Math.abs(d)<.9999999?(this._y=Math.atan2(-h,f),this._z=Math.atan2(-o,c)):(this._y=0,this._z=Math.atan2(l,r));break;case"ZYX":this._y=Math.asin(-Et(h,-1,1)),Math.abs(h)<.9999999?(this._x=Math.atan2(d,f),this._z=Math.atan2(l,r)):(this._x=0,this._z=Math.atan2(-o,c));break;case"YZX":this._z=Math.asin(Et(l,-1,1)),Math.abs(l)<.9999999?(this._x=Math.atan2(-u,c),this._y=Math.atan2(-h,r)):(this._x=0,this._y=Math.atan2(a,f));break;case"XZY":this._z=Math.asin(-Et(o,-1,1)),Math.abs(o)<.9999999?(this._x=Math.atan2(d,c),this._y=Math.atan2(a,r)):(this._x=Math.atan2(-u,f),this._y=0);break;default:console.warn("THREE.Euler: .setFromRotationMatrix() encountered an unknown order: "+t)}return this._order=t,n===!0&&this._onChangeCallback(),this}setFromQuaternion(e,t,n){return oh.makeRotationFromQuaternion(e),this.setFromRotationMatrix(oh,t,n)}setFromVector3(e,t=this._order){return this.set(e.x,e.y,e.z,t)}reorder(e){return ah.setFromEuler(this),this.setFromQuaternion(ah,e)}equals(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._order===this._order}fromArray(e){return this._x=e[0],this._y=e[1],this._z=e[2],e[3]!==void 0&&(this._order=e[3]),this._onChangeCallback(),this}toArray(e=[],t=0){return e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._order,e}_onChange(e){return this._onChangeCallback=e,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._order}}_n.DEFAULT_ORDER="XYZ";class La{constructor(){this.mask=1}set(e){this.mask=(1<>>0}enable(e){this.mask|=1<1){for(let t=0;t1){for(let n=0;n0&&(i.userData=this.userData),i.layers=this.layers.mask,i.matrix=this.matrix.toArray(),i.up=this.up.toArray(),this.matrixAutoUpdate===!1&&(i.matrixAutoUpdate=!1),this.isInstancedMesh&&(i.type="InstancedMesh",i.count=this.count,i.instanceMatrix=this.instanceMatrix.toJSON(),this.instanceColor!==null&&(i.instanceColor=this.instanceColor.toJSON())),this.isBatchedMesh&&(i.type="BatchedMesh",i.perObjectFrustumCulled=this.perObjectFrustumCulled,i.sortObjects=this.sortObjects,i.drawRanges=this._drawRanges,i.reservedRanges=this._reservedRanges,i.visibility=this._visibility,i.active=this._active,i.bounds=this._bounds.map(a=>({boxInitialized:a.boxInitialized,boxMin:a.box.min.toArray(),boxMax:a.box.max.toArray(),sphereInitialized:a.sphereInitialized,sphereRadius:a.sphere.radius,sphereCenter:a.sphere.center.toArray()})),i.maxGeometryCount=this._maxGeometryCount,i.maxVertexCount=this._maxVertexCount,i.maxIndexCount=this._maxIndexCount,i.geometryInitialized=this._geometryInitialized,i.geometryCount=this._geometryCount,i.matricesTexture=this._matricesTexture.toJSON(e),this._colorsTexture!==null&&(i.colorsTexture=this._colorsTexture.toJSON(e)),this.boundingSphere!==null&&(i.boundingSphere={center:i.boundingSphere.center.toArray(),radius:i.boundingSphere.radius}),this.boundingBox!==null&&(i.boundingBox={min:i.boundingBox.min.toArray(),max:i.boundingBox.max.toArray()}));function r(a,l){return a[l.uuid]===void 0&&(a[l.uuid]=l.toJSON(e)),l.uuid}if(this.isScene)this.background&&(this.background.isColor?i.background=this.background.toJSON():this.background.isTexture&&(i.background=this.background.toJSON(e).uuid)),this.environment&&this.environment.isTexture&&this.environment.isRenderTargetTexture!==!0&&(i.environment=this.environment.toJSON(e).uuid);else if(this.isMesh||this.isLine||this.isPoints){i.geometry=r(e.geometries,this.geometry);const a=this.geometry.parameters;if(a!==void 0&&a.shapes!==void 0){const l=a.shapes;if(Array.isArray(l))for(let c=0,u=l.length;c0){i.children=[];for(let a=0;a0){i.animations=[];for(let a=0;a0&&(n.geometries=a),l.length>0&&(n.materials=l),c.length>0&&(n.textures=c),u.length>0&&(n.images=u),h.length>0&&(n.shapes=h),d.length>0&&(n.skeletons=d),f.length>0&&(n.animations=f),g.length>0&&(n.nodes=g)}return n.object=i,n;function o(a){const l=[];for(const c in a){const u=a[c];delete u.metadata,l.push(u)}return l}}clone(e){return new this.constructor().copy(this,e)}copy(e,t=!0){if(this.name=e.name,this.up.copy(e.up),this.position.copy(e.position),this.rotation.order=e.rotation.order,this.quaternion.copy(e.quaternion),this.scale.copy(e.scale),this.matrix.copy(e.matrix),this.matrixWorld.copy(e.matrixWorld),this.matrixAutoUpdate=e.matrixAutoUpdate,this.matrixWorldAutoUpdate=e.matrixWorldAutoUpdate,this.matrixWorldNeedsUpdate=e.matrixWorldNeedsUpdate,this.layers.mask=e.layers.mask,this.visible=e.visible,this.castShadow=e.castShadow,this.receiveShadow=e.receiveShadow,this.frustumCulled=e.frustumCulled,this.renderOrder=e.renderOrder,this.animations=e.animations.slice(),this.userData=JSON.parse(JSON.stringify(e.userData)),t===!0)for(let n=0;n0?i.multiplyScalar(1/Math.sqrt(r)):i.set(0,0,0)}static getBarycoord(e,t,n,i,r){wn.subVectors(i,t),jn.subVectors(n,t),yl.subVectors(e,t);const o=wn.dot(wn),a=wn.dot(jn),l=wn.dot(yl),c=jn.dot(jn),u=jn.dot(yl),h=o*c-a*a;if(h===0)return r.set(0,0,0),null;const d=1/h,f=(c*l-a*u)*d,g=(o*u-a*l)*d;return r.set(1-f-g,g,f)}static containsPoint(e,t,n,i){return this.getBarycoord(e,t,n,i,Qn)===null?!1:Qn.x>=0&&Qn.y>=0&&Qn.x+Qn.y<=1}static getInterpolation(e,t,n,i,r,o,a,l){return this.getBarycoord(e,t,n,i,Qn)===null?(l.x=0,l.y=0,"z"in l&&(l.z=0),"w"in l&&(l.w=0),null):(l.setScalar(0),l.addScaledVector(r,Qn.x),l.addScaledVector(o,Qn.y),l.addScaledVector(a,Qn.z),l)}static isFrontFacing(e,t,n,i){return wn.subVectors(n,t),jn.subVectors(e,t),wn.cross(jn).dot(i)<0}set(e,t,n){return this.a.copy(e),this.b.copy(t),this.c.copy(n),this}setFromPointsAndIndices(e,t,n,i){return this.a.copy(e[t]),this.b.copy(e[n]),this.c.copy(e[i]),this}setFromAttributeAndIndices(e,t,n,i){return this.a.fromBufferAttribute(e,t),this.b.fromBufferAttribute(e,n),this.c.fromBufferAttribute(e,i),this}clone(){return new this.constructor().copy(this)}copy(e){return this.a.copy(e.a),this.b.copy(e.b),this.c.copy(e.c),this}getArea(){return wn.subVectors(this.c,this.b),jn.subVectors(this.a,this.b),wn.cross(jn).length()*.5}getMidpoint(e){return e.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)}getNormal(e){return mn.getNormal(this.a,this.b,this.c,e)}getPlane(e){return e.setFromCoplanarPoints(this.a,this.b,this.c)}getBarycoord(e,t){return mn.getBarycoord(e,this.a,this.b,this.c,t)}getInterpolation(e,t,n,i,r){return mn.getInterpolation(e,this.a,this.b,this.c,t,n,i,r)}containsPoint(e){return mn.containsPoint(e,this.a,this.b,this.c)}isFrontFacing(e){return mn.isFrontFacing(this.a,this.b,this.c,e)}intersectsBox(e){return e.intersectsTriangle(this)}closestPointToPoint(e,t){const n=this.a,i=this.b,r=this.c;let o,a;ys.subVectors(i,n),xs.subVectors(r,n),xl.subVectors(e,n);const l=ys.dot(xl),c=xs.dot(xl);if(l<=0&&c<=0)return t.copy(n);Ml.subVectors(e,i);const u=ys.dot(Ml),h=xs.dot(Ml);if(u>=0&&h<=u)return t.copy(i);const d=l*h-u*c;if(d<=0&&l>=0&&u<=0)return o=l/(l-u),t.copy(n).addScaledVector(ys,o);bl.subVectors(e,r);const f=ys.dot(bl),g=xs.dot(bl);if(g>=0&&f<=g)return t.copy(r);const v=f*c-l*g;if(v<=0&&c>=0&&g<=0)return a=c/(c-g),t.copy(n).addScaledVector(xs,a);const m=u*g-f*h;if(m<=0&&h-u>=0&&f-g>=0)return fh.subVectors(r,i),a=(h-u)/(h-u+(f-g)),t.copy(i).addScaledVector(fh,a);const p=1/(m+v+d);return o=v*p,a=d*p,t.copy(n).addScaledVector(ys,o).addScaledVector(xs,a)}equals(e){return e.a.equals(this.a)&&e.b.equals(this.b)&&e.c.equals(this.c)}}const lp={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074},yi={h:0,s:0,l:0},mo={h:0,s:0,l:0};function Sl(s,e,t){return t<0&&(t+=1),t>1&&(t-=1),t<1/6?s+(e-s)*6*t:t<1/2?e:t<2/3?s+(e-s)*6*(2/3-t):s}class Pe{constructor(e,t,n){return this.isColor=!0,this.r=1,this.g=1,this.b=1,this.set(e,t,n)}set(e,t,n){if(t===void 0&&n===void 0){const i=e;i&&i.isColor?this.copy(i):typeof i=="number"?this.setHex(i):typeof i=="string"&&this.setStyle(i)}else this.setRGB(e,t,n);return this}setScalar(e){return this.r=e,this.g=e,this.b=e,this}setHex(e,t=ln){return e=Math.floor(e),this.r=(e>>16&255)/255,this.g=(e>>8&255)/255,this.b=(e&255)/255,ht.toWorkingColorSpace(this,t),this}setRGB(e,t,n,i=ht.workingColorSpace){return this.r=e,this.g=t,this.b=n,ht.toWorkingColorSpace(this,i),this}setHSL(e,t,n,i=ht.workingColorSpace){if(e=cu(e,1),t=Et(t,0,1),n=Et(n,0,1),t===0)this.r=this.g=this.b=n;else{const r=n<=.5?n*(1+t):n+t-n*t,o=2*n-r;this.r=Sl(o,r,e+1/3),this.g=Sl(o,r,e),this.b=Sl(o,r,e-1/3)}return ht.toWorkingColorSpace(this,i),this}setStyle(e,t=ln){function n(r){r!==void 0&&parseFloat(r)<1&&console.warn("THREE.Color: Alpha component of "+e+" will be ignored.")}let i;if(i=/^(\w+)\(([^\)]*)\)/.exec(e)){let r;const o=i[1],a=i[2];switch(o){case"rgb":case"rgba":if(r=/^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(a))return n(r[4]),this.setRGB(Math.min(255,parseInt(r[1],10))/255,Math.min(255,parseInt(r[2],10))/255,Math.min(255,parseInt(r[3],10))/255,t);if(r=/^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(a))return n(r[4]),this.setRGB(Math.min(100,parseInt(r[1],10))/100,Math.min(100,parseInt(r[2],10))/100,Math.min(100,parseInt(r[3],10))/100,t);break;case"hsl":case"hsla":if(r=/^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(a))return n(r[4]),this.setHSL(parseFloat(r[1])/360,parseFloat(r[2])/100,parseFloat(r[3])/100,t);break;default:console.warn("THREE.Color: Unknown color model "+e)}}else if(i=/^\#([A-Fa-f\d]+)$/.exec(e)){const r=i[1],o=r.length;if(o===3)return this.setRGB(parseInt(r.charAt(0),16)/15,parseInt(r.charAt(1),16)/15,parseInt(r.charAt(2),16)/15,t);if(o===6)return this.setHex(parseInt(r,16),t);console.warn("THREE.Color: Invalid hex color "+e)}else if(e&&e.length>0)return this.setColorName(e,t);return this}setColorName(e,t=ln){const n=lp[e.toLowerCase()];return n!==void 0?this.setHex(n,t):console.warn("THREE.Color: Unknown color "+e),this}clone(){return new this.constructor(this.r,this.g,this.b)}copy(e){return this.r=e.r,this.g=e.g,this.b=e.b,this}copySRGBToLinear(e){return this.r=zs(e.r),this.g=zs(e.g),this.b=zs(e.b),this}copyLinearToSRGB(e){return this.r=ul(e.r),this.g=ul(e.g),this.b=ul(e.b),this}convertSRGBToLinear(){return this.copySRGBToLinear(this),this}convertLinearToSRGB(){return this.copyLinearToSRGB(this),this}getHex(e=ln){return ht.fromWorkingColorSpace(qt.copy(this),e),Math.round(Et(qt.r*255,0,255))*65536+Math.round(Et(qt.g*255,0,255))*256+Math.round(Et(qt.b*255,0,255))}getHexString(e=ln){return("000000"+this.getHex(e).toString(16)).slice(-6)}getHSL(e,t=ht.workingColorSpace){ht.fromWorkingColorSpace(qt.copy(this),t);const n=qt.r,i=qt.g,r=qt.b,o=Math.max(n,i,r),a=Math.min(n,i,r);let l,c;const u=(a+o)/2;if(a===o)l=0,c=0;else{const h=o-a;switch(c=u<=.5?h/(o+a):h/(2-o-a),o){case n:l=(i-r)/h+(i0!=e>0&&this.version++,this._alphaTest=e}onBuild(){}onBeforeRender(){}onBeforeCompile(){}customProgramCacheKey(){return this.onBeforeCompile.toString()}setValues(e){if(e!==void 0)for(const t in e){const n=e[t];if(n===void 0){console.warn(`THREE.Material: parameter '${t}' has value of undefined.`);continue}const i=this[t];if(i===void 0){console.warn(`THREE.Material: '${t}' is not a property of THREE.${this.type}.`);continue}i&&i.isColor?i.set(n):i&&i.isVector3&&n&&n.isVector3?i.copy(n):this[t]=n}}toJSON(e){const t=e===void 0||typeof e=="string";t&&(e={textures:{},images:{}});const n={metadata:{version:4.6,type:"Material",generator:"Material.toJSON"}};n.uuid=this.uuid,n.type=this.type,this.name!==""&&(n.name=this.name),this.color&&this.color.isColor&&(n.color=this.color.getHex()),this.roughness!==void 0&&(n.roughness=this.roughness),this.metalness!==void 0&&(n.metalness=this.metalness),this.sheen!==void 0&&(n.sheen=this.sheen),this.sheenColor&&this.sheenColor.isColor&&(n.sheenColor=this.sheenColor.getHex()),this.sheenRoughness!==void 0&&(n.sheenRoughness=this.sheenRoughness),this.emissive&&this.emissive.isColor&&(n.emissive=this.emissive.getHex()),this.emissiveIntensity!==void 0&&this.emissiveIntensity!==1&&(n.emissiveIntensity=this.emissiveIntensity),this.specular&&this.specular.isColor&&(n.specular=this.specular.getHex()),this.specularIntensity!==void 0&&(n.specularIntensity=this.specularIntensity),this.specularColor&&this.specularColor.isColor&&(n.specularColor=this.specularColor.getHex()),this.shininess!==void 0&&(n.shininess=this.shininess),this.clearcoat!==void 0&&(n.clearcoat=this.clearcoat),this.clearcoatRoughness!==void 0&&(n.clearcoatRoughness=this.clearcoatRoughness),this.clearcoatMap&&this.clearcoatMap.isTexture&&(n.clearcoatMap=this.clearcoatMap.toJSON(e).uuid),this.clearcoatRoughnessMap&&this.clearcoatRoughnessMap.isTexture&&(n.clearcoatRoughnessMap=this.clearcoatRoughnessMap.toJSON(e).uuid),this.clearcoatNormalMap&&this.clearcoatNormalMap.isTexture&&(n.clearcoatNormalMap=this.clearcoatNormalMap.toJSON(e).uuid,n.clearcoatNormalScale=this.clearcoatNormalScale.toArray()),this.dispersion!==void 0&&(n.dispersion=this.dispersion),this.iridescence!==void 0&&(n.iridescence=this.iridescence),this.iridescenceIOR!==void 0&&(n.iridescenceIOR=this.iridescenceIOR),this.iridescenceThicknessRange!==void 0&&(n.iridescenceThicknessRange=this.iridescenceThicknessRange),this.iridescenceMap&&this.iridescenceMap.isTexture&&(n.iridescenceMap=this.iridescenceMap.toJSON(e).uuid),this.iridescenceThicknessMap&&this.iridescenceThicknessMap.isTexture&&(n.iridescenceThicknessMap=this.iridescenceThicknessMap.toJSON(e).uuid),this.anisotropy!==void 0&&(n.anisotropy=this.anisotropy),this.anisotropyRotation!==void 0&&(n.anisotropyRotation=this.anisotropyRotation),this.anisotropyMap&&this.anisotropyMap.isTexture&&(n.anisotropyMap=this.anisotropyMap.toJSON(e).uuid),this.map&&this.map.isTexture&&(n.map=this.map.toJSON(e).uuid),this.matcap&&this.matcap.isTexture&&(n.matcap=this.matcap.toJSON(e).uuid),this.alphaMap&&this.alphaMap.isTexture&&(n.alphaMap=this.alphaMap.toJSON(e).uuid),this.lightMap&&this.lightMap.isTexture&&(n.lightMap=this.lightMap.toJSON(e).uuid,n.lightMapIntensity=this.lightMapIntensity),this.aoMap&&this.aoMap.isTexture&&(n.aoMap=this.aoMap.toJSON(e).uuid,n.aoMapIntensity=this.aoMapIntensity),this.bumpMap&&this.bumpMap.isTexture&&(n.bumpMap=this.bumpMap.toJSON(e).uuid,n.bumpScale=this.bumpScale),this.normalMap&&this.normalMap.isTexture&&(n.normalMap=this.normalMap.toJSON(e).uuid,n.normalMapType=this.normalMapType,n.normalScale=this.normalScale.toArray()),this.displacementMap&&this.displacementMap.isTexture&&(n.displacementMap=this.displacementMap.toJSON(e).uuid,n.displacementScale=this.displacementScale,n.displacementBias=this.displacementBias),this.roughnessMap&&this.roughnessMap.isTexture&&(n.roughnessMap=this.roughnessMap.toJSON(e).uuid),this.metalnessMap&&this.metalnessMap.isTexture&&(n.metalnessMap=this.metalnessMap.toJSON(e).uuid),this.emissiveMap&&this.emissiveMap.isTexture&&(n.emissiveMap=this.emissiveMap.toJSON(e).uuid),this.specularMap&&this.specularMap.isTexture&&(n.specularMap=this.specularMap.toJSON(e).uuid),this.specularIntensityMap&&this.specularIntensityMap.isTexture&&(n.specularIntensityMap=this.specularIntensityMap.toJSON(e).uuid),this.specularColorMap&&this.specularColorMap.isTexture&&(n.specularColorMap=this.specularColorMap.toJSON(e).uuid),this.envMap&&this.envMap.isTexture&&(n.envMap=this.envMap.toJSON(e).uuid,this.combine!==void 0&&(n.combine=this.combine)),this.envMapRotation!==void 0&&(n.envMapRotation=this.envMapRotation.toArray()),this.envMapIntensity!==void 0&&(n.envMapIntensity=this.envMapIntensity),this.reflectivity!==void 0&&(n.reflectivity=this.reflectivity),this.refractionRatio!==void 0&&(n.refractionRatio=this.refractionRatio),this.gradientMap&&this.gradientMap.isTexture&&(n.gradientMap=this.gradientMap.toJSON(e).uuid),this.transmission!==void 0&&(n.transmission=this.transmission),this.transmissionMap&&this.transmissionMap.isTexture&&(n.transmissionMap=this.transmissionMap.toJSON(e).uuid),this.thickness!==void 0&&(n.thickness=this.thickness),this.thicknessMap&&this.thicknessMap.isTexture&&(n.thicknessMap=this.thicknessMap.toJSON(e).uuid),this.attenuationDistance!==void 0&&this.attenuationDistance!==1/0&&(n.attenuationDistance=this.attenuationDistance),this.attenuationColor!==void 0&&(n.attenuationColor=this.attenuationColor.getHex()),this.size!==void 0&&(n.size=this.size),this.shadowSide!==null&&(n.shadowSide=this.shadowSide),this.sizeAttenuation!==void 0&&(n.sizeAttenuation=this.sizeAttenuation),this.blending!==es&&(n.blending=this.blending),this.side!==oi&&(n.side=this.side),this.vertexColors===!0&&(n.vertexColors=!0),this.opacity<1&&(n.opacity=this.opacity),this.transparent===!0&&(n.transparent=!0),this.blendSrc!==va&&(n.blendSrc=this.blendSrc),this.blendDst!==_a&&(n.blendDst=this.blendDst),this.blendEquation!==Ai&&(n.blendEquation=this.blendEquation),this.blendSrcAlpha!==null&&(n.blendSrcAlpha=this.blendSrcAlpha),this.blendDstAlpha!==null&&(n.blendDstAlpha=this.blendDstAlpha),this.blendEquationAlpha!==null&&(n.blendEquationAlpha=this.blendEquationAlpha),this.blendColor&&this.blendColor.isColor&&(n.blendColor=this.blendColor.getHex()),this.blendAlpha!==0&&(n.blendAlpha=this.blendAlpha),this.depthFunc!==_r&&(n.depthFunc=this.depthFunc),this.depthTest===!1&&(n.depthTest=this.depthTest),this.depthWrite===!1&&(n.depthWrite=this.depthWrite),this.colorWrite===!1&&(n.colorWrite=this.colorWrite),this.stencilWriteMask!==255&&(n.stencilWriteMask=this.stencilWriteMask),this.stencilFunc!==Pc&&(n.stencilFunc=this.stencilFunc),this.stencilRef!==0&&(n.stencilRef=this.stencilRef),this.stencilFuncMask!==255&&(n.stencilFuncMask=this.stencilFuncMask),this.stencilFail!==Bn&&(n.stencilFail=this.stencilFail),this.stencilZFail!==Bn&&(n.stencilZFail=this.stencilZFail),this.stencilZPass!==Bn&&(n.stencilZPass=this.stencilZPass),this.stencilWrite===!0&&(n.stencilWrite=this.stencilWrite),this.rotation!==void 0&&this.rotation!==0&&(n.rotation=this.rotation),this.polygonOffset===!0&&(n.polygonOffset=!0),this.polygonOffsetFactor!==0&&(n.polygonOffsetFactor=this.polygonOffsetFactor),this.polygonOffsetUnits!==0&&(n.polygonOffsetUnits=this.polygonOffsetUnits),this.linewidth!==void 0&&this.linewidth!==1&&(n.linewidth=this.linewidth),this.dashSize!==void 0&&(n.dashSize=this.dashSize),this.gapSize!==void 0&&(n.gapSize=this.gapSize),this.scale!==void 0&&(n.scale=this.scale),this.dithering===!0&&(n.dithering=!0),this.alphaTest>0&&(n.alphaTest=this.alphaTest),this.alphaHash===!0&&(n.alphaHash=!0),this.alphaToCoverage===!0&&(n.alphaToCoverage=!0),this.premultipliedAlpha===!0&&(n.premultipliedAlpha=!0),this.forceSinglePass===!0&&(n.forceSinglePass=!0),this.wireframe===!0&&(n.wireframe=!0),this.wireframeLinewidth>1&&(n.wireframeLinewidth=this.wireframeLinewidth),this.wireframeLinecap!=="round"&&(n.wireframeLinecap=this.wireframeLinecap),this.wireframeLinejoin!=="round"&&(n.wireframeLinejoin=this.wireframeLinejoin),this.flatShading===!0&&(n.flatShading=!0),this.visible===!1&&(n.visible=!1),this.toneMapped===!1&&(n.toneMapped=!1),this.fog===!1&&(n.fog=!1),Object.keys(this.userData).length>0&&(n.userData=this.userData);function i(r){const o=[];for(const a in r){const l=r[a];delete l.metadata,o.push(l)}return o}if(t){const r=i(e.textures),o=i(e.images);r.length>0&&(n.textures=r),o.length>0&&(n.images=o)}return n}clone(){return new this.constructor().copy(this)}copy(e){this.name=e.name,this.blending=e.blending,this.side=e.side,this.vertexColors=e.vertexColors,this.opacity=e.opacity,this.transparent=e.transparent,this.blendSrc=e.blendSrc,this.blendDst=e.blendDst,this.blendEquation=e.blendEquation,this.blendSrcAlpha=e.blendSrcAlpha,this.blendDstAlpha=e.blendDstAlpha,this.blendEquationAlpha=e.blendEquationAlpha,this.blendColor.copy(e.blendColor),this.blendAlpha=e.blendAlpha,this.depthFunc=e.depthFunc,this.depthTest=e.depthTest,this.depthWrite=e.depthWrite,this.stencilWriteMask=e.stencilWriteMask,this.stencilFunc=e.stencilFunc,this.stencilRef=e.stencilRef,this.stencilFuncMask=e.stencilFuncMask,this.stencilFail=e.stencilFail,this.stencilZFail=e.stencilZFail,this.stencilZPass=e.stencilZPass,this.stencilWrite=e.stencilWrite;const t=e.clippingPlanes;let n=null;if(t!==null){const i=t.length;n=new Array(i);for(let r=0;r!==i;++r)n[r]=t[r].clone()}return this.clippingPlanes=n,this.clipIntersection=e.clipIntersection,this.clipShadows=e.clipShadows,this.shadowSide=e.shadowSide,this.colorWrite=e.colorWrite,this.precision=e.precision,this.polygonOffset=e.polygonOffset,this.polygonOffsetFactor=e.polygonOffsetFactor,this.polygonOffsetUnits=e.polygonOffsetUnits,this.dithering=e.dithering,this.alphaTest=e.alphaTest,this.alphaHash=e.alphaHash,this.alphaToCoverage=e.alphaToCoverage,this.premultipliedAlpha=e.premultipliedAlpha,this.forceSinglePass=e.forceSinglePass,this.visible=e.visible,this.toneMapped=e.toneMapped,this.userData=JSON.parse(JSON.stringify(e.userData)),this}dispose(){this.dispatchEvent({type:"dispose"})}set needsUpdate(e){e===!0&&this.version++}}class hi extends Kt{constructor(e){super(),this.isMeshBasicMaterial=!0,this.type="MeshBasicMaterial",this.color=new Pe(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new _n,this.combine=Gr,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.envMapRotation.copy(e.envMapRotation),this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.fog=e.fog,this}}const ni=_v();function _v(){const s=new ArrayBuffer(4),e=new Float32Array(s),t=new Uint32Array(s),n=new Uint32Array(512),i=new Uint32Array(512);for(let l=0;l<256;++l){const c=l-127;c<-27?(n[l]=0,n[l|256]=32768,i[l]=24,i[l|256]=24):c<-14?(n[l]=1024>>-c-14,n[l|256]=1024>>-c-14|32768,i[l]=-c-1,i[l|256]=-c-1):c<=15?(n[l]=c+15<<10,n[l|256]=c+15<<10|32768,i[l]=13,i[l|256]=13):c<128?(n[l]=31744,n[l|256]=64512,i[l]=24,i[l|256]=24):(n[l]=31744,n[l|256]=64512,i[l]=13,i[l|256]=13)}const r=new Uint32Array(2048),o=new Uint32Array(64),a=new Uint32Array(64);for(let l=1;l<1024;++l){let c=l<<13,u=0;for(;!(c&8388608);)c<<=1,u-=8388608;c&=-8388609,u+=947912704,r[l]=c|u}for(let l=1024;l<2048;++l)r[l]=939524096+(l-1024<<13);for(let l=1;l<31;++l)o[l]=l<<23;o[31]=1199570944,o[32]=2147483648;for(let l=33;l<63;++l)o[l]=2147483648+(l-32<<23);o[63]=3347054592;for(let l=1;l<64;++l)l!==32&&(a[l]=1024);return{floatView:e,uint32View:t,baseTable:n,shiftTable:i,mantissaTable:r,exponentTable:o,offsetTable:a}}function an(s){Math.abs(s)>65504&&console.warn("THREE.DataUtils.toHalfFloat(): Value out of range."),s=Et(s,-65504,65504),ni.floatView[0]=s;const e=ni.uint32View[0],t=e>>23&511;return ni.baseTable[t]+((e&8388607)>>ni.shiftTable[t])}function cr(s){const e=s>>10;return ni.uint32View[0]=ni.mantissaTable[ni.offsetTable[e]+(s&1023)]+ni.exponentTable[e],ni.floatView[0]}const yv={toHalfFloat:an,fromHalfFloat:cr},Dt=new N,go=new se;class pt{constructor(e,t,n=!1){if(Array.isArray(e))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.isBufferAttribute=!0,this.name="",this.array=e,this.itemSize=t,this.count=e!==void 0?e.length/t:0,this.normalized=n,this.usage=Pr,this._updateRange={offset:0,count:-1},this.updateRanges=[],this.gpuType=gn,this.version=0}onUploadCallback(){}set needsUpdate(e){e===!0&&this.version++}get updateRange(){return uu("THREE.BufferAttribute: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead."),this._updateRange}setUsage(e){return this.usage=e,this}addUpdateRange(e,t){this.updateRanges.push({start:e,count:t})}clearUpdateRanges(){this.updateRanges.length=0}copy(e){return this.name=e.name,this.array=new e.array.constructor(e.array),this.itemSize=e.itemSize,this.count=e.count,this.normalized=e.normalized,this.usage=e.usage,this.gpuType=e.gpuType,this}copyAt(e,t,n){e*=this.itemSize,n*=t.itemSize;for(let i=0,r=this.itemSize;i0&&(e.userData=this.userData),this.parameters!==void 0){const l=this.parameters;for(const c in l)l[c]!==void 0&&(e[c]=l[c]);return e}e.data={attributes:{}};const t=this.index;t!==null&&(e.data.index={type:t.array.constructor.name,array:Array.prototype.slice.call(t.array)});const n=this.attributes;for(const l in n){const c=n[l];e.data.attributes[l]=c.toJSON(e.data)}const i={};let r=!1;for(const l in this.morphAttributes){const c=this.morphAttributes[l],u=[];for(let h=0,d=c.length;h0&&(i[l]=u,r=!0)}r&&(e.data.morphAttributes=i,e.data.morphTargetsRelative=this.morphTargetsRelative);const o=this.groups;o.length>0&&(e.data.groups=JSON.parse(JSON.stringify(o)));const a=this.boundingSphere;return a!==null&&(e.data.boundingSphere={center:a.center.toArray(),radius:a.radius}),e}clone(){return new this.constructor().copy(this)}copy(e){this.index=null,this.attributes={},this.morphAttributes={},this.groups=[],this.boundingBox=null,this.boundingSphere=null;const t={};this.name=e.name;const n=e.index;n!==null&&this.setIndex(n.clone(t));const i=e.attributes;for(const c in i){const u=i[c];this.setAttribute(c,u.clone(t))}const r=e.morphAttributes;for(const c in r){const u=[],h=r[c];for(let d=0,f=h.length;d0){const i=t[n[0]];if(i!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let r=0,o=i.length;r(e.far-e.near)**2))&&(ph.copy(r).invert(),ki.copy(e.ray).applyMatrix4(ph),!(n.boundingBox!==null&&ki.intersectsBox(n.boundingBox)===!1)&&this._computeIntersections(e,t,ki)))}_computeIntersections(e,t,n){let i;const r=this.geometry,o=this.material,a=r.index,l=r.attributes.position,c=r.attributes.uv,u=r.attributes.uv1,h=r.attributes.normal,d=r.groups,f=r.drawRange;if(a!==null)if(Array.isArray(o))for(let g=0,v=d.length;gt.far?null:{distance:c,point:So.clone(),object:s}}function wo(s,e,t,n,i,r,o,a,l,c){s.getVertexPosition(a,bs),s.getVertexPosition(l,Ss),s.getVertexPosition(c,ws);const u=Ev(s,e,t,n,bs,Ss,ws,bo);if(u){i&&(yo.fromBufferAttribute(i,a),xo.fromBufferAttribute(i,l),Mo.fromBufferAttribute(i,c),u.uv=mn.getInterpolation(bo,bs,Ss,ws,yo,xo,Mo,new se)),r&&(yo.fromBufferAttribute(r,a),xo.fromBufferAttribute(r,l),Mo.fromBufferAttribute(r,c),u.uv1=mn.getInterpolation(bo,bs,Ss,ws,yo,xo,Mo,new se)),o&&(gh.fromBufferAttribute(o,a),vh.fromBufferAttribute(o,l),_h.fromBufferAttribute(o,c),u.normal=mn.getInterpolation(bo,bs,Ss,ws,gh,vh,_h,new N),u.normal.dot(n.direction)>0&&u.normal.multiplyScalar(-1));const h={a,b:l,c,normal:new N,materialIndex:0};mn.getNormal(bs,Ss,ws,h.normal),u.face=h}return u}class cs extends it{constructor(e=1,t=1,n=1,i=1,r=1,o=1){super(),this.type="BoxGeometry",this.parameters={width:e,height:t,depth:n,widthSegments:i,heightSegments:r,depthSegments:o};const a=this;i=Math.floor(i),r=Math.floor(r),o=Math.floor(o);const l=[],c=[],u=[],h=[];let d=0,f=0;g("z","y","x",-1,-1,n,t,e,o,r,0),g("z","y","x",1,-1,n,t,-e,o,r,1),g("x","z","y",1,1,e,n,t,i,o,2),g("x","z","y",1,-1,e,n,-t,i,o,3),g("x","y","z",1,-1,e,t,n,i,r,4),g("x","y","z",-1,-1,e,t,-n,i,r,5),this.setIndex(l),this.setAttribute("position",new Ne(c,3)),this.setAttribute("normal",new Ne(u,3)),this.setAttribute("uv",new Ne(h,2));function g(v,m,p,y,_,x,A,b,E,I,w){const M=x/E,F=A/I,V=x/2,G=A/2,q=b/2,ae=E+1,Q=I+1;let oe=0,B=0;const Me=new N;for(let be=0;be0?1:-1,u.push(Me.x,Me.y,Me.z),h.push(ge/E),h.push(1-be/I),oe+=1}}for(let be=0;be0&&(t.defines=this.defines),t.vertexShader=this.vertexShader,t.fragmentShader=this.fragmentShader,t.lights=this.lights,t.clipping=this.clipping;const n={};for(const i in this.extensions)this.extensions[i]===!0&&(n[i]=!0);return Object.keys(n).length>0&&(t.extensions=n),t}}class Xr extends ct{constructor(){super(),this.isCamera=!0,this.type="Camera",this.matrixWorldInverse=new qe,this.projectionMatrix=new qe,this.projectionMatrixInverse=new qe,this.coordinateSystem=Vn}copy(e,t){return super.copy(e,t),this.matrixWorldInverse.copy(e.matrixWorldInverse),this.projectionMatrix.copy(e.projectionMatrix),this.projectionMatrixInverse.copy(e.projectionMatrixInverse),this.coordinateSystem=e.coordinateSystem,this}getWorldDirection(e){return super.getWorldDirection(e).negate()}updateMatrixWorld(e){super.updateMatrixWorld(e),this.matrixWorldInverse.copy(this.matrixWorld).invert()}updateWorldMatrix(e,t){super.updateWorldMatrix(e,t),this.matrixWorldInverse.copy(this.matrixWorld).invert()}clone(){return new this.constructor().copy(this)}}const xi=new N,yh=new se,xh=new se;class Ut extends Xr{constructor(e=50,t=1,n=.1,i=2e3){super(),this.isPerspectiveCamera=!0,this.type="PerspectiveCamera",this.fov=e,this.zoom=1,this.near=n,this.far=i,this.focus=10,this.aspect=t,this.view=null,this.filmGauge=35,this.filmOffset=0,this.updateProjectionMatrix()}copy(e,t){return super.copy(e,t),this.fov=e.fov,this.zoom=e.zoom,this.near=e.near,this.far=e.far,this.focus=e.focus,this.aspect=e.aspect,this.view=e.view===null?null:Object.assign({},e.view),this.filmGauge=e.filmGauge,this.filmOffset=e.filmOffset,this}setFocalLength(e){const t=.5*this.getFilmHeight()/e;this.fov=Vs*2*Math.atan(t),this.updateProjectionMatrix()}getFocalLength(){const e=Math.tan(ns*.5*this.fov);return .5*this.getFilmHeight()/e}getEffectiveFOV(){return Vs*2*Math.atan(Math.tan(ns*.5*this.fov)/this.zoom)}getFilmWidth(){return this.filmGauge*Math.min(this.aspect,1)}getFilmHeight(){return this.filmGauge/Math.max(this.aspect,1)}getViewBounds(e,t,n){xi.set(-1,-1,.5).applyMatrix4(this.projectionMatrixInverse),t.set(xi.x,xi.y).multiplyScalar(-e/xi.z),xi.set(1,1,.5).applyMatrix4(this.projectionMatrixInverse),n.set(xi.x,xi.y).multiplyScalar(-e/xi.z)}getViewSize(e,t){return this.getViewBounds(e,yh,xh),t.subVectors(xh,yh)}setViewOffset(e,t,n,i,r,o){this.aspect=e/t,this.view===null&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=e,this.view.fullHeight=t,this.view.offsetX=n,this.view.offsetY=i,this.view.width=r,this.view.height=o,this.updateProjectionMatrix()}clearViewOffset(){this.view!==null&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const e=this.near;let t=e*Math.tan(ns*.5*this.fov)/this.zoom,n=2*t,i=this.aspect*n,r=-.5*i;const o=this.view;if(this.view!==null&&this.view.enabled){const l=o.fullWidth,c=o.fullHeight;r+=o.offsetX*i/l,t-=o.offsetY*n/c,i*=o.width/l,n*=o.height/c}const a=this.filmOffset;a!==0&&(r+=e*a/this.getFilmWidth()),this.projectionMatrix.makePerspective(r,r+i,t,t-n,e,this.far,this.coordinateSystem),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(e){const t=super.toJSON(e);return t.object.fov=this.fov,t.object.zoom=this.zoom,t.object.near=this.near,t.object.far=this.far,t.object.focus=this.focus,t.object.aspect=this.aspect,this.view!==null&&(t.object.view=Object.assign({},this.view)),t.object.filmGauge=this.filmGauge,t.object.filmOffset=this.filmOffset,t}}const As=-90,Ts=1;class hp extends ct{constructor(e,t,n){super(),this.type="CubeCamera",this.renderTarget=n,this.coordinateSystem=null,this.activeMipmapLevel=0;const i=new Ut(As,Ts,e,t);i.layers=this.layers,this.add(i);const r=new Ut(As,Ts,e,t);r.layers=this.layers,this.add(r);const o=new Ut(As,Ts,e,t);o.layers=this.layers,this.add(o);const a=new Ut(As,Ts,e,t);a.layers=this.layers,this.add(a);const l=new Ut(As,Ts,e,t);l.layers=this.layers,this.add(l);const c=new Ut(As,Ts,e,t);c.layers=this.layers,this.add(c)}updateCoordinateSystem(){const e=this.coordinateSystem,t=this.children.concat(),[n,i,r,o,a,l]=t;for(const c of t)this.remove(c);if(e===Vn)n.up.set(0,1,0),n.lookAt(1,0,0),i.up.set(0,1,0),i.lookAt(-1,0,0),r.up.set(0,0,-1),r.lookAt(0,1,0),o.up.set(0,0,1),o.lookAt(0,-1,0),a.up.set(0,1,0),a.lookAt(0,0,1),l.up.set(0,1,0),l.lookAt(0,0,-1);else if(e===Rr)n.up.set(0,-1,0),n.lookAt(-1,0,0),i.up.set(0,-1,0),i.lookAt(1,0,0),r.up.set(0,0,1),r.lookAt(0,1,0),o.up.set(0,0,-1),o.lookAt(0,-1,0),a.up.set(0,-1,0),a.lookAt(0,0,1),l.up.set(0,-1,0),l.lookAt(0,0,-1);else throw new Error("THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: "+e);for(const c of t)this.add(c),c.updateMatrixWorld()}update(e,t){this.parent===null&&this.updateMatrixWorld();const{renderTarget:n,activeMipmapLevel:i}=this;this.coordinateSystem!==e.coordinateSystem&&(this.coordinateSystem=e.coordinateSystem,this.updateCoordinateSystem());const[r,o,a,l,c,u]=this.children,h=e.getRenderTarget(),d=e.getActiveCubeFace(),f=e.getActiveMipmapLevel(),g=e.xr.enabled;e.xr.enabled=!1;const v=n.texture.generateMipmaps;n.texture.generateMipmaps=!1,e.setRenderTarget(n,0,i),e.render(t,r),e.setRenderTarget(n,1,i),e.render(t,o),e.setRenderTarget(n,2,i),e.render(t,a),e.setRenderTarget(n,3,i),e.render(t,l),e.setRenderTarget(n,4,i),e.render(t,c),n.texture.generateMipmaps=v,e.setRenderTarget(n,5,i),e.render(t,u),e.setRenderTarget(h,d,f),e.xr.enabled=g,n.texture.needsPMREMUpdate=!0}}class qr extends Pt{constructor(e,t,n,i,r,o,a,l,c,u){e=e!==void 0?e:[],t=t!==void 0?t:ai,super(e,t,n,i,r,o,a,l,c,u),this.isCubeTexture=!0,this.flipY=!1}get images(){return this.image}set images(e){this.image=e}}class dp extends In{constructor(e=1,t={}){super(e,e,t),this.isWebGLCubeRenderTarget=!0;const n={width:e,height:e,depth:1},i=[n,n,n,n,n,n];this.texture=new qr(i,t.mapping,t.wrapS,t.wrapT,t.magFilter,t.minFilter,t.format,t.type,t.anisotropy,t.colorSpace),this.texture.isRenderTargetTexture=!0,this.texture.generateMipmaps=t.generateMipmaps!==void 0?t.generateMipmaps:!1,this.texture.minFilter=t.minFilter!==void 0?t.minFilter:Ot}fromEquirectangularTexture(e,t){this.texture.type=t.type,this.texture.colorSpace=t.colorSpace,this.texture.generateMipmaps=t.generateMipmaps,this.texture.minFilter=t.minFilter,this.texture.magFilter=t.magFilter;const n={uniforms:{tEquirect:{value:null}},vertexShader:` + + varying vec3 vWorldDirection; + + vec3 transformDirection( in vec3 dir, in mat4 matrix ) { + + return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); + + } + + void main() { + + vWorldDirection = transformDirection( position, modelMatrix ); + + #include + #include + + } + `,fragmentShader:` + + uniform sampler2D tEquirect; + + varying vec3 vWorldDirection; + + #include + + void main() { + + vec3 direction = normalize( vWorldDirection ); + + vec2 sampleUV = equirectUv( direction ); + + gl_FragColor = texture2D( tEquirect, sampleUV ); + + } + `},i=new cs(5,5,5),r=new Ln({name:"CubemapFromEquirect",uniforms:Hs(n.uniforms),vertexShader:n.vertexShader,fragmentShader:n.fragmentShader,side:nn,blending:si});r.uniforms.tEquirect.value=t;const o=new Nt(i,r),a=t.minFilter;return t.minFilter===zn&&(t.minFilter=Ot),new hp(1,10,this).update(e,o),t.minFilter=a,o.geometry.dispose(),o.material.dispose(),this}clear(e,t,n,i){const r=e.getRenderTarget();for(let o=0;o<6;o++)e.setRenderTarget(this,o),e.clear(t,n,i);e.setRenderTarget(r)}}const Tl=new N,Iv=new N,Lv=new Ze;class wi{constructor(e=new N(1,0,0),t=0){this.isPlane=!0,this.normal=e,this.constant=t}set(e,t){return this.normal.copy(e),this.constant=t,this}setComponents(e,t,n,i){return this.normal.set(e,t,n),this.constant=i,this}setFromNormalAndCoplanarPoint(e,t){return this.normal.copy(e),this.constant=-t.dot(this.normal),this}setFromCoplanarPoints(e,t,n){const i=Tl.subVectors(n,t).cross(Iv.subVectors(e,t)).normalize();return this.setFromNormalAndCoplanarPoint(i,e),this}copy(e){return this.normal.copy(e.normal),this.constant=e.constant,this}normalize(){const e=1/this.normal.length();return this.normal.multiplyScalar(e),this.constant*=e,this}negate(){return this.constant*=-1,this.normal.negate(),this}distanceToPoint(e){return this.normal.dot(e)+this.constant}distanceToSphere(e){return this.distanceToPoint(e.center)-e.radius}projectPoint(e,t){return t.copy(e).addScaledVector(this.normal,-this.distanceToPoint(e))}intersectLine(e,t){const n=e.delta(Tl),i=this.normal.dot(n);if(i===0)return this.distanceToPoint(e.start)===0?t.copy(e.start):null;const r=-(e.start.dot(this.normal)+this.constant)/i;return r<0||r>1?null:t.copy(e.start).addScaledVector(n,r)}intersectsLine(e){const t=this.distanceToPoint(e.start),n=this.distanceToPoint(e.end);return t<0&&n>0||n<0&&t>0}intersectsBox(e){return e.intersectsPlane(this)}intersectsSphere(e){return e.intersectsPlane(this)}coplanarPoint(e){return e.copy(this.normal).multiplyScalar(-this.constant)}applyMatrix4(e,t){const n=t||Lv.getNormalMatrix(e),i=this.coplanarPoint(Tl).applyMatrix4(e),r=this.normal.applyMatrix3(n).normalize();return this.constant=-i.dot(r),this}translate(e){return this.constant-=e.dot(this.normal),this}equals(e){return e.normal.equals(this.normal)&&e.constant===this.constant}clone(){return new this.constructor().copy(this)}}const Bi=new Zt,Ao=new N;class Yr{constructor(e=new wi,t=new wi,n=new wi,i=new wi,r=new wi,o=new wi){this.planes=[e,t,n,i,r,o]}set(e,t,n,i,r,o){const a=this.planes;return a[0].copy(e),a[1].copy(t),a[2].copy(n),a[3].copy(i),a[4].copy(r),a[5].copy(o),this}copy(e){const t=this.planes;for(let n=0;n<6;n++)t[n].copy(e.planes[n]);return this}setFromProjectionMatrix(e,t=Vn){const n=this.planes,i=e.elements,r=i[0],o=i[1],a=i[2],l=i[3],c=i[4],u=i[5],h=i[6],d=i[7],f=i[8],g=i[9],v=i[10],m=i[11],p=i[12],y=i[13],_=i[14],x=i[15];if(n[0].setComponents(l-r,d-c,m-f,x-p).normalize(),n[1].setComponents(l+r,d+c,m+f,x+p).normalize(),n[2].setComponents(l+o,d+u,m+g,x+y).normalize(),n[3].setComponents(l-o,d-u,m-g,x-y).normalize(),n[4].setComponents(l-a,d-h,m-v,x-_).normalize(),t===Vn)n[5].setComponents(l+a,d+h,m+v,x+_).normalize();else if(t===Rr)n[5].setComponents(a,h,v,_).normalize();else throw new Error("THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: "+t);return this}intersectsObject(e){if(e.boundingSphere!==void 0)e.boundingSphere===null&&e.computeBoundingSphere(),Bi.copy(e.boundingSphere).applyMatrix4(e.matrixWorld);else{const t=e.geometry;t.boundingSphere===null&&t.computeBoundingSphere(),Bi.copy(t.boundingSphere).applyMatrix4(e.matrixWorld)}return this.intersectsSphere(Bi)}intersectsSprite(e){return Bi.center.set(0,0,0),Bi.radius=.7071067811865476,Bi.applyMatrix4(e.matrixWorld),this.intersectsSphere(Bi)}intersectsSphere(e){const t=this.planes,n=e.center,i=-e.radius;for(let r=0;r<6;r++)if(t[r].distanceToPoint(n)0?e.max.x:e.min.x,Ao.y=i.normal.y>0?e.max.y:e.min.y,Ao.z=i.normal.z>0?e.max.z:e.min.z,i.distanceToPoint(Ao)<0)return!1}return!0}containsPoint(e){const t=this.planes;for(let n=0;n<6;n++)if(t[n].distanceToPoint(e)<0)return!1;return!0}clone(){return new this.constructor().copy(this)}}function fp(){let s=null,e=!1,t=null,n=null;function i(r,o){t(r,o),n=s.requestAnimationFrame(i)}return{start:function(){e!==!0&&t!==null&&(n=s.requestAnimationFrame(i),e=!0)},stop:function(){s.cancelAnimationFrame(n),e=!1},setAnimationLoop:function(r){t=r},setContext:function(r){s=r}}}function Nv(s){const e=new WeakMap;function t(a,l){const c=a.array,u=a.usage,h=c.byteLength,d=s.createBuffer();s.bindBuffer(l,d),s.bufferData(l,c,u),a.onUploadCallback();let f;if(c instanceof Float32Array)f=s.FLOAT;else if(c instanceof Uint16Array)a.isFloat16BufferAttribute?f=s.HALF_FLOAT:f=s.UNSIGNED_SHORT;else if(c instanceof Int16Array)f=s.SHORT;else if(c instanceof Uint32Array)f=s.UNSIGNED_INT;else if(c instanceof Int32Array)f=s.INT;else if(c instanceof Int8Array)f=s.BYTE;else if(c instanceof Uint8Array)f=s.UNSIGNED_BYTE;else if(c instanceof Uint8ClampedArray)f=s.UNSIGNED_BYTE;else throw new Error("THREE.WebGLAttributes: Unsupported buffer data format: "+c);return{buffer:d,type:f,bytesPerElement:c.BYTES_PER_ELEMENT,version:a.version,size:h}}function n(a,l,c){const u=l.array,h=l._updateRange,d=l.updateRanges;if(s.bindBuffer(c,a),h.count===-1&&d.length===0&&s.bufferSubData(c,0,u),d.length!==0){for(let f=0,g=d.length;f 0 + vec4 plane; + #ifdef ALPHA_TO_COVERAGE + float distanceToPlane, distanceGradient; + float clipOpacity = 1.0; + #pragma unroll_loop_start + for ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) { + plane = clippingPlanes[ i ]; + distanceToPlane = - dot( vClipPosition, plane.xyz ) + plane.w; + distanceGradient = fwidth( distanceToPlane ) / 2.0; + clipOpacity *= smoothstep( - distanceGradient, distanceGradient, distanceToPlane ); + if ( clipOpacity == 0.0 ) discard; + } + #pragma unroll_loop_end + #if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES + float unionClipOpacity = 1.0; + #pragma unroll_loop_start + for ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) { + plane = clippingPlanes[ i ]; + distanceToPlane = - dot( vClipPosition, plane.xyz ) + plane.w; + distanceGradient = fwidth( distanceToPlane ) / 2.0; + unionClipOpacity *= 1.0 - smoothstep( - distanceGradient, distanceGradient, distanceToPlane ); + } + #pragma unroll_loop_end + clipOpacity *= 1.0 - unionClipOpacity; + #endif + diffuseColor.a *= clipOpacity; + if ( diffuseColor.a == 0.0 ) discard; + #else + #pragma unroll_loop_start + for ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) { + plane = clippingPlanes[ i ]; + if ( dot( vClipPosition, plane.xyz ) > plane.w ) discard; + } + #pragma unroll_loop_end + #if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES + bool clipped = true; + #pragma unroll_loop_start + for ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) { + plane = clippingPlanes[ i ]; + clipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped; + } + #pragma unroll_loop_end + if ( clipped ) discard; + #endif + #endif +#endif`,Jv=`#if NUM_CLIPPING_PLANES > 0 + varying vec3 vClipPosition; + uniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ]; +#endif`,Kv=`#if NUM_CLIPPING_PLANES > 0 + varying vec3 vClipPosition; +#endif`,jv=`#if NUM_CLIPPING_PLANES > 0 + vClipPosition = - mvPosition.xyz; +#endif`,Qv=`#if defined( USE_COLOR_ALPHA ) + diffuseColor *= vColor; +#elif defined( USE_COLOR ) + diffuseColor.rgb *= vColor; +#endif`,e_=`#if defined( USE_COLOR_ALPHA ) + varying vec4 vColor; +#elif defined( USE_COLOR ) + varying vec3 vColor; +#endif`,t_=`#if defined( USE_COLOR_ALPHA ) + varying vec4 vColor; +#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR ) + varying vec3 vColor; +#endif`,n_=`#if defined( USE_COLOR_ALPHA ) + vColor = vec4( 1.0 ); +#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR ) + vColor = vec3( 1.0 ); +#endif +#ifdef USE_COLOR + vColor *= color; +#endif +#ifdef USE_INSTANCING_COLOR + vColor.xyz *= instanceColor.xyz; +#endif +#ifdef USE_BATCHING_COLOR + vec3 batchingColor = getBatchingColor( batchId ); + vColor.xyz *= batchingColor.xyz; +#endif`,i_=`#define PI 3.141592653589793 +#define PI2 6.283185307179586 +#define PI_HALF 1.5707963267948966 +#define RECIPROCAL_PI 0.3183098861837907 +#define RECIPROCAL_PI2 0.15915494309189535 +#define EPSILON 1e-6 +#ifndef saturate +#define saturate( a ) clamp( a, 0.0, 1.0 ) +#endif +#define whiteComplement( a ) ( 1.0 - saturate( a ) ) +float pow2( const in float x ) { return x*x; } +vec3 pow2( const in vec3 x ) { return x*x; } +float pow3( const in float x ) { return x*x*x; } +float pow4( const in float x ) { float x2 = x*x; return x2*x2; } +float max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); } +float average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); } +highp float rand( const in vec2 uv ) { + const highp float a = 12.9898, b = 78.233, c = 43758.5453; + highp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI ); + return fract( sin( sn ) * c ); +} +#ifdef HIGH_PRECISION + float precisionSafeLength( vec3 v ) { return length( v ); } +#else + float precisionSafeLength( vec3 v ) { + float maxComponent = max3( abs( v ) ); + return length( v / maxComponent ) * maxComponent; + } +#endif +struct IncidentLight { + vec3 color; + vec3 direction; + bool visible; +}; +struct ReflectedLight { + vec3 directDiffuse; + vec3 directSpecular; + vec3 indirectDiffuse; + vec3 indirectSpecular; +}; +#ifdef USE_ALPHAHASH + varying vec3 vPosition; +#endif +vec3 transformDirection( in vec3 dir, in mat4 matrix ) { + return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); +} +vec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) { + return normalize( ( vec4( dir, 0.0 ) * matrix ).xyz ); +} +mat3 transposeMat3( const in mat3 m ) { + mat3 tmp; + tmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x ); + tmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y ); + tmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z ); + return tmp; +} +float luminance( const in vec3 rgb ) { + const vec3 weights = vec3( 0.2126729, 0.7151522, 0.0721750 ); + return dot( weights, rgb ); +} +bool isPerspectiveMatrix( mat4 m ) { + return m[ 2 ][ 3 ] == - 1.0; +} +vec2 equirectUv( in vec3 dir ) { + float u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5; + float v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5; + return vec2( u, v ); +} +vec3 BRDF_Lambert( const in vec3 diffuseColor ) { + return RECIPROCAL_PI * diffuseColor; +} +vec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) { + float fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH ); + return f0 * ( 1.0 - fresnel ) + ( f90 * fresnel ); +} +float F_Schlick( const in float f0, const in float f90, const in float dotVH ) { + float fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH ); + return f0 * ( 1.0 - fresnel ) + ( f90 * fresnel ); +} // validated`,s_=`#ifdef ENVMAP_TYPE_CUBE_UV + #define cubeUV_minMipLevel 4.0 + #define cubeUV_minTileSize 16.0 + float getFace( vec3 direction ) { + vec3 absDirection = abs( direction ); + float face = - 1.0; + if ( absDirection.x > absDirection.z ) { + if ( absDirection.x > absDirection.y ) + face = direction.x > 0.0 ? 0.0 : 3.0; + else + face = direction.y > 0.0 ? 1.0 : 4.0; + } else { + if ( absDirection.z > absDirection.y ) + face = direction.z > 0.0 ? 2.0 : 5.0; + else + face = direction.y > 0.0 ? 1.0 : 4.0; + } + return face; + } + vec2 getUV( vec3 direction, float face ) { + vec2 uv; + if ( face == 0.0 ) { + uv = vec2( direction.z, direction.y ) / abs( direction.x ); + } else if ( face == 1.0 ) { + uv = vec2( - direction.x, - direction.z ) / abs( direction.y ); + } else if ( face == 2.0 ) { + uv = vec2( - direction.x, direction.y ) / abs( direction.z ); + } else if ( face == 3.0 ) { + uv = vec2( - direction.z, direction.y ) / abs( direction.x ); + } else if ( face == 4.0 ) { + uv = vec2( - direction.x, direction.z ) / abs( direction.y ); + } else { + uv = vec2( direction.x, direction.y ) / abs( direction.z ); + } + return 0.5 * ( uv + 1.0 ); + } + vec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) { + float face = getFace( direction ); + float filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 ); + mipInt = max( mipInt, cubeUV_minMipLevel ); + float faceSize = exp2( mipInt ); + highp vec2 uv = getUV( direction, face ) * ( faceSize - 2.0 ) + 1.0; + if ( face > 2.0 ) { + uv.y += faceSize; + face -= 3.0; + } + uv.x += face * faceSize; + uv.x += filterInt * 3.0 * cubeUV_minTileSize; + uv.y += 4.0 * ( exp2( CUBEUV_MAX_MIP ) - faceSize ); + uv.x *= CUBEUV_TEXEL_WIDTH; + uv.y *= CUBEUV_TEXEL_HEIGHT; + #ifdef texture2DGradEXT + return texture2DGradEXT( envMap, uv, vec2( 0.0 ), vec2( 0.0 ) ).rgb; + #else + return texture2D( envMap, uv ).rgb; + #endif + } + #define cubeUV_r0 1.0 + #define cubeUV_m0 - 2.0 + #define cubeUV_r1 0.8 + #define cubeUV_m1 - 1.0 + #define cubeUV_r4 0.4 + #define cubeUV_m4 2.0 + #define cubeUV_r5 0.305 + #define cubeUV_m5 3.0 + #define cubeUV_r6 0.21 + #define cubeUV_m6 4.0 + float roughnessToMip( float roughness ) { + float mip = 0.0; + if ( roughness >= cubeUV_r1 ) { + mip = ( cubeUV_r0 - roughness ) * ( cubeUV_m1 - cubeUV_m0 ) / ( cubeUV_r0 - cubeUV_r1 ) + cubeUV_m0; + } else if ( roughness >= cubeUV_r4 ) { + mip = ( cubeUV_r1 - roughness ) * ( cubeUV_m4 - cubeUV_m1 ) / ( cubeUV_r1 - cubeUV_r4 ) + cubeUV_m1; + } else if ( roughness >= cubeUV_r5 ) { + mip = ( cubeUV_r4 - roughness ) * ( cubeUV_m5 - cubeUV_m4 ) / ( cubeUV_r4 - cubeUV_r5 ) + cubeUV_m4; + } else if ( roughness >= cubeUV_r6 ) { + mip = ( cubeUV_r5 - roughness ) * ( cubeUV_m6 - cubeUV_m5 ) / ( cubeUV_r5 - cubeUV_r6 ) + cubeUV_m5; + } else { + mip = - 2.0 * log2( 1.16 * roughness ); } + return mip; + } + vec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) { + float mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP ); + float mipF = fract( mip ); + float mipInt = floor( mip ); + vec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt ); + if ( mipF == 0.0 ) { + return vec4( color0, 1.0 ); + } else { + vec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 ); + return vec4( mix( color0, color1, mipF ), 1.0 ); + } + } +#endif`,r_=`vec3 transformedNormal = objectNormal; +#ifdef USE_TANGENT + vec3 transformedTangent = objectTangent; +#endif +#ifdef USE_BATCHING + mat3 bm = mat3( batchingMatrix ); + transformedNormal /= vec3( dot( bm[ 0 ], bm[ 0 ] ), dot( bm[ 1 ], bm[ 1 ] ), dot( bm[ 2 ], bm[ 2 ] ) ); + transformedNormal = bm * transformedNormal; + #ifdef USE_TANGENT + transformedTangent = bm * transformedTangent; + #endif +#endif +#ifdef USE_INSTANCING + mat3 im = mat3( instanceMatrix ); + transformedNormal /= vec3( dot( im[ 0 ], im[ 0 ] ), dot( im[ 1 ], im[ 1 ] ), dot( im[ 2 ], im[ 2 ] ) ); + transformedNormal = im * transformedNormal; + #ifdef USE_TANGENT + transformedTangent = im * transformedTangent; + #endif +#endif +transformedNormal = normalMatrix * transformedNormal; +#ifdef FLIP_SIDED + transformedNormal = - transformedNormal; +#endif +#ifdef USE_TANGENT + transformedTangent = ( modelViewMatrix * vec4( transformedTangent, 0.0 ) ).xyz; + #ifdef FLIP_SIDED + transformedTangent = - transformedTangent; + #endif +#endif`,o_=`#ifdef USE_DISPLACEMENTMAP + uniform sampler2D displacementMap; + uniform float displacementScale; + uniform float displacementBias; +#endif`,a_=`#ifdef USE_DISPLACEMENTMAP + transformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias ); +#endif`,l_=`#ifdef USE_EMISSIVEMAP + vec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv ); + totalEmissiveRadiance *= emissiveColor.rgb; +#endif`,c_=`#ifdef USE_EMISSIVEMAP + uniform sampler2D emissiveMap; +#endif`,u_="gl_FragColor = linearToOutputTexel( gl_FragColor );",h_=` +const mat3 LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = mat3( + vec3( 0.8224621, 0.177538, 0.0 ), + vec3( 0.0331941, 0.9668058, 0.0 ), + vec3( 0.0170827, 0.0723974, 0.9105199 ) +); +const mat3 LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = mat3( + vec3( 1.2249401, - 0.2249404, 0.0 ), + vec3( - 0.0420569, 1.0420571, 0.0 ), + vec3( - 0.0196376, - 0.0786361, 1.0982735 ) +); +vec4 LinearSRGBToLinearDisplayP3( in vec4 value ) { + return vec4( value.rgb * LINEAR_SRGB_TO_LINEAR_DISPLAY_P3, value.a ); +} +vec4 LinearDisplayP3ToLinearSRGB( in vec4 value ) { + return vec4( value.rgb * LINEAR_DISPLAY_P3_TO_LINEAR_SRGB, value.a ); +} +vec4 LinearTransferOETF( in vec4 value ) { + return value; +} +vec4 sRGBTransferOETF( in vec4 value ) { + return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a ); +} +vec4 LinearToLinear( in vec4 value ) { + return value; +} +vec4 LinearTosRGB( in vec4 value ) { + return sRGBTransferOETF( value ); +}`,d_=`#ifdef USE_ENVMAP + #ifdef ENV_WORLDPOS + vec3 cameraToFrag; + if ( isOrthographic ) { + cameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) ); + } else { + cameraToFrag = normalize( vWorldPosition - cameraPosition ); + } + vec3 worldNormal = inverseTransformDirection( normal, viewMatrix ); + #ifdef ENVMAP_MODE_REFLECTION + vec3 reflectVec = reflect( cameraToFrag, worldNormal ); + #else + vec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio ); + #endif + #else + vec3 reflectVec = vReflect; + #endif + #ifdef ENVMAP_TYPE_CUBE + vec4 envColor = textureCube( envMap, envMapRotation * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) ); + #else + vec4 envColor = vec4( 0.0 ); + #endif + #ifdef ENVMAP_BLENDING_MULTIPLY + outgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity ); + #elif defined( ENVMAP_BLENDING_MIX ) + outgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity ); + #elif defined( ENVMAP_BLENDING_ADD ) + outgoingLight += envColor.xyz * specularStrength * reflectivity; + #endif +#endif`,f_=`#ifdef USE_ENVMAP + uniform float envMapIntensity; + uniform float flipEnvMap; + uniform mat3 envMapRotation; + #ifdef ENVMAP_TYPE_CUBE + uniform samplerCube envMap; + #else + uniform sampler2D envMap; + #endif + +#endif`,p_=`#ifdef USE_ENVMAP + uniform float reflectivity; + #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT ) + #define ENV_WORLDPOS + #endif + #ifdef ENV_WORLDPOS + varying vec3 vWorldPosition; + uniform float refractionRatio; + #else + varying vec3 vReflect; + #endif +#endif`,m_=`#ifdef USE_ENVMAP + #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT ) + #define ENV_WORLDPOS + #endif + #ifdef ENV_WORLDPOS + + varying vec3 vWorldPosition; + #else + varying vec3 vReflect; + uniform float refractionRatio; + #endif +#endif`,g_=`#ifdef USE_ENVMAP + #ifdef ENV_WORLDPOS + vWorldPosition = worldPosition.xyz; + #else + vec3 cameraToVertex; + if ( isOrthographic ) { + cameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) ); + } else { + cameraToVertex = normalize( worldPosition.xyz - cameraPosition ); + } + vec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix ); + #ifdef ENVMAP_MODE_REFLECTION + vReflect = reflect( cameraToVertex, worldNormal ); + #else + vReflect = refract( cameraToVertex, worldNormal, refractionRatio ); + #endif + #endif +#endif`,v_=`#ifdef USE_FOG + vFogDepth = - mvPosition.z; +#endif`,__=`#ifdef USE_FOG + varying float vFogDepth; +#endif`,y_=`#ifdef USE_FOG + #ifdef FOG_EXP2 + float fogFactor = 1.0 - exp( - fogDensity * fogDensity * vFogDepth * vFogDepth ); + #else + float fogFactor = smoothstep( fogNear, fogFar, vFogDepth ); + #endif + gl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor ); +#endif`,x_=`#ifdef USE_FOG + uniform vec3 fogColor; + varying float vFogDepth; + #ifdef FOG_EXP2 + uniform float fogDensity; + #else + uniform float fogNear; + uniform float fogFar; + #endif +#endif`,M_=`#ifdef USE_GRADIENTMAP + uniform sampler2D gradientMap; +#endif +vec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) { + float dotNL = dot( normal, lightDirection ); + vec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 ); + #ifdef USE_GRADIENTMAP + return vec3( texture2D( gradientMap, coord ).r ); + #else + vec2 fw = fwidth( coord ) * 0.5; + return mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( 0.7 - fw.x, 0.7 + fw.x, coord.x ) ); + #endif +}`,b_=`#ifdef USE_LIGHTMAP + uniform sampler2D lightMap; + uniform float lightMapIntensity; +#endif`,S_=`LambertMaterial material; +material.diffuseColor = diffuseColor.rgb; +material.specularStrength = specularStrength;`,w_=`varying vec3 vViewPosition; +struct LambertMaterial { + vec3 diffuseColor; + float specularStrength; +}; +void RE_Direct_Lambert( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) { + float dotNL = saturate( dot( geometryNormal, directLight.direction ) ); + vec3 irradiance = dotNL * directLight.color; + reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +void RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) { + reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +#define RE_Direct RE_Direct_Lambert +#define RE_IndirectDiffuse RE_IndirectDiffuse_Lambert`,A_=`uniform bool receiveShadow; +uniform vec3 ambientLightColor; +#if defined( USE_LIGHT_PROBES ) + uniform vec3 lightProbe[ 9 ]; +#endif +vec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) { + float x = normal.x, y = normal.y, z = normal.z; + vec3 result = shCoefficients[ 0 ] * 0.886227; + result += shCoefficients[ 1 ] * 2.0 * 0.511664 * y; + result += shCoefficients[ 2 ] * 2.0 * 0.511664 * z; + result += shCoefficients[ 3 ] * 2.0 * 0.511664 * x; + result += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y; + result += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z; + result += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 ); + result += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z; + result += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y ); + return result; +} +vec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) { + vec3 worldNormal = inverseTransformDirection( normal, viewMatrix ); + vec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe ); + return irradiance; +} +vec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) { + vec3 irradiance = ambientLightColor; + return irradiance; +} +float getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) { + float distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 ); + if ( cutoffDistance > 0.0 ) { + distanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) ); + } + return distanceFalloff; +} +float getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) { + return smoothstep( coneCosine, penumbraCosine, angleCosine ); +} +#if NUM_DIR_LIGHTS > 0 + struct DirectionalLight { + vec3 direction; + vec3 color; + }; + uniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ]; + void getDirectionalLightInfo( const in DirectionalLight directionalLight, out IncidentLight light ) { + light.color = directionalLight.color; + light.direction = directionalLight.direction; + light.visible = true; + } +#endif +#if NUM_POINT_LIGHTS > 0 + struct PointLight { + vec3 position; + vec3 color; + float distance; + float decay; + }; + uniform PointLight pointLights[ NUM_POINT_LIGHTS ]; + void getPointLightInfo( const in PointLight pointLight, const in vec3 geometryPosition, out IncidentLight light ) { + vec3 lVector = pointLight.position - geometryPosition; + light.direction = normalize( lVector ); + float lightDistance = length( lVector ); + light.color = pointLight.color; + light.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay ); + light.visible = ( light.color != vec3( 0.0 ) ); + } +#endif +#if NUM_SPOT_LIGHTS > 0 + struct SpotLight { + vec3 position; + vec3 direction; + vec3 color; + float distance; + float decay; + float coneCos; + float penumbraCos; + }; + uniform SpotLight spotLights[ NUM_SPOT_LIGHTS ]; + void getSpotLightInfo( const in SpotLight spotLight, const in vec3 geometryPosition, out IncidentLight light ) { + vec3 lVector = spotLight.position - geometryPosition; + light.direction = normalize( lVector ); + float angleCos = dot( light.direction, spotLight.direction ); + float spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos ); + if ( spotAttenuation > 0.0 ) { + float lightDistance = length( lVector ); + light.color = spotLight.color * spotAttenuation; + light.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay ); + light.visible = ( light.color != vec3( 0.0 ) ); + } else { + light.color = vec3( 0.0 ); + light.visible = false; + } + } +#endif +#if NUM_RECT_AREA_LIGHTS > 0 + struct RectAreaLight { + vec3 color; + vec3 position; + vec3 halfWidth; + vec3 halfHeight; + }; + uniform sampler2D ltc_1; uniform sampler2D ltc_2; + uniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ]; +#endif +#if NUM_HEMI_LIGHTS > 0 + struct HemisphereLight { + vec3 direction; + vec3 skyColor; + vec3 groundColor; + }; + uniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ]; + vec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) { + float dotNL = dot( normal, hemiLight.direction ); + float hemiDiffuseWeight = 0.5 * dotNL + 0.5; + vec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight ); + return irradiance; + } +#endif`,T_=`#ifdef USE_ENVMAP + vec3 getIBLIrradiance( const in vec3 normal ) { + #ifdef ENVMAP_TYPE_CUBE_UV + vec3 worldNormal = inverseTransformDirection( normal, viewMatrix ); + vec4 envMapColor = textureCubeUV( envMap, envMapRotation * worldNormal, 1.0 ); + return PI * envMapColor.rgb * envMapIntensity; + #else + return vec3( 0.0 ); + #endif + } + vec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) { + #ifdef ENVMAP_TYPE_CUBE_UV + vec3 reflectVec = reflect( - viewDir, normal ); + reflectVec = normalize( mix( reflectVec, normal, roughness * roughness) ); + reflectVec = inverseTransformDirection( reflectVec, viewMatrix ); + vec4 envMapColor = textureCubeUV( envMap, envMapRotation * reflectVec, roughness ); + return envMapColor.rgb * envMapIntensity; + #else + return vec3( 0.0 ); + #endif + } + #ifdef USE_ANISOTROPY + vec3 getIBLAnisotropyRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in vec3 bitangent, const in float anisotropy ) { + #ifdef ENVMAP_TYPE_CUBE_UV + vec3 bentNormal = cross( bitangent, viewDir ); + bentNormal = normalize( cross( bentNormal, bitangent ) ); + bentNormal = normalize( mix( bentNormal, normal, pow2( pow2( 1.0 - anisotropy * ( 1.0 - roughness ) ) ) ) ); + return getIBLRadiance( viewDir, bentNormal, roughness ); + #else + return vec3( 0.0 ); + #endif + } + #endif +#endif`,E_=`ToonMaterial material; +material.diffuseColor = diffuseColor.rgb;`,C_=`varying vec3 vViewPosition; +struct ToonMaterial { + vec3 diffuseColor; +}; +void RE_Direct_Toon( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) { + vec3 irradiance = getGradientIrradiance( geometryNormal, directLight.direction ) * directLight.color; + reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +void RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) { + reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +#define RE_Direct RE_Direct_Toon +#define RE_IndirectDiffuse RE_IndirectDiffuse_Toon`,P_=`BlinnPhongMaterial material; +material.diffuseColor = diffuseColor.rgb; +material.specularColor = specular; +material.specularShininess = shininess; +material.specularStrength = specularStrength;`,R_=`varying vec3 vViewPosition; +struct BlinnPhongMaterial { + vec3 diffuseColor; + vec3 specularColor; + float specularShininess; + float specularStrength; +}; +void RE_Direct_BlinnPhong( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) { + float dotNL = saturate( dot( geometryNormal, directLight.direction ) ); + vec3 irradiance = dotNL * directLight.color; + reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); + reflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometryViewDir, geometryNormal, material.specularColor, material.specularShininess ) * material.specularStrength; +} +void RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) { + reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +#define RE_Direct RE_Direct_BlinnPhong +#define RE_IndirectDiffuse RE_IndirectDiffuse_BlinnPhong`,I_=`PhysicalMaterial material; +material.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor ); +vec3 dxy = max( abs( dFdx( nonPerturbedNormal ) ), abs( dFdy( nonPerturbedNormal ) ) ); +float geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z ); +material.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness; +material.roughness = min( material.roughness, 1.0 ); +#ifdef IOR + material.ior = ior; + #ifdef USE_SPECULAR + float specularIntensityFactor = specularIntensity; + vec3 specularColorFactor = specularColor; + #ifdef USE_SPECULAR_COLORMAP + specularColorFactor *= texture2D( specularColorMap, vSpecularColorMapUv ).rgb; + #endif + #ifdef USE_SPECULAR_INTENSITYMAP + specularIntensityFactor *= texture2D( specularIntensityMap, vSpecularIntensityMapUv ).a; + #endif + material.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor ); + #else + float specularIntensityFactor = 1.0; + vec3 specularColorFactor = vec3( 1.0 ); + material.specularF90 = 1.0; + #endif + material.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor ); +#else + material.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor ); + material.specularF90 = 1.0; +#endif +#ifdef USE_CLEARCOAT + material.clearcoat = clearcoat; + material.clearcoatRoughness = clearcoatRoughness; + material.clearcoatF0 = vec3( 0.04 ); + material.clearcoatF90 = 1.0; + #ifdef USE_CLEARCOATMAP + material.clearcoat *= texture2D( clearcoatMap, vClearcoatMapUv ).x; + #endif + #ifdef USE_CLEARCOAT_ROUGHNESSMAP + material.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vClearcoatRoughnessMapUv ).y; + #endif + material.clearcoat = saturate( material.clearcoat ); material.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 ); + material.clearcoatRoughness += geometryRoughness; + material.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 ); +#endif +#ifdef USE_DISPERSION + material.dispersion = dispersion; +#endif +#ifdef USE_IRIDESCENCE + material.iridescence = iridescence; + material.iridescenceIOR = iridescenceIOR; + #ifdef USE_IRIDESCENCEMAP + material.iridescence *= texture2D( iridescenceMap, vIridescenceMapUv ).r; + #endif + #ifdef USE_IRIDESCENCE_THICKNESSMAP + material.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vIridescenceThicknessMapUv ).g + iridescenceThicknessMinimum; + #else + material.iridescenceThickness = iridescenceThicknessMaximum; + #endif +#endif +#ifdef USE_SHEEN + material.sheenColor = sheenColor; + #ifdef USE_SHEEN_COLORMAP + material.sheenColor *= texture2D( sheenColorMap, vSheenColorMapUv ).rgb; + #endif + material.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 ); + #ifdef USE_SHEEN_ROUGHNESSMAP + material.sheenRoughness *= texture2D( sheenRoughnessMap, vSheenRoughnessMapUv ).a; + #endif +#endif +#ifdef USE_ANISOTROPY + #ifdef USE_ANISOTROPYMAP + mat2 anisotropyMat = mat2( anisotropyVector.x, anisotropyVector.y, - anisotropyVector.y, anisotropyVector.x ); + vec3 anisotropyPolar = texture2D( anisotropyMap, vAnisotropyMapUv ).rgb; + vec2 anisotropyV = anisotropyMat * normalize( 2.0 * anisotropyPolar.rg - vec2( 1.0 ) ) * anisotropyPolar.b; + #else + vec2 anisotropyV = anisotropyVector; + #endif + material.anisotropy = length( anisotropyV ); + if( material.anisotropy == 0.0 ) { + anisotropyV = vec2( 1.0, 0.0 ); + } else { + anisotropyV /= material.anisotropy; + material.anisotropy = saturate( material.anisotropy ); + } + material.alphaT = mix( pow2( material.roughness ), 1.0, pow2( material.anisotropy ) ); + material.anisotropyT = tbn[ 0 ] * anisotropyV.x + tbn[ 1 ] * anisotropyV.y; + material.anisotropyB = tbn[ 1 ] * anisotropyV.x - tbn[ 0 ] * anisotropyV.y; +#endif`,L_=`struct PhysicalMaterial { + vec3 diffuseColor; + float roughness; + vec3 specularColor; + float specularF90; + float dispersion; + #ifdef USE_CLEARCOAT + float clearcoat; + float clearcoatRoughness; + vec3 clearcoatF0; + float clearcoatF90; + #endif + #ifdef USE_IRIDESCENCE + float iridescence; + float iridescenceIOR; + float iridescenceThickness; + vec3 iridescenceFresnel; + vec3 iridescenceF0; + #endif + #ifdef USE_SHEEN + vec3 sheenColor; + float sheenRoughness; + #endif + #ifdef IOR + float ior; + #endif + #ifdef USE_TRANSMISSION + float transmission; + float transmissionAlpha; + float thickness; + float attenuationDistance; + vec3 attenuationColor; + #endif + #ifdef USE_ANISOTROPY + float anisotropy; + float alphaT; + vec3 anisotropyT; + vec3 anisotropyB; + #endif +}; +vec3 clearcoatSpecularDirect = vec3( 0.0 ); +vec3 clearcoatSpecularIndirect = vec3( 0.0 ); +vec3 sheenSpecularDirect = vec3( 0.0 ); +vec3 sheenSpecularIndirect = vec3(0.0 ); +vec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) { + float x = clamp( 1.0 - dotVH, 0.0, 1.0 ); + float x2 = x * x; + float x5 = clamp( x * x2 * x2, 0.0, 0.9999 ); + return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 ); +} +float V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) { + float a2 = pow2( alpha ); + float gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) ); + float gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) ); + return 0.5 / max( gv + gl, EPSILON ); +} +float D_GGX( const in float alpha, const in float dotNH ) { + float a2 = pow2( alpha ); + float denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0; + return RECIPROCAL_PI * a2 / pow2( denom ); +} +#ifdef USE_ANISOTROPY + float V_GGX_SmithCorrelated_Anisotropic( const in float alphaT, const in float alphaB, const in float dotTV, const in float dotBV, const in float dotTL, const in float dotBL, const in float dotNV, const in float dotNL ) { + float gv = dotNL * length( vec3( alphaT * dotTV, alphaB * dotBV, dotNV ) ); + float gl = dotNV * length( vec3( alphaT * dotTL, alphaB * dotBL, dotNL ) ); + float v = 0.5 / ( gv + gl ); + return saturate(v); + } + float D_GGX_Anisotropic( const in float alphaT, const in float alphaB, const in float dotNH, const in float dotTH, const in float dotBH ) { + float a2 = alphaT * alphaB; + highp vec3 v = vec3( alphaB * dotTH, alphaT * dotBH, a2 * dotNH ); + highp float v2 = dot( v, v ); + float w2 = a2 / v2; + return RECIPROCAL_PI * a2 * pow2 ( w2 ); + } +#endif +#ifdef USE_CLEARCOAT + vec3 BRDF_GGX_Clearcoat( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material) { + vec3 f0 = material.clearcoatF0; + float f90 = material.clearcoatF90; + float roughness = material.clearcoatRoughness; + float alpha = pow2( roughness ); + vec3 halfDir = normalize( lightDir + viewDir ); + float dotNL = saturate( dot( normal, lightDir ) ); + float dotNV = saturate( dot( normal, viewDir ) ); + float dotNH = saturate( dot( normal, halfDir ) ); + float dotVH = saturate( dot( viewDir, halfDir ) ); + vec3 F = F_Schlick( f0, f90, dotVH ); + float V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV ); + float D = D_GGX( alpha, dotNH ); + return F * ( V * D ); + } +#endif +vec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) { + vec3 f0 = material.specularColor; + float f90 = material.specularF90; + float roughness = material.roughness; + float alpha = pow2( roughness ); + vec3 halfDir = normalize( lightDir + viewDir ); + float dotNL = saturate( dot( normal, lightDir ) ); + float dotNV = saturate( dot( normal, viewDir ) ); + float dotNH = saturate( dot( normal, halfDir ) ); + float dotVH = saturate( dot( viewDir, halfDir ) ); + vec3 F = F_Schlick( f0, f90, dotVH ); + #ifdef USE_IRIDESCENCE + F = mix( F, material.iridescenceFresnel, material.iridescence ); + #endif + #ifdef USE_ANISOTROPY + float dotTL = dot( material.anisotropyT, lightDir ); + float dotTV = dot( material.anisotropyT, viewDir ); + float dotTH = dot( material.anisotropyT, halfDir ); + float dotBL = dot( material.anisotropyB, lightDir ); + float dotBV = dot( material.anisotropyB, viewDir ); + float dotBH = dot( material.anisotropyB, halfDir ); + float V = V_GGX_SmithCorrelated_Anisotropic( material.alphaT, alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL ); + float D = D_GGX_Anisotropic( material.alphaT, alpha, dotNH, dotTH, dotBH ); + #else + float V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV ); + float D = D_GGX( alpha, dotNH ); + #endif + return F * ( V * D ); +} +vec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) { + const float LUT_SIZE = 64.0; + const float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE; + const float LUT_BIAS = 0.5 / LUT_SIZE; + float dotNV = saturate( dot( N, V ) ); + vec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) ); + uv = uv * LUT_SCALE + LUT_BIAS; + return uv; +} +float LTC_ClippedSphereFormFactor( const in vec3 f ) { + float l = length( f ); + return max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 ); +} +vec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) { + float x = dot( v1, v2 ); + float y = abs( x ); + float a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y; + float b = 3.4175940 + ( 4.1616724 + y ) * y; + float v = a / b; + float theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v; + return cross( v1, v2 ) * theta_sintheta; +} +vec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) { + vec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ]; + vec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ]; + vec3 lightNormal = cross( v1, v2 ); + if( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 ); + vec3 T1, T2; + T1 = normalize( V - N * dot( V, N ) ); + T2 = - cross( N, T1 ); + mat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) ); + vec3 coords[ 4 ]; + coords[ 0 ] = mat * ( rectCoords[ 0 ] - P ); + coords[ 1 ] = mat * ( rectCoords[ 1 ] - P ); + coords[ 2 ] = mat * ( rectCoords[ 2 ] - P ); + coords[ 3 ] = mat * ( rectCoords[ 3 ] - P ); + coords[ 0 ] = normalize( coords[ 0 ] ); + coords[ 1 ] = normalize( coords[ 1 ] ); + coords[ 2 ] = normalize( coords[ 2 ] ); + coords[ 3 ] = normalize( coords[ 3 ] ); + vec3 vectorFormFactor = vec3( 0.0 ); + vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] ); + vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] ); + vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] ); + vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] ); + float result = LTC_ClippedSphereFormFactor( vectorFormFactor ); + return vec3( result ); +} +#if defined( USE_SHEEN ) +float D_Charlie( float roughness, float dotNH ) { + float alpha = pow2( roughness ); + float invAlpha = 1.0 / alpha; + float cos2h = dotNH * dotNH; + float sin2h = max( 1.0 - cos2h, 0.0078125 ); + return ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI ); +} +float V_Neubelt( float dotNV, float dotNL ) { + return saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) ); +} +vec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) { + vec3 halfDir = normalize( lightDir + viewDir ); + float dotNL = saturate( dot( normal, lightDir ) ); + float dotNV = saturate( dot( normal, viewDir ) ); + float dotNH = saturate( dot( normal, halfDir ) ); + float D = D_Charlie( sheenRoughness, dotNH ); + float V = V_Neubelt( dotNV, dotNL ); + return sheenColor * ( D * V ); +} +#endif +float IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) { + float dotNV = saturate( dot( normal, viewDir ) ); + float r2 = roughness * roughness; + float a = roughness < 0.25 ? -339.2 * r2 + 161.4 * roughness - 25.9 : -8.48 * r2 + 14.3 * roughness - 9.95; + float b = roughness < 0.25 ? 44.0 * r2 - 23.7 * roughness + 3.26 : 1.97 * r2 - 3.27 * roughness + 0.72; + float DG = exp( a * dotNV + b ) + ( roughness < 0.25 ? 0.0 : 0.1 * ( roughness - 0.25 ) ); + return saturate( DG * RECIPROCAL_PI ); +} +vec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) { + float dotNV = saturate( dot( normal, viewDir ) ); + const vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 ); + const vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 ); + vec4 r = roughness * c0 + c1; + float a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y; + vec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw; + return fab; +} +vec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) { + vec2 fab = DFGApprox( normal, viewDir, roughness ); + return specularColor * fab.x + specularF90 * fab.y; +} +#ifdef USE_IRIDESCENCE +void computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) { +#else +void computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) { +#endif + vec2 fab = DFGApprox( normal, viewDir, roughness ); + #ifdef USE_IRIDESCENCE + vec3 Fr = mix( specularColor, iridescenceF0, iridescence ); + #else + vec3 Fr = specularColor; + #endif + vec3 FssEss = Fr * fab.x + specularF90 * fab.y; + float Ess = fab.x + fab.y; + float Ems = 1.0 - Ess; + vec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619; vec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg ); + singleScatter += FssEss; + multiScatter += Fms * Ems; +} +#if NUM_RECT_AREA_LIGHTS > 0 + void RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { + vec3 normal = geometryNormal; + vec3 viewDir = geometryViewDir; + vec3 position = geometryPosition; + vec3 lightPos = rectAreaLight.position; + vec3 halfWidth = rectAreaLight.halfWidth; + vec3 halfHeight = rectAreaLight.halfHeight; + vec3 lightColor = rectAreaLight.color; + float roughness = material.roughness; + vec3 rectCoords[ 4 ]; + rectCoords[ 0 ] = lightPos + halfWidth - halfHeight; rectCoords[ 1 ] = lightPos - halfWidth - halfHeight; + rectCoords[ 2 ] = lightPos - halfWidth + halfHeight; + rectCoords[ 3 ] = lightPos + halfWidth + halfHeight; + vec2 uv = LTC_Uv( normal, viewDir, roughness ); + vec4 t1 = texture2D( ltc_1, uv ); + vec4 t2 = texture2D( ltc_2, uv ); + mat3 mInv = mat3( + vec3( t1.x, 0, t1.y ), + vec3( 0, 1, 0 ), + vec3( t1.z, 0, t1.w ) + ); + vec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y ); + reflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords ); + reflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords ); + } +#endif +void RE_Direct_Physical( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { + float dotNL = saturate( dot( geometryNormal, directLight.direction ) ); + vec3 irradiance = dotNL * directLight.color; + #ifdef USE_CLEARCOAT + float dotNLcc = saturate( dot( geometryClearcoatNormal, directLight.direction ) ); + vec3 ccIrradiance = dotNLcc * directLight.color; + clearcoatSpecularDirect += ccIrradiance * BRDF_GGX_Clearcoat( directLight.direction, geometryViewDir, geometryClearcoatNormal, material ); + #endif + #ifdef USE_SHEEN + sheenSpecularDirect += irradiance * BRDF_Sheen( directLight.direction, geometryViewDir, geometryNormal, material.sheenColor, material.sheenRoughness ); + #endif + reflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometryViewDir, geometryNormal, material ); + reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +void RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { + reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) { + #ifdef USE_CLEARCOAT + clearcoatSpecularIndirect += clearcoatRadiance * EnvironmentBRDF( geometryClearcoatNormal, geometryViewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness ); + #endif + #ifdef USE_SHEEN + sheenSpecularIndirect += irradiance * material.sheenColor * IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness ); + #endif + vec3 singleScattering = vec3( 0.0 ); + vec3 multiScattering = vec3( 0.0 ); + vec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI; + #ifdef USE_IRIDESCENCE + computeMultiscatteringIridescence( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness, singleScattering, multiScattering ); + #else + computeMultiscattering( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering ); + #endif + vec3 totalScattering = singleScattering + multiScattering; + vec3 diffuse = material.diffuseColor * ( 1.0 - max( max( totalScattering.r, totalScattering.g ), totalScattering.b ) ); + reflectedLight.indirectSpecular += radiance * singleScattering; + reflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance; + reflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance; +} +#define RE_Direct RE_Direct_Physical +#define RE_Direct_RectArea RE_Direct_RectArea_Physical +#define RE_IndirectDiffuse RE_IndirectDiffuse_Physical +#define RE_IndirectSpecular RE_IndirectSpecular_Physical +float computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) { + return saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion ); +}`,N_=` +vec3 geometryPosition = - vViewPosition; +vec3 geometryNormal = normal; +vec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition ); +vec3 geometryClearcoatNormal = vec3( 0.0 ); +#ifdef USE_CLEARCOAT + geometryClearcoatNormal = clearcoatNormal; +#endif +#ifdef USE_IRIDESCENCE + float dotNVi = saturate( dot( normal, geometryViewDir ) ); + if ( material.iridescenceThickness == 0.0 ) { + material.iridescence = 0.0; + } else { + material.iridescence = saturate( material.iridescence ); + } + if ( material.iridescence > 0.0 ) { + material.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor ); + material.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi ); + } +#endif +IncidentLight directLight; +#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct ) + PointLight pointLight; + #if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0 + PointLightShadow pointLightShadow; + #endif + #pragma unroll_loop_start + for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) { + pointLight = pointLights[ i ]; + getPointLightInfo( pointLight, geometryPosition, directLight ); + #if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS ) + pointLightShadow = pointLightShadows[ i ]; + directLight.color *= ( directLight.visible && receiveShadow ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0; + #endif + RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); + } + #pragma unroll_loop_end +#endif +#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct ) + SpotLight spotLight; + vec4 spotColor; + vec3 spotLightCoord; + bool inSpotLightMap; + #if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0 + SpotLightShadow spotLightShadow; + #endif + #pragma unroll_loop_start + for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) { + spotLight = spotLights[ i ]; + getSpotLightInfo( spotLight, geometryPosition, directLight ); + #if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS ) + #define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX + #elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS ) + #define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS + #else + #define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS ) + #endif + #if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS ) + spotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w; + inSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) ); + spotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy ); + directLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color; + #endif + #undef SPOT_LIGHT_MAP_INDEX + #if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS ) + spotLightShadow = spotLightShadows[ i ]; + directLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0; + #endif + RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); + } + #pragma unroll_loop_end +#endif +#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct ) + DirectionalLight directionalLight; + #if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0 + DirectionalLightShadow directionalLightShadow; + #endif + #pragma unroll_loop_start + for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) { + directionalLight = directionalLights[ i ]; + getDirectionalLightInfo( directionalLight, directLight ); + #if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS ) + directionalLightShadow = directionalLightShadows[ i ]; + directLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0; + #endif + RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); + } + #pragma unroll_loop_end +#endif +#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea ) + RectAreaLight rectAreaLight; + #pragma unroll_loop_start + for ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) { + rectAreaLight = rectAreaLights[ i ]; + RE_Direct_RectArea( rectAreaLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); + } + #pragma unroll_loop_end +#endif +#if defined( RE_IndirectDiffuse ) + vec3 iblIrradiance = vec3( 0.0 ); + vec3 irradiance = getAmbientLightIrradiance( ambientLightColor ); + #if defined( USE_LIGHT_PROBES ) + irradiance += getLightProbeIrradiance( lightProbe, geometryNormal ); + #endif + #if ( NUM_HEMI_LIGHTS > 0 ) + #pragma unroll_loop_start + for ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) { + irradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometryNormal ); + } + #pragma unroll_loop_end + #endif +#endif +#if defined( RE_IndirectSpecular ) + vec3 radiance = vec3( 0.0 ); + vec3 clearcoatRadiance = vec3( 0.0 ); +#endif`,D_=`#if defined( RE_IndirectDiffuse ) + #ifdef USE_LIGHTMAP + vec4 lightMapTexel = texture2D( lightMap, vLightMapUv ); + vec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity; + irradiance += lightMapIrradiance; + #endif + #if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV ) + iblIrradiance += getIBLIrradiance( geometryNormal ); + #endif +#endif +#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular ) + #ifdef USE_ANISOTROPY + radiance += getIBLAnisotropyRadiance( geometryViewDir, geometryNormal, material.roughness, material.anisotropyB, material.anisotropy ); + #else + radiance += getIBLRadiance( geometryViewDir, geometryNormal, material.roughness ); + #endif + #ifdef USE_CLEARCOAT + clearcoatRadiance += getIBLRadiance( geometryViewDir, geometryClearcoatNormal, material.clearcoatRoughness ); + #endif +#endif`,U_=`#if defined( RE_IndirectDiffuse ) + RE_IndirectDiffuse( irradiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); +#endif +#if defined( RE_IndirectSpecular ) + RE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); +#endif`,O_=`#if defined( USE_LOGDEPTHBUF ) + gl_FragDepth = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5; +#endif`,F_=`#if defined( USE_LOGDEPTHBUF ) + uniform float logDepthBufFC; + varying float vFragDepth; + varying float vIsPerspective; +#endif`,k_=`#ifdef USE_LOGDEPTHBUF + varying float vFragDepth; + varying float vIsPerspective; +#endif`,B_=`#ifdef USE_LOGDEPTHBUF + vFragDepth = 1.0 + gl_Position.w; + vIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) ); +#endif`,z_=`#ifdef USE_MAP + vec4 sampledDiffuseColor = texture2D( map, vMapUv ); + #ifdef DECODE_VIDEO_TEXTURE + sampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w ); + + #endif + diffuseColor *= sampledDiffuseColor; +#endif`,V_=`#ifdef USE_MAP + uniform sampler2D map; +#endif`,H_=`#if defined( USE_MAP ) || defined( USE_ALPHAMAP ) + #if defined( USE_POINTS_UV ) + vec2 uv = vUv; + #else + vec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy; + #endif +#endif +#ifdef USE_MAP + diffuseColor *= texture2D( map, uv ); +#endif +#ifdef USE_ALPHAMAP + diffuseColor.a *= texture2D( alphaMap, uv ).g; +#endif`,G_=`#if defined( USE_POINTS_UV ) + varying vec2 vUv; +#else + #if defined( USE_MAP ) || defined( USE_ALPHAMAP ) + uniform mat3 uvTransform; + #endif +#endif +#ifdef USE_MAP + uniform sampler2D map; +#endif +#ifdef USE_ALPHAMAP + uniform sampler2D alphaMap; +#endif`,W_=`float metalnessFactor = metalness; +#ifdef USE_METALNESSMAP + vec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv ); + metalnessFactor *= texelMetalness.b; +#endif`,$_=`#ifdef USE_METALNESSMAP + uniform sampler2D metalnessMap; +#endif`,X_=`#ifdef USE_INSTANCING_MORPH + float morphTargetInfluences[ MORPHTARGETS_COUNT ]; + float morphTargetBaseInfluence = texelFetch( morphTexture, ivec2( 0, gl_InstanceID ), 0 ).r; + for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { + morphTargetInfluences[i] = texelFetch( morphTexture, ivec2( i + 1, gl_InstanceID ), 0 ).r; + } +#endif`,q_=`#if defined( USE_MORPHCOLORS ) + vColor *= morphTargetBaseInfluence; + for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { + #if defined( USE_COLOR_ALPHA ) + if ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ) * morphTargetInfluences[ i ]; + #elif defined( USE_COLOR ) + if ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ).rgb * morphTargetInfluences[ i ]; + #endif + } +#endif`,Y_=`#ifdef USE_MORPHNORMALS + objectNormal *= morphTargetBaseInfluence; + for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { + if ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1 ).xyz * morphTargetInfluences[ i ]; + } +#endif`,Z_=`#ifdef USE_MORPHTARGETS + #ifndef USE_INSTANCING_MORPH + uniform float morphTargetBaseInfluence; + uniform float morphTargetInfluences[ MORPHTARGETS_COUNT ]; + #endif + uniform sampler2DArray morphTargetsTexture; + uniform ivec2 morphTargetsTextureSize; + vec4 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset ) { + int texelIndex = vertexIndex * MORPHTARGETS_TEXTURE_STRIDE + offset; + int y = texelIndex / morphTargetsTextureSize.x; + int x = texelIndex - y * morphTargetsTextureSize.x; + ivec3 morphUV = ivec3( x, y, morphTargetIndex ); + return texelFetch( morphTargetsTexture, morphUV, 0 ); + } +#endif`,J_=`#ifdef USE_MORPHTARGETS + transformed *= morphTargetBaseInfluence; + for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { + if ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ]; + } +#endif`,K_=`float faceDirection = gl_FrontFacing ? 1.0 : - 1.0; +#ifdef FLAT_SHADED + vec3 fdx = dFdx( vViewPosition ); + vec3 fdy = dFdy( vViewPosition ); + vec3 normal = normalize( cross( fdx, fdy ) ); +#else + vec3 normal = normalize( vNormal ); + #ifdef DOUBLE_SIDED + normal *= faceDirection; + #endif +#endif +#if defined( USE_NORMALMAP_TANGENTSPACE ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) + #ifdef USE_TANGENT + mat3 tbn = mat3( normalize( vTangent ), normalize( vBitangent ), normal ); + #else + mat3 tbn = getTangentFrame( - vViewPosition, normal, + #if defined( USE_NORMALMAP ) + vNormalMapUv + #elif defined( USE_CLEARCOAT_NORMALMAP ) + vClearcoatNormalMapUv + #else + vUv + #endif + ); + #endif + #if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED ) + tbn[0] *= faceDirection; + tbn[1] *= faceDirection; + #endif +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + #ifdef USE_TANGENT + mat3 tbn2 = mat3( normalize( vTangent ), normalize( vBitangent ), normal ); + #else + mat3 tbn2 = getTangentFrame( - vViewPosition, normal, vClearcoatNormalMapUv ); + #endif + #if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED ) + tbn2[0] *= faceDirection; + tbn2[1] *= faceDirection; + #endif +#endif +vec3 nonPerturbedNormal = normal;`,j_=`#ifdef USE_NORMALMAP_OBJECTSPACE + normal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0; + #ifdef FLIP_SIDED + normal = - normal; + #endif + #ifdef DOUBLE_SIDED + normal = normal * faceDirection; + #endif + normal = normalize( normalMatrix * normal ); +#elif defined( USE_NORMALMAP_TANGENTSPACE ) + vec3 mapN = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0; + mapN.xy *= normalScale; + normal = normalize( tbn * mapN ); +#elif defined( USE_BUMPMAP ) + normal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection ); +#endif`,Q_=`#ifndef FLAT_SHADED + varying vec3 vNormal; + #ifdef USE_TANGENT + varying vec3 vTangent; + varying vec3 vBitangent; + #endif +#endif`,e0=`#ifndef FLAT_SHADED + varying vec3 vNormal; + #ifdef USE_TANGENT + varying vec3 vTangent; + varying vec3 vBitangent; + #endif +#endif`,t0=`#ifndef FLAT_SHADED + vNormal = normalize( transformedNormal ); + #ifdef USE_TANGENT + vTangent = normalize( transformedTangent ); + vBitangent = normalize( cross( vNormal, vTangent ) * tangent.w ); + #endif +#endif`,n0=`#ifdef USE_NORMALMAP + uniform sampler2D normalMap; + uniform vec2 normalScale; +#endif +#ifdef USE_NORMALMAP_OBJECTSPACE + uniform mat3 normalMatrix; +#endif +#if ! defined ( USE_TANGENT ) && ( defined ( USE_NORMALMAP_TANGENTSPACE ) || defined ( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) ) + mat3 getTangentFrame( vec3 eye_pos, vec3 surf_norm, vec2 uv ) { + vec3 q0 = dFdx( eye_pos.xyz ); + vec3 q1 = dFdy( eye_pos.xyz ); + vec2 st0 = dFdx( uv.st ); + vec2 st1 = dFdy( uv.st ); + vec3 N = surf_norm; + vec3 q1perp = cross( q1, N ); + vec3 q0perp = cross( N, q0 ); + vec3 T = q1perp * st0.x + q0perp * st1.x; + vec3 B = q1perp * st0.y + q0perp * st1.y; + float det = max( dot( T, T ), dot( B, B ) ); + float scale = ( det == 0.0 ) ? 0.0 : inversesqrt( det ); + return mat3( T * scale, B * scale, N ); + } +#endif`,i0=`#ifdef USE_CLEARCOAT + vec3 clearcoatNormal = nonPerturbedNormal; +#endif`,s0=`#ifdef USE_CLEARCOAT_NORMALMAP + vec3 clearcoatMapN = texture2D( clearcoatNormalMap, vClearcoatNormalMapUv ).xyz * 2.0 - 1.0; + clearcoatMapN.xy *= clearcoatNormalScale; + clearcoatNormal = normalize( tbn2 * clearcoatMapN ); +#endif`,r0=`#ifdef USE_CLEARCOATMAP + uniform sampler2D clearcoatMap; +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + uniform sampler2D clearcoatNormalMap; + uniform vec2 clearcoatNormalScale; +#endif +#ifdef USE_CLEARCOAT_ROUGHNESSMAP + uniform sampler2D clearcoatRoughnessMap; +#endif`,o0=`#ifdef USE_IRIDESCENCEMAP + uniform sampler2D iridescenceMap; +#endif +#ifdef USE_IRIDESCENCE_THICKNESSMAP + uniform sampler2D iridescenceThicknessMap; +#endif`,a0=`#ifdef OPAQUE +diffuseColor.a = 1.0; +#endif +#ifdef USE_TRANSMISSION +diffuseColor.a *= material.transmissionAlpha; +#endif +gl_FragColor = vec4( outgoingLight, diffuseColor.a );`,l0=`vec3 packNormalToRGB( const in vec3 normal ) { + return normalize( normal ) * 0.5 + 0.5; +} +vec3 unpackRGBToNormal( const in vec3 rgb ) { + return 2.0 * rgb.xyz - 1.0; +} +const float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.; +const vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. ); +const vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. ); +const float ShiftRight8 = 1. / 256.; +vec4 packDepthToRGBA( const in float v ) { + vec4 r = vec4( fract( v * PackFactors ), v ); + r.yzw -= r.xyz * ShiftRight8; return r * PackUpscale; +} +float unpackRGBAToDepth( const in vec4 v ) { + return dot( v, UnpackFactors ); +} +vec2 packDepthToRG( in highp float v ) { + return packDepthToRGBA( v ).yx; +} +float unpackRGToDepth( const in highp vec2 v ) { + return unpackRGBAToDepth( vec4( v.xy, 0.0, 0.0 ) ); +} +vec4 pack2HalfToRGBA( vec2 v ) { + vec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) ); + return vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w ); +} +vec2 unpackRGBATo2Half( vec4 v ) { + return vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) ); +} +float viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) { + return ( viewZ + near ) / ( near - far ); +} +float orthographicDepthToViewZ( const in float depth, const in float near, const in float far ) { + return depth * ( near - far ) - near; +} +float viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) { + return ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ ); +} +float perspectiveDepthToViewZ( const in float depth, const in float near, const in float far ) { + return ( near * far ) / ( ( far - near ) * depth - far ); +}`,c0=`#ifdef PREMULTIPLIED_ALPHA + gl_FragColor.rgb *= gl_FragColor.a; +#endif`,u0=`vec4 mvPosition = vec4( transformed, 1.0 ); +#ifdef USE_BATCHING + mvPosition = batchingMatrix * mvPosition; +#endif +#ifdef USE_INSTANCING + mvPosition = instanceMatrix * mvPosition; +#endif +mvPosition = modelViewMatrix * mvPosition; +gl_Position = projectionMatrix * mvPosition;`,h0=`#ifdef DITHERING + gl_FragColor.rgb = dithering( gl_FragColor.rgb ); +#endif`,d0=`#ifdef DITHERING + vec3 dithering( vec3 color ) { + float grid_position = rand( gl_FragCoord.xy ); + vec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 ); + dither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position ); + return color + dither_shift_RGB; + } +#endif`,f0=`float roughnessFactor = roughness; +#ifdef USE_ROUGHNESSMAP + vec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv ); + roughnessFactor *= texelRoughness.g; +#endif`,p0=`#ifdef USE_ROUGHNESSMAP + uniform sampler2D roughnessMap; +#endif`,m0=`#if NUM_SPOT_LIGHT_COORDS > 0 + varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ]; +#endif +#if NUM_SPOT_LIGHT_MAPS > 0 + uniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ]; +#endif +#ifdef USE_SHADOWMAP + #if NUM_DIR_LIGHT_SHADOWS > 0 + uniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ]; + varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ]; + struct DirectionalLightShadow { + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + }; + uniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ]; + #endif + #if NUM_SPOT_LIGHT_SHADOWS > 0 + uniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ]; + struct SpotLightShadow { + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + }; + uniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ]; + #endif + #if NUM_POINT_LIGHT_SHADOWS > 0 + uniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ]; + varying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ]; + struct PointLightShadow { + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + float shadowCameraNear; + float shadowCameraFar; + }; + uniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ]; + #endif + float texture2DCompare( sampler2D depths, vec2 uv, float compare ) { + return step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) ); + } + vec2 texture2DDistribution( sampler2D shadow, vec2 uv ) { + return unpackRGBATo2Half( texture2D( shadow, uv ) ); + } + float VSMShadow (sampler2D shadow, vec2 uv, float compare ){ + float occlusion = 1.0; + vec2 distribution = texture2DDistribution( shadow, uv ); + float hard_shadow = step( compare , distribution.x ); + if (hard_shadow != 1.0 ) { + float distance = compare - distribution.x ; + float variance = max( 0.00000, distribution.y * distribution.y ); + float softness_probability = variance / (variance + distance * distance ); softness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 ); occlusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 ); + } + return occlusion; + } + float getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) { + float shadow = 1.0; + shadowCoord.xyz /= shadowCoord.w; + shadowCoord.z += shadowBias; + bool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0; + bool frustumTest = inFrustum && shadowCoord.z <= 1.0; + if ( frustumTest ) { + #if defined( SHADOWMAP_TYPE_PCF ) + vec2 texelSize = vec2( 1.0 ) / shadowMapSize; + float dx0 = - texelSize.x * shadowRadius; + float dy0 = - texelSize.y * shadowRadius; + float dx1 = + texelSize.x * shadowRadius; + float dy1 = + texelSize.y * shadowRadius; + float dx2 = dx0 / 2.0; + float dy2 = dy0 / 2.0; + float dx3 = dx1 / 2.0; + float dy3 = dy1 / 2.0; + shadow = ( + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z ) + ) * ( 1.0 / 17.0 ); + #elif defined( SHADOWMAP_TYPE_PCF_SOFT ) + vec2 texelSize = vec2( 1.0 ) / shadowMapSize; + float dx = texelSize.x; + float dy = texelSize.y; + vec2 uv = shadowCoord.xy; + vec2 f = fract( uv * shadowMapSize + 0.5 ); + uv -= f * texelSize; + shadow = ( + texture2DCompare( shadowMap, uv, shadowCoord.z ) + + texture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) + + texture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) + + mix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ), + texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ), + f.x ) + + mix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ), + texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ), + f.x ) + + mix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ), + texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ), + f.y ) + + mix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ), + texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ), + f.y ) + + mix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ), + texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ), + f.x ), + mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ), + texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ), + f.x ), + f.y ) + ) * ( 1.0 / 9.0 ); + #elif defined( SHADOWMAP_TYPE_VSM ) + shadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z ); + #else + shadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ); + #endif + } + return shadow; + } + vec2 cubeToUV( vec3 v, float texelSizeY ) { + vec3 absV = abs( v ); + float scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) ); + absV *= scaleToCube; + v *= scaleToCube * ( 1.0 - 2.0 * texelSizeY ); + vec2 planar = v.xy; + float almostATexel = 1.5 * texelSizeY; + float almostOne = 1.0 - almostATexel; + if ( absV.z >= almostOne ) { + if ( v.z > 0.0 ) + planar.x = 4.0 - v.x; + } else if ( absV.x >= almostOne ) { + float signX = sign( v.x ); + planar.x = v.z * signX + 2.0 * signX; + } else if ( absV.y >= almostOne ) { + float signY = sign( v.y ); + planar.x = v.x + 2.0 * signY + 2.0; + planar.y = v.z * signY - 2.0; + } + return vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 ); + } + float getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) { + float shadow = 1.0; + vec3 lightToPosition = shadowCoord.xyz; + + float lightToPositionLength = length( lightToPosition ); + if ( lightToPositionLength - shadowCameraFar <= 0.0 && lightToPositionLength - shadowCameraNear >= 0.0 ) { + float dp = ( lightToPositionLength - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear ); dp += shadowBias; + vec3 bd3D = normalize( lightToPosition ); + vec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) ); + #if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM ) + vec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y; + shadow = ( + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp ) + ) * ( 1.0 / 9.0 ); + #else + shadow = texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ); + #endif + } + return shadow; + } +#endif`,g0=`#if NUM_SPOT_LIGHT_COORDS > 0 + uniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ]; + varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ]; +#endif +#ifdef USE_SHADOWMAP + #if NUM_DIR_LIGHT_SHADOWS > 0 + uniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ]; + varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ]; + struct DirectionalLightShadow { + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + }; + uniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ]; + #endif + #if NUM_SPOT_LIGHT_SHADOWS > 0 + struct SpotLightShadow { + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + }; + uniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ]; + #endif + #if NUM_POINT_LIGHT_SHADOWS > 0 + uniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ]; + varying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ]; + struct PointLightShadow { + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + float shadowCameraNear; + float shadowCameraFar; + }; + uniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ]; + #endif +#endif`,v0=`#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 ) + vec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix ); + vec4 shadowWorldPosition; +#endif +#if defined( USE_SHADOWMAP ) + #if NUM_DIR_LIGHT_SHADOWS > 0 + #pragma unroll_loop_start + for ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) { + shadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 ); + vDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition; + } + #pragma unroll_loop_end + #endif + #if NUM_POINT_LIGHT_SHADOWS > 0 + #pragma unroll_loop_start + for ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) { + shadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 ); + vPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition; + } + #pragma unroll_loop_end + #endif +#endif +#if NUM_SPOT_LIGHT_COORDS > 0 + #pragma unroll_loop_start + for ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) { + shadowWorldPosition = worldPosition; + #if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS ) + shadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias; + #endif + vSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition; + } + #pragma unroll_loop_end +#endif`,_0=`float getShadowMask() { + float shadow = 1.0; + #ifdef USE_SHADOWMAP + #if NUM_DIR_LIGHT_SHADOWS > 0 + DirectionalLightShadow directionalLight; + #pragma unroll_loop_start + for ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) { + directionalLight = directionalLightShadows[ i ]; + shadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0; + } + #pragma unroll_loop_end + #endif + #if NUM_SPOT_LIGHT_SHADOWS > 0 + SpotLightShadow spotLight; + #pragma unroll_loop_start + for ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) { + spotLight = spotLightShadows[ i ]; + shadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0; + } + #pragma unroll_loop_end + #endif + #if NUM_POINT_LIGHT_SHADOWS > 0 + PointLightShadow pointLight; + #pragma unroll_loop_start + for ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) { + pointLight = pointLightShadows[ i ]; + shadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0; + } + #pragma unroll_loop_end + #endif + #endif + return shadow; +}`,y0=`#ifdef USE_SKINNING + mat4 boneMatX = getBoneMatrix( skinIndex.x ); + mat4 boneMatY = getBoneMatrix( skinIndex.y ); + mat4 boneMatZ = getBoneMatrix( skinIndex.z ); + mat4 boneMatW = getBoneMatrix( skinIndex.w ); +#endif`,x0=`#ifdef USE_SKINNING + uniform mat4 bindMatrix; + uniform mat4 bindMatrixInverse; + uniform highp sampler2D boneTexture; + mat4 getBoneMatrix( const in float i ) { + int size = textureSize( boneTexture, 0 ).x; + int j = int( i ) * 4; + int x = j % size; + int y = j / size; + vec4 v1 = texelFetch( boneTexture, ivec2( x, y ), 0 ); + vec4 v2 = texelFetch( boneTexture, ivec2( x + 1, y ), 0 ); + vec4 v3 = texelFetch( boneTexture, ivec2( x + 2, y ), 0 ); + vec4 v4 = texelFetch( boneTexture, ivec2( x + 3, y ), 0 ); + return mat4( v1, v2, v3, v4 ); + } +#endif`,M0=`#ifdef USE_SKINNING + vec4 skinVertex = bindMatrix * vec4( transformed, 1.0 ); + vec4 skinned = vec4( 0.0 ); + skinned += boneMatX * skinVertex * skinWeight.x; + skinned += boneMatY * skinVertex * skinWeight.y; + skinned += boneMatZ * skinVertex * skinWeight.z; + skinned += boneMatW * skinVertex * skinWeight.w; + transformed = ( bindMatrixInverse * skinned ).xyz; +#endif`,b0=`#ifdef USE_SKINNING + mat4 skinMatrix = mat4( 0.0 ); + skinMatrix += skinWeight.x * boneMatX; + skinMatrix += skinWeight.y * boneMatY; + skinMatrix += skinWeight.z * boneMatZ; + skinMatrix += skinWeight.w * boneMatW; + skinMatrix = bindMatrixInverse * skinMatrix * bindMatrix; + objectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz; + #ifdef USE_TANGENT + objectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz; + #endif +#endif`,S0=`float specularStrength; +#ifdef USE_SPECULARMAP + vec4 texelSpecular = texture2D( specularMap, vSpecularMapUv ); + specularStrength = texelSpecular.r; +#else + specularStrength = 1.0; +#endif`,w0=`#ifdef USE_SPECULARMAP + uniform sampler2D specularMap; +#endif`,A0=`#if defined( TONE_MAPPING ) + gl_FragColor.rgb = toneMapping( gl_FragColor.rgb ); +#endif`,T0=`#ifndef saturate +#define saturate( a ) clamp( a, 0.0, 1.0 ) +#endif +uniform float toneMappingExposure; +vec3 LinearToneMapping( vec3 color ) { + return saturate( toneMappingExposure * color ); +} +vec3 ReinhardToneMapping( vec3 color ) { + color *= toneMappingExposure; + return saturate( color / ( vec3( 1.0 ) + color ) ); +} +vec3 OptimizedCineonToneMapping( vec3 color ) { + color *= toneMappingExposure; + color = max( vec3( 0.0 ), color - 0.004 ); + return pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) ); +} +vec3 RRTAndODTFit( vec3 v ) { + vec3 a = v * ( v + 0.0245786 ) - 0.000090537; + vec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081; + return a / b; +} +vec3 ACESFilmicToneMapping( vec3 color ) { + const mat3 ACESInputMat = mat3( + vec3( 0.59719, 0.07600, 0.02840 ), vec3( 0.35458, 0.90834, 0.13383 ), + vec3( 0.04823, 0.01566, 0.83777 ) + ); + const mat3 ACESOutputMat = mat3( + vec3( 1.60475, -0.10208, -0.00327 ), vec3( -0.53108, 1.10813, -0.07276 ), + vec3( -0.07367, -0.00605, 1.07602 ) + ); + color *= toneMappingExposure / 0.6; + color = ACESInputMat * color; + color = RRTAndODTFit( color ); + color = ACESOutputMat * color; + return saturate( color ); +} +const mat3 LINEAR_REC2020_TO_LINEAR_SRGB = mat3( + vec3( 1.6605, - 0.1246, - 0.0182 ), + vec3( - 0.5876, 1.1329, - 0.1006 ), + vec3( - 0.0728, - 0.0083, 1.1187 ) +); +const mat3 LINEAR_SRGB_TO_LINEAR_REC2020 = mat3( + vec3( 0.6274, 0.0691, 0.0164 ), + vec3( 0.3293, 0.9195, 0.0880 ), + vec3( 0.0433, 0.0113, 0.8956 ) +); +vec3 agxDefaultContrastApprox( vec3 x ) { + vec3 x2 = x * x; + vec3 x4 = x2 * x2; + return + 15.5 * x4 * x2 + - 40.14 * x4 * x + + 31.96 * x4 + - 6.868 * x2 * x + + 0.4298 * x2 + + 0.1191 * x + - 0.00232; +} +vec3 AgXToneMapping( vec3 color ) { + const mat3 AgXInsetMatrix = mat3( + vec3( 0.856627153315983, 0.137318972929847, 0.11189821299995 ), + vec3( 0.0951212405381588, 0.761241990602591, 0.0767994186031903 ), + vec3( 0.0482516061458583, 0.101439036467562, 0.811302368396859 ) + ); + const mat3 AgXOutsetMatrix = mat3( + vec3( 1.1271005818144368, - 0.1413297634984383, - 0.14132976349843826 ), + vec3( - 0.11060664309660323, 1.157823702216272, - 0.11060664309660294 ), + vec3( - 0.016493938717834573, - 0.016493938717834257, 1.2519364065950405 ) + ); + const float AgxMinEv = - 12.47393; const float AgxMaxEv = 4.026069; + color *= toneMappingExposure; + color = LINEAR_SRGB_TO_LINEAR_REC2020 * color; + color = AgXInsetMatrix * color; + color = max( color, 1e-10 ); color = log2( color ); + color = ( color - AgxMinEv ) / ( AgxMaxEv - AgxMinEv ); + color = clamp( color, 0.0, 1.0 ); + color = agxDefaultContrastApprox( color ); + color = AgXOutsetMatrix * color; + color = pow( max( vec3( 0.0 ), color ), vec3( 2.2 ) ); + color = LINEAR_REC2020_TO_LINEAR_SRGB * color; + color = clamp( color, 0.0, 1.0 ); + return color; +} +vec3 NeutralToneMapping( vec3 color ) { + const float StartCompression = 0.8 - 0.04; + const float Desaturation = 0.15; + color *= toneMappingExposure; + float x = min( color.r, min( color.g, color.b ) ); + float offset = x < 0.08 ? x - 6.25 * x * x : 0.04; + color -= offset; + float peak = max( color.r, max( color.g, color.b ) ); + if ( peak < StartCompression ) return color; + float d = 1. - StartCompression; + float newPeak = 1. - d * d / ( peak + d - StartCompression ); + color *= newPeak / peak; + float g = 1. - 1. / ( Desaturation * ( peak - newPeak ) + 1. ); + return mix( color, vec3( newPeak ), g ); +} +vec3 CustomToneMapping( vec3 color ) { return color; }`,E0=`#ifdef USE_TRANSMISSION + material.transmission = transmission; + material.transmissionAlpha = 1.0; + material.thickness = thickness; + material.attenuationDistance = attenuationDistance; + material.attenuationColor = attenuationColor; + #ifdef USE_TRANSMISSIONMAP + material.transmission *= texture2D( transmissionMap, vTransmissionMapUv ).r; + #endif + #ifdef USE_THICKNESSMAP + material.thickness *= texture2D( thicknessMap, vThicknessMapUv ).g; + #endif + vec3 pos = vWorldPosition; + vec3 v = normalize( cameraPosition - pos ); + vec3 n = inverseTransformDirection( normal, viewMatrix ); + vec4 transmitted = getIBLVolumeRefraction( + n, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90, + pos, modelMatrix, viewMatrix, projectionMatrix, material.dispersion, material.ior, material.thickness, + material.attenuationColor, material.attenuationDistance ); + material.transmissionAlpha = mix( material.transmissionAlpha, transmitted.a, material.transmission ); + totalDiffuse = mix( totalDiffuse, transmitted.rgb, material.transmission ); +#endif`,C0=`#ifdef USE_TRANSMISSION + uniform float transmission; + uniform float thickness; + uniform float attenuationDistance; + uniform vec3 attenuationColor; + #ifdef USE_TRANSMISSIONMAP + uniform sampler2D transmissionMap; + #endif + #ifdef USE_THICKNESSMAP + uniform sampler2D thicknessMap; + #endif + uniform vec2 transmissionSamplerSize; + uniform sampler2D transmissionSamplerMap; + uniform mat4 modelMatrix; + uniform mat4 projectionMatrix; + varying vec3 vWorldPosition; + float w0( float a ) { + return ( 1.0 / 6.0 ) * ( a * ( a * ( - a + 3.0 ) - 3.0 ) + 1.0 ); + } + float w1( float a ) { + return ( 1.0 / 6.0 ) * ( a * a * ( 3.0 * a - 6.0 ) + 4.0 ); + } + float w2( float a ){ + return ( 1.0 / 6.0 ) * ( a * ( a * ( - 3.0 * a + 3.0 ) + 3.0 ) + 1.0 ); + } + float w3( float a ) { + return ( 1.0 / 6.0 ) * ( a * a * a ); + } + float g0( float a ) { + return w0( a ) + w1( a ); + } + float g1( float a ) { + return w2( a ) + w3( a ); + } + float h0( float a ) { + return - 1.0 + w1( a ) / ( w0( a ) + w1( a ) ); + } + float h1( float a ) { + return 1.0 + w3( a ) / ( w2( a ) + w3( a ) ); + } + vec4 bicubic( sampler2D tex, vec2 uv, vec4 texelSize, float lod ) { + uv = uv * texelSize.zw + 0.5; + vec2 iuv = floor( uv ); + vec2 fuv = fract( uv ); + float g0x = g0( fuv.x ); + float g1x = g1( fuv.x ); + float h0x = h0( fuv.x ); + float h1x = h1( fuv.x ); + float h0y = h0( fuv.y ); + float h1y = h1( fuv.y ); + vec2 p0 = ( vec2( iuv.x + h0x, iuv.y + h0y ) - 0.5 ) * texelSize.xy; + vec2 p1 = ( vec2( iuv.x + h1x, iuv.y + h0y ) - 0.5 ) * texelSize.xy; + vec2 p2 = ( vec2( iuv.x + h0x, iuv.y + h1y ) - 0.5 ) * texelSize.xy; + vec2 p3 = ( vec2( iuv.x + h1x, iuv.y + h1y ) - 0.5 ) * texelSize.xy; + return g0( fuv.y ) * ( g0x * textureLod( tex, p0, lod ) + g1x * textureLod( tex, p1, lod ) ) + + g1( fuv.y ) * ( g0x * textureLod( tex, p2, lod ) + g1x * textureLod( tex, p3, lod ) ); + } + vec4 textureBicubic( sampler2D sampler, vec2 uv, float lod ) { + vec2 fLodSize = vec2( textureSize( sampler, int( lod ) ) ); + vec2 cLodSize = vec2( textureSize( sampler, int( lod + 1.0 ) ) ); + vec2 fLodSizeInv = 1.0 / fLodSize; + vec2 cLodSizeInv = 1.0 / cLodSize; + vec4 fSample = bicubic( sampler, uv, vec4( fLodSizeInv, fLodSize ), floor( lod ) ); + vec4 cSample = bicubic( sampler, uv, vec4( cLodSizeInv, cLodSize ), ceil( lod ) ); + return mix( fSample, cSample, fract( lod ) ); + } + vec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) { + vec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior ); + vec3 modelScale; + modelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) ); + modelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) ); + modelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) ); + return normalize( refractionVector ) * thickness * modelScale; + } + float applyIorToRoughness( const in float roughness, const in float ior ) { + return roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 ); + } + vec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) { + float lod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior ); + return textureBicubic( transmissionSamplerMap, fragCoord.xy, lod ); + } + vec3 volumeAttenuation( const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) { + if ( isinf( attenuationDistance ) ) { + return vec3( 1.0 ); + } else { + vec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance; + vec3 transmittance = exp( - attenuationCoefficient * transmissionDistance ); return transmittance; + } + } + vec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor, + const in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix, + const in mat4 viewMatrix, const in mat4 projMatrix, const in float dispersion, const in float ior, const in float thickness, + const in vec3 attenuationColor, const in float attenuationDistance ) { + vec4 transmittedLight; + vec3 transmittance; + #ifdef USE_DISPERSION + float halfSpread = ( ior - 1.0 ) * 0.025 * dispersion; + vec3 iors = vec3( ior - halfSpread, ior, ior + halfSpread ); + for ( int i = 0; i < 3; i ++ ) { + vec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, iors[ i ], modelMatrix ); + vec3 refractedRayExit = position + transmissionRay; + + vec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 ); + vec2 refractionCoords = ndcPos.xy / ndcPos.w; + refractionCoords += 1.0; + refractionCoords /= 2.0; + + vec4 transmissionSample = getTransmissionSample( refractionCoords, roughness, iors[ i ] ); + transmittedLight[ i ] = transmissionSample[ i ]; + transmittedLight.a += transmissionSample.a; + transmittance[ i ] = diffuseColor[ i ] * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance )[ i ]; + } + transmittedLight.a /= 3.0; + + #else + + vec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix ); + vec3 refractedRayExit = position + transmissionRay; + vec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 ); + vec2 refractionCoords = ndcPos.xy / ndcPos.w; + refractionCoords += 1.0; + refractionCoords /= 2.0; + transmittedLight = getTransmissionSample( refractionCoords, roughness, ior ); + transmittance = diffuseColor * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance ); + + #endif + vec3 attenuatedColor = transmittance * transmittedLight.rgb; + vec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness ); + float transmittanceFactor = ( transmittance.r + transmittance.g + transmittance.b ) / 3.0; + return vec4( ( 1.0 - F ) * attenuatedColor, 1.0 - ( 1.0 - transmittedLight.a ) * transmittanceFactor ); + } +#endif`,P0=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) + varying vec2 vUv; +#endif +#ifdef USE_MAP + varying vec2 vMapUv; +#endif +#ifdef USE_ALPHAMAP + varying vec2 vAlphaMapUv; +#endif +#ifdef USE_LIGHTMAP + varying vec2 vLightMapUv; +#endif +#ifdef USE_AOMAP + varying vec2 vAoMapUv; +#endif +#ifdef USE_BUMPMAP + varying vec2 vBumpMapUv; +#endif +#ifdef USE_NORMALMAP + varying vec2 vNormalMapUv; +#endif +#ifdef USE_EMISSIVEMAP + varying vec2 vEmissiveMapUv; +#endif +#ifdef USE_METALNESSMAP + varying vec2 vMetalnessMapUv; +#endif +#ifdef USE_ROUGHNESSMAP + varying vec2 vRoughnessMapUv; +#endif +#ifdef USE_ANISOTROPYMAP + varying vec2 vAnisotropyMapUv; +#endif +#ifdef USE_CLEARCOATMAP + varying vec2 vClearcoatMapUv; +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + varying vec2 vClearcoatNormalMapUv; +#endif +#ifdef USE_CLEARCOAT_ROUGHNESSMAP + varying vec2 vClearcoatRoughnessMapUv; +#endif +#ifdef USE_IRIDESCENCEMAP + varying vec2 vIridescenceMapUv; +#endif +#ifdef USE_IRIDESCENCE_THICKNESSMAP + varying vec2 vIridescenceThicknessMapUv; +#endif +#ifdef USE_SHEEN_COLORMAP + varying vec2 vSheenColorMapUv; +#endif +#ifdef USE_SHEEN_ROUGHNESSMAP + varying vec2 vSheenRoughnessMapUv; +#endif +#ifdef USE_SPECULARMAP + varying vec2 vSpecularMapUv; +#endif +#ifdef USE_SPECULAR_COLORMAP + varying vec2 vSpecularColorMapUv; +#endif +#ifdef USE_SPECULAR_INTENSITYMAP + varying vec2 vSpecularIntensityMapUv; +#endif +#ifdef USE_TRANSMISSIONMAP + uniform mat3 transmissionMapTransform; + varying vec2 vTransmissionMapUv; +#endif +#ifdef USE_THICKNESSMAP + uniform mat3 thicknessMapTransform; + varying vec2 vThicknessMapUv; +#endif`,R0=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) + varying vec2 vUv; +#endif +#ifdef USE_MAP + uniform mat3 mapTransform; + varying vec2 vMapUv; +#endif +#ifdef USE_ALPHAMAP + uniform mat3 alphaMapTransform; + varying vec2 vAlphaMapUv; +#endif +#ifdef USE_LIGHTMAP + uniform mat3 lightMapTransform; + varying vec2 vLightMapUv; +#endif +#ifdef USE_AOMAP + uniform mat3 aoMapTransform; + varying vec2 vAoMapUv; +#endif +#ifdef USE_BUMPMAP + uniform mat3 bumpMapTransform; + varying vec2 vBumpMapUv; +#endif +#ifdef USE_NORMALMAP + uniform mat3 normalMapTransform; + varying vec2 vNormalMapUv; +#endif +#ifdef USE_DISPLACEMENTMAP + uniform mat3 displacementMapTransform; + varying vec2 vDisplacementMapUv; +#endif +#ifdef USE_EMISSIVEMAP + uniform mat3 emissiveMapTransform; + varying vec2 vEmissiveMapUv; +#endif +#ifdef USE_METALNESSMAP + uniform mat3 metalnessMapTransform; + varying vec2 vMetalnessMapUv; +#endif +#ifdef USE_ROUGHNESSMAP + uniform mat3 roughnessMapTransform; + varying vec2 vRoughnessMapUv; +#endif +#ifdef USE_ANISOTROPYMAP + uniform mat3 anisotropyMapTransform; + varying vec2 vAnisotropyMapUv; +#endif +#ifdef USE_CLEARCOATMAP + uniform mat3 clearcoatMapTransform; + varying vec2 vClearcoatMapUv; +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + uniform mat3 clearcoatNormalMapTransform; + varying vec2 vClearcoatNormalMapUv; +#endif +#ifdef USE_CLEARCOAT_ROUGHNESSMAP + uniform mat3 clearcoatRoughnessMapTransform; + varying vec2 vClearcoatRoughnessMapUv; +#endif +#ifdef USE_SHEEN_COLORMAP + uniform mat3 sheenColorMapTransform; + varying vec2 vSheenColorMapUv; +#endif +#ifdef USE_SHEEN_ROUGHNESSMAP + uniform mat3 sheenRoughnessMapTransform; + varying vec2 vSheenRoughnessMapUv; +#endif +#ifdef USE_IRIDESCENCEMAP + uniform mat3 iridescenceMapTransform; + varying vec2 vIridescenceMapUv; +#endif +#ifdef USE_IRIDESCENCE_THICKNESSMAP + uniform mat3 iridescenceThicknessMapTransform; + varying vec2 vIridescenceThicknessMapUv; +#endif +#ifdef USE_SPECULARMAP + uniform mat3 specularMapTransform; + varying vec2 vSpecularMapUv; +#endif +#ifdef USE_SPECULAR_COLORMAP + uniform mat3 specularColorMapTransform; + varying vec2 vSpecularColorMapUv; +#endif +#ifdef USE_SPECULAR_INTENSITYMAP + uniform mat3 specularIntensityMapTransform; + varying vec2 vSpecularIntensityMapUv; +#endif +#ifdef USE_TRANSMISSIONMAP + uniform mat3 transmissionMapTransform; + varying vec2 vTransmissionMapUv; +#endif +#ifdef USE_THICKNESSMAP + uniform mat3 thicknessMapTransform; + varying vec2 vThicknessMapUv; +#endif`,I0=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) + vUv = vec3( uv, 1 ).xy; +#endif +#ifdef USE_MAP + vMapUv = ( mapTransform * vec3( MAP_UV, 1 ) ).xy; +#endif +#ifdef USE_ALPHAMAP + vAlphaMapUv = ( alphaMapTransform * vec3( ALPHAMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_LIGHTMAP + vLightMapUv = ( lightMapTransform * vec3( LIGHTMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_AOMAP + vAoMapUv = ( aoMapTransform * vec3( AOMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_BUMPMAP + vBumpMapUv = ( bumpMapTransform * vec3( BUMPMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_NORMALMAP + vNormalMapUv = ( normalMapTransform * vec3( NORMALMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_DISPLACEMENTMAP + vDisplacementMapUv = ( displacementMapTransform * vec3( DISPLACEMENTMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_EMISSIVEMAP + vEmissiveMapUv = ( emissiveMapTransform * vec3( EMISSIVEMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_METALNESSMAP + vMetalnessMapUv = ( metalnessMapTransform * vec3( METALNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_ROUGHNESSMAP + vRoughnessMapUv = ( roughnessMapTransform * vec3( ROUGHNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_ANISOTROPYMAP + vAnisotropyMapUv = ( anisotropyMapTransform * vec3( ANISOTROPYMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_CLEARCOATMAP + vClearcoatMapUv = ( clearcoatMapTransform * vec3( CLEARCOATMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + vClearcoatNormalMapUv = ( clearcoatNormalMapTransform * vec3( CLEARCOAT_NORMALMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_CLEARCOAT_ROUGHNESSMAP + vClearcoatRoughnessMapUv = ( clearcoatRoughnessMapTransform * vec3( CLEARCOAT_ROUGHNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_IRIDESCENCEMAP + vIridescenceMapUv = ( iridescenceMapTransform * vec3( IRIDESCENCEMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_IRIDESCENCE_THICKNESSMAP + vIridescenceThicknessMapUv = ( iridescenceThicknessMapTransform * vec3( IRIDESCENCE_THICKNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SHEEN_COLORMAP + vSheenColorMapUv = ( sheenColorMapTransform * vec3( SHEEN_COLORMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SHEEN_ROUGHNESSMAP + vSheenRoughnessMapUv = ( sheenRoughnessMapTransform * vec3( SHEEN_ROUGHNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SPECULARMAP + vSpecularMapUv = ( specularMapTransform * vec3( SPECULARMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SPECULAR_COLORMAP + vSpecularColorMapUv = ( specularColorMapTransform * vec3( SPECULAR_COLORMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SPECULAR_INTENSITYMAP + vSpecularIntensityMapUv = ( specularIntensityMapTransform * vec3( SPECULAR_INTENSITYMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_TRANSMISSIONMAP + vTransmissionMapUv = ( transmissionMapTransform * vec3( TRANSMISSIONMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_THICKNESSMAP + vThicknessMapUv = ( thicknessMapTransform * vec3( THICKNESSMAP_UV, 1 ) ).xy; +#endif`,L0=`#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0 + vec4 worldPosition = vec4( transformed, 1.0 ); + #ifdef USE_BATCHING + worldPosition = batchingMatrix * worldPosition; + #endif + #ifdef USE_INSTANCING + worldPosition = instanceMatrix * worldPosition; + #endif + worldPosition = modelMatrix * worldPosition; +#endif`;const N0=`varying vec2 vUv; +uniform mat3 uvTransform; +void main() { + vUv = ( uvTransform * vec3( uv, 1 ) ).xy; + gl_Position = vec4( position.xy, 1.0, 1.0 ); +}`,D0=`uniform sampler2D t2D; +uniform float backgroundIntensity; +varying vec2 vUv; +void main() { + vec4 texColor = texture2D( t2D, vUv ); + #ifdef DECODE_VIDEO_TEXTURE + texColor = vec4( mix( pow( texColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), texColor.rgb * 0.0773993808, vec3( lessThanEqual( texColor.rgb, vec3( 0.04045 ) ) ) ), texColor.w ); + #endif + texColor.rgb *= backgroundIntensity; + gl_FragColor = texColor; + #include + #include +}`,U0=`varying vec3 vWorldDirection; +#include +void main() { + vWorldDirection = transformDirection( position, modelMatrix ); + #include + #include + gl_Position.z = gl_Position.w; +}`,O0=`#ifdef ENVMAP_TYPE_CUBE + uniform samplerCube envMap; +#elif defined( ENVMAP_TYPE_CUBE_UV ) + uniform sampler2D envMap; +#endif +uniform float flipEnvMap; +uniform float backgroundBlurriness; +uniform float backgroundIntensity; +uniform mat3 backgroundRotation; +varying vec3 vWorldDirection; +#include +void main() { + #ifdef ENVMAP_TYPE_CUBE + vec4 texColor = textureCube( envMap, backgroundRotation * vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) ); + #elif defined( ENVMAP_TYPE_CUBE_UV ) + vec4 texColor = textureCubeUV( envMap, backgroundRotation * vWorldDirection, backgroundBlurriness ); + #else + vec4 texColor = vec4( 0.0, 0.0, 0.0, 1.0 ); + #endif + texColor.rgb *= backgroundIntensity; + gl_FragColor = texColor; + #include + #include +}`,F0=`varying vec3 vWorldDirection; +#include +void main() { + vWorldDirection = transformDirection( position, modelMatrix ); + #include + #include + gl_Position.z = gl_Position.w; +}`,k0=`uniform samplerCube tCube; +uniform float tFlip; +uniform float opacity; +varying vec3 vWorldDirection; +void main() { + vec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) ); + gl_FragColor = texColor; + gl_FragColor.a *= opacity; + #include + #include +}`,B0=`#include +#include +#include +#include +#include +#include +#include +#include +varying vec2 vHighPrecisionZW; +void main() { + #include + #include + #include + #include + #ifdef USE_DISPLACEMENTMAP + #include + #include + #include + #endif + #include + #include + #include + #include + #include + #include + #include + vHighPrecisionZW = gl_Position.zw; +}`,z0=`#if DEPTH_PACKING == 3200 + uniform float opacity; +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +varying vec2 vHighPrecisionZW; +void main() { + vec4 diffuseColor = vec4( 1.0 ); + #include + #if DEPTH_PACKING == 3200 + diffuseColor.a = opacity; + #endif + #include + #include + #include + #include + #include + float fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5; + #if DEPTH_PACKING == 3200 + gl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity ); + #elif DEPTH_PACKING == 3201 + gl_FragColor = packDepthToRGBA( fragCoordZ ); + #endif +}`,V0=`#define DISTANCE +varying vec3 vWorldPosition; +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #ifdef USE_DISPLACEMENTMAP + #include + #include + #include + #endif + #include + #include + #include + #include + #include + #include + #include + vWorldPosition = worldPosition.xyz; +}`,H0=`#define DISTANCE +uniform vec3 referencePosition; +uniform float nearDistance; +uniform float farDistance; +varying vec3 vWorldPosition; +#include +#include +#include +#include +#include +#include +#include +#include +void main () { + vec4 diffuseColor = vec4( 1.0 ); + #include + #include + #include + #include + #include + float dist = length( vWorldPosition - referencePosition ); + dist = ( dist - nearDistance ) / ( farDistance - nearDistance ); + dist = saturate( dist ); + gl_FragColor = packDepthToRGBA( dist ); +}`,G0=`varying vec3 vWorldDirection; +#include +void main() { + vWorldDirection = transformDirection( position, modelMatrix ); + #include + #include +}`,W0=`uniform sampler2D tEquirect; +varying vec3 vWorldDirection; +#include +void main() { + vec3 direction = normalize( vWorldDirection ); + vec2 sampleUV = equirectUv( direction ); + gl_FragColor = texture2D( tEquirect, sampleUV ); + #include + #include +}`,$0=`uniform float scale; +attribute float lineDistance; +varying float vLineDistance; +#include +#include +#include +#include +#include +#include +#include +void main() { + vLineDistance = scale * lineDistance; + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +}`,X0=`uniform vec3 diffuse; +uniform float opacity; +uniform float dashSize; +uniform float totalSize; +varying float vLineDistance; +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + if ( mod( vLineDistance, totalSize ) > dashSize ) { + discard; + } + vec3 outgoingLight = vec3( 0.0 ); + #include + #include + #include + outgoingLight = diffuseColor.rgb; + #include + #include + #include + #include + #include +}`,q0=`#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #if defined ( USE_ENVMAP ) || defined ( USE_SKINNING ) + #include + #include + #include + #include + #include + #endif + #include + #include + #include + #include + #include + #include + #include + #include + #include +}`,Y0=`uniform vec3 diffuse; +uniform float opacity; +#ifndef FLAT_SHADED + varying vec3 vNormal; +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + #include + #include + #include + #include + #include + #include + #include + ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); + #ifdef USE_LIGHTMAP + vec4 lightMapTexel = texture2D( lightMap, vLightMapUv ); + reflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI; + #else + reflectedLight.indirectDiffuse += vec3( 1.0 ); + #endif + #include + reflectedLight.indirectDiffuse *= diffuseColor.rgb; + vec3 outgoingLight = reflectedLight.indirectDiffuse; + #include + #include + #include + #include + #include + #include + #include +}`,Z0=`#define LAMBERT +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vViewPosition = - mvPosition.xyz; + #include + #include + #include + #include +}`,J0=`#define LAMBERT +uniform vec3 diffuse; +uniform vec3 emissive; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); + vec3 totalEmissiveRadiance = emissive; + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance; + #include + #include + #include + #include + #include + #include + #include +}`,K0=`#define MATCAP +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vViewPosition = - mvPosition.xyz; +}`,j0=`#define MATCAP +uniform vec3 diffuse; +uniform float opacity; +uniform sampler2D matcap; +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + #include + #include + #include + #include + #include + #include + #include + #include + vec3 viewDir = normalize( vViewPosition ); + vec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) ); + vec3 y = cross( viewDir, x ); + vec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5; + #ifdef USE_MATCAP + vec4 matcapColor = texture2D( matcap, uv ); + #else + vec4 matcapColor = vec4( vec3( mix( 0.2, 0.8, uv.y ) ), 1.0 ); + #endif + vec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb; + #include + #include + #include + #include + #include + #include +}`,Q0=`#define NORMAL +#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE ) + varying vec3 vViewPosition; +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE ) + vViewPosition = - mvPosition.xyz; +#endif +}`,ey=`#define NORMAL +uniform float opacity; +#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE ) + varying vec3 vViewPosition; +#endif +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( 0.0, 0.0, 0.0, opacity ); + #include + #include + #include + #include + gl_FragColor = vec4( packNormalToRGB( normal ), diffuseColor.a ); + #ifdef OPAQUE + gl_FragColor.a = 1.0; + #endif +}`,ty=`#define PHONG +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vViewPosition = - mvPosition.xyz; + #include + #include + #include + #include +}`,ny=`#define PHONG +uniform vec3 diffuse; +uniform vec3 emissive; +uniform vec3 specular; +uniform float shininess; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); + vec3 totalEmissiveRadiance = emissive; + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance; + #include + #include + #include + #include + #include + #include + #include +}`,iy=`#define STANDARD +varying vec3 vViewPosition; +#ifdef USE_TRANSMISSION + varying vec3 vWorldPosition; +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vViewPosition = - mvPosition.xyz; + #include + #include + #include +#ifdef USE_TRANSMISSION + vWorldPosition = worldPosition.xyz; +#endif +}`,sy=`#define STANDARD +#ifdef PHYSICAL + #define IOR + #define USE_SPECULAR +#endif +uniform vec3 diffuse; +uniform vec3 emissive; +uniform float roughness; +uniform float metalness; +uniform float opacity; +#ifdef IOR + uniform float ior; +#endif +#ifdef USE_SPECULAR + uniform float specularIntensity; + uniform vec3 specularColor; + #ifdef USE_SPECULAR_COLORMAP + uniform sampler2D specularColorMap; + #endif + #ifdef USE_SPECULAR_INTENSITYMAP + uniform sampler2D specularIntensityMap; + #endif +#endif +#ifdef USE_CLEARCOAT + uniform float clearcoat; + uniform float clearcoatRoughness; +#endif +#ifdef USE_DISPERSION + uniform float dispersion; +#endif +#ifdef USE_IRIDESCENCE + uniform float iridescence; + uniform float iridescenceIOR; + uniform float iridescenceThicknessMinimum; + uniform float iridescenceThicknessMaximum; +#endif +#ifdef USE_SHEEN + uniform vec3 sheenColor; + uniform float sheenRoughness; + #ifdef USE_SHEEN_COLORMAP + uniform sampler2D sheenColorMap; + #endif + #ifdef USE_SHEEN_ROUGHNESSMAP + uniform sampler2D sheenRoughnessMap; + #endif +#endif +#ifdef USE_ANISOTROPY + uniform vec2 anisotropyVector; + #ifdef USE_ANISOTROPYMAP + uniform sampler2D anisotropyMap; + #endif +#endif +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); + vec3 totalEmissiveRadiance = emissive; + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse; + vec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular; + #include + vec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance; + #ifdef USE_SHEEN + float sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor ); + outgoingLight = outgoingLight * sheenEnergyComp + sheenSpecularDirect + sheenSpecularIndirect; + #endif + #ifdef USE_CLEARCOAT + float dotNVcc = saturate( dot( geometryClearcoatNormal, geometryViewDir ) ); + vec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc ); + outgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + ( clearcoatSpecularDirect + clearcoatSpecularIndirect ) * material.clearcoat; + #endif + #include + #include + #include + #include + #include + #include +}`,ry=`#define TOON +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vViewPosition = - mvPosition.xyz; + #include + #include + #include +}`,oy=`#define TOON +uniform vec3 diffuse; +uniform vec3 emissive; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); + vec3 totalEmissiveRadiance = emissive; + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance; + #include + #include + #include + #include + #include + #include +}`,ay=`uniform float size; +uniform float scale; +#include +#include +#include +#include +#include +#include +#ifdef USE_POINTS_UV + varying vec2 vUv; + uniform mat3 uvTransform; +#endif +void main() { + #ifdef USE_POINTS_UV + vUv = ( uvTransform * vec3( uv, 1 ) ).xy; + #endif + #include + #include + #include + #include + #include + #include + gl_PointSize = size; + #ifdef USE_SIZEATTENUATION + bool isPerspective = isPerspectiveMatrix( projectionMatrix ); + if ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z ); + #endif + #include + #include + #include + #include +}`,ly=`uniform vec3 diffuse; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + vec3 outgoingLight = vec3( 0.0 ); + #include + #include + #include + #include + #include + outgoingLight = diffuseColor.rgb; + #include + #include + #include + #include + #include +}`,cy=`#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +}`,uy=`uniform vec3 color; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + gl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) ); + #include + #include + #include +}`,hy=`uniform float rotation; +uniform vec2 center; +#include +#include +#include +#include +#include +void main() { + #include + vec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 ); + vec2 scale; + scale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) ); + scale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) ); + #ifndef USE_SIZEATTENUATION + bool isPerspective = isPerspectiveMatrix( projectionMatrix ); + if ( isPerspective ) scale *= - mvPosition.z; + #endif + vec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale; + vec2 rotatedPosition; + rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y; + rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y; + mvPosition.xy += rotatedPosition; + gl_Position = projectionMatrix * mvPosition; + #include + #include + #include +}`,dy=`uniform vec3 diffuse; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + vec3 outgoingLight = vec3( 0.0 ); + #include + #include + #include + #include + #include + outgoingLight = diffuseColor.rgb; + #include + #include + #include + #include +}`,nt={alphahash_fragment:Dv,alphahash_pars_fragment:Uv,alphamap_fragment:Ov,alphamap_pars_fragment:Fv,alphatest_fragment:kv,alphatest_pars_fragment:Bv,aomap_fragment:zv,aomap_pars_fragment:Vv,batching_pars_vertex:Hv,batching_vertex:Gv,begin_vertex:Wv,beginnormal_vertex:$v,bsdfs:Xv,iridescence_fragment:qv,bumpmap_pars_fragment:Yv,clipping_planes_fragment:Zv,clipping_planes_pars_fragment:Jv,clipping_planes_pars_vertex:Kv,clipping_planes_vertex:jv,color_fragment:Qv,color_pars_fragment:e_,color_pars_vertex:t_,color_vertex:n_,common:i_,cube_uv_reflection_fragment:s_,defaultnormal_vertex:r_,displacementmap_pars_vertex:o_,displacementmap_vertex:a_,emissivemap_fragment:l_,emissivemap_pars_fragment:c_,colorspace_fragment:u_,colorspace_pars_fragment:h_,envmap_fragment:d_,envmap_common_pars_fragment:f_,envmap_pars_fragment:p_,envmap_pars_vertex:m_,envmap_physical_pars_fragment:T_,envmap_vertex:g_,fog_vertex:v_,fog_pars_vertex:__,fog_fragment:y_,fog_pars_fragment:x_,gradientmap_pars_fragment:M_,lightmap_pars_fragment:b_,lights_lambert_fragment:S_,lights_lambert_pars_fragment:w_,lights_pars_begin:A_,lights_toon_fragment:E_,lights_toon_pars_fragment:C_,lights_phong_fragment:P_,lights_phong_pars_fragment:R_,lights_physical_fragment:I_,lights_physical_pars_fragment:L_,lights_fragment_begin:N_,lights_fragment_maps:D_,lights_fragment_end:U_,logdepthbuf_fragment:O_,logdepthbuf_pars_fragment:F_,logdepthbuf_pars_vertex:k_,logdepthbuf_vertex:B_,map_fragment:z_,map_pars_fragment:V_,map_particle_fragment:H_,map_particle_pars_fragment:G_,metalnessmap_fragment:W_,metalnessmap_pars_fragment:$_,morphinstance_vertex:X_,morphcolor_vertex:q_,morphnormal_vertex:Y_,morphtarget_pars_vertex:Z_,morphtarget_vertex:J_,normal_fragment_begin:K_,normal_fragment_maps:j_,normal_pars_fragment:Q_,normal_pars_vertex:e0,normal_vertex:t0,normalmap_pars_fragment:n0,clearcoat_normal_fragment_begin:i0,clearcoat_normal_fragment_maps:s0,clearcoat_pars_fragment:r0,iridescence_pars_fragment:o0,opaque_fragment:a0,packing:l0,premultiplied_alpha_fragment:c0,project_vertex:u0,dithering_fragment:h0,dithering_pars_fragment:d0,roughnessmap_fragment:f0,roughnessmap_pars_fragment:p0,shadowmap_pars_fragment:m0,shadowmap_pars_vertex:g0,shadowmap_vertex:v0,shadowmask_pars_fragment:_0,skinbase_vertex:y0,skinning_pars_vertex:x0,skinning_vertex:M0,skinnormal_vertex:b0,specularmap_fragment:S0,specularmap_pars_fragment:w0,tonemapping_fragment:A0,tonemapping_pars_fragment:T0,transmission_fragment:E0,transmission_pars_fragment:C0,uv_pars_fragment:P0,uv_pars_vertex:R0,uv_vertex:I0,worldpos_vertex:L0,background_vert:N0,background_frag:D0,backgroundCube_vert:U0,backgroundCube_frag:O0,cube_vert:F0,cube_frag:k0,depth_vert:B0,depth_frag:z0,distanceRGBA_vert:V0,distanceRGBA_frag:H0,equirect_vert:G0,equirect_frag:W0,linedashed_vert:$0,linedashed_frag:X0,meshbasic_vert:q0,meshbasic_frag:Y0,meshlambert_vert:Z0,meshlambert_frag:J0,meshmatcap_vert:K0,meshmatcap_frag:j0,meshnormal_vert:Q0,meshnormal_frag:ey,meshphong_vert:ty,meshphong_frag:ny,meshphysical_vert:iy,meshphysical_frag:sy,meshtoon_vert:ry,meshtoon_frag:oy,points_vert:ay,points_frag:ly,shadow_vert:cy,shadow_frag:uy,sprite_vert:hy,sprite_frag:dy},Ce={common:{diffuse:{value:new Pe(16777215)},opacity:{value:1},map:{value:null},mapTransform:{value:new Ze},alphaMap:{value:null},alphaMapTransform:{value:new Ze},alphaTest:{value:0}},specularmap:{specularMap:{value:null},specularMapTransform:{value:new Ze}},envmap:{envMap:{value:null},envMapRotation:{value:new Ze},flipEnvMap:{value:-1},reflectivity:{value:1},ior:{value:1.5},refractionRatio:{value:.98}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1},aoMapTransform:{value:new Ze}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1},lightMapTransform:{value:new Ze}},bumpmap:{bumpMap:{value:null},bumpMapTransform:{value:new Ze},bumpScale:{value:1}},normalmap:{normalMap:{value:null},normalMapTransform:{value:new Ze},normalScale:{value:new se(1,1)}},displacementmap:{displacementMap:{value:null},displacementMapTransform:{value:new Ze},displacementScale:{value:1},displacementBias:{value:0}},emissivemap:{emissiveMap:{value:null},emissiveMapTransform:{value:new Ze}},metalnessmap:{metalnessMap:{value:null},metalnessMapTransform:{value:new Ze}},roughnessmap:{roughnessMap:{value:null},roughnessMapTransform:{value:new Ze}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:25e-5},fogNear:{value:1},fogFar:{value:2e3},fogColor:{value:new Pe(16777215)}},lights:{ambientLightColor:{value:[]},lightProbe:{value:[]},directionalLights:{value:[],properties:{direction:{},color:{}}},directionalLightShadows:{value:[],properties:{shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},directionalShadowMap:{value:[]},directionalShadowMatrix:{value:[]},spotLights:{value:[],properties:{color:{},position:{},direction:{},distance:{},coneCos:{},penumbraCos:{},decay:{}}},spotLightShadows:{value:[],properties:{shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},spotLightMap:{value:[]},spotShadowMap:{value:[]},spotLightMatrix:{value:[]},pointLights:{value:[],properties:{color:{},position:{},decay:{},distance:{}}},pointLightShadows:{value:[],properties:{shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{},shadowCameraNear:{},shadowCameraFar:{}}},pointShadowMap:{value:[]},pointShadowMatrix:{value:[]},hemisphereLights:{value:[],properties:{direction:{},skyColor:{},groundColor:{}}},rectAreaLights:{value:[],properties:{color:{},position:{},width:{},height:{}}},ltc_1:{value:null},ltc_2:{value:null}},points:{diffuse:{value:new Pe(16777215)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},alphaMap:{value:null},alphaMapTransform:{value:new Ze},alphaTest:{value:0},uvTransform:{value:new Ze}},sprite:{diffuse:{value:new Pe(16777215)},opacity:{value:1},center:{value:new se(.5,.5)},rotation:{value:0},map:{value:null},mapTransform:{value:new Ze},alphaMap:{value:null},alphaMapTransform:{value:new Ze},alphaTest:{value:0}}},Tn={basic:{uniforms:en([Ce.common,Ce.specularmap,Ce.envmap,Ce.aomap,Ce.lightmap,Ce.fog]),vertexShader:nt.meshbasic_vert,fragmentShader:nt.meshbasic_frag},lambert:{uniforms:en([Ce.common,Ce.specularmap,Ce.envmap,Ce.aomap,Ce.lightmap,Ce.emissivemap,Ce.bumpmap,Ce.normalmap,Ce.displacementmap,Ce.fog,Ce.lights,{emissive:{value:new Pe(0)}}]),vertexShader:nt.meshlambert_vert,fragmentShader:nt.meshlambert_frag},phong:{uniforms:en([Ce.common,Ce.specularmap,Ce.envmap,Ce.aomap,Ce.lightmap,Ce.emissivemap,Ce.bumpmap,Ce.normalmap,Ce.displacementmap,Ce.fog,Ce.lights,{emissive:{value:new Pe(0)},specular:{value:new Pe(1118481)},shininess:{value:30}}]),vertexShader:nt.meshphong_vert,fragmentShader:nt.meshphong_frag},standard:{uniforms:en([Ce.common,Ce.envmap,Ce.aomap,Ce.lightmap,Ce.emissivemap,Ce.bumpmap,Ce.normalmap,Ce.displacementmap,Ce.roughnessmap,Ce.metalnessmap,Ce.fog,Ce.lights,{emissive:{value:new Pe(0)},roughness:{value:1},metalness:{value:0},envMapIntensity:{value:1}}]),vertexShader:nt.meshphysical_vert,fragmentShader:nt.meshphysical_frag},toon:{uniforms:en([Ce.common,Ce.aomap,Ce.lightmap,Ce.emissivemap,Ce.bumpmap,Ce.normalmap,Ce.displacementmap,Ce.gradientmap,Ce.fog,Ce.lights,{emissive:{value:new Pe(0)}}]),vertexShader:nt.meshtoon_vert,fragmentShader:nt.meshtoon_frag},matcap:{uniforms:en([Ce.common,Ce.bumpmap,Ce.normalmap,Ce.displacementmap,Ce.fog,{matcap:{value:null}}]),vertexShader:nt.meshmatcap_vert,fragmentShader:nt.meshmatcap_frag},points:{uniforms:en([Ce.points,Ce.fog]),vertexShader:nt.points_vert,fragmentShader:nt.points_frag},dashed:{uniforms:en([Ce.common,Ce.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:nt.linedashed_vert,fragmentShader:nt.linedashed_frag},depth:{uniforms:en([Ce.common,Ce.displacementmap]),vertexShader:nt.depth_vert,fragmentShader:nt.depth_frag},normal:{uniforms:en([Ce.common,Ce.bumpmap,Ce.normalmap,Ce.displacementmap,{opacity:{value:1}}]),vertexShader:nt.meshnormal_vert,fragmentShader:nt.meshnormal_frag},sprite:{uniforms:en([Ce.sprite,Ce.fog]),vertexShader:nt.sprite_vert,fragmentShader:nt.sprite_frag},background:{uniforms:{uvTransform:{value:new Ze},t2D:{value:null},backgroundIntensity:{value:1}},vertexShader:nt.background_vert,fragmentShader:nt.background_frag},backgroundCube:{uniforms:{envMap:{value:null},flipEnvMap:{value:-1},backgroundBlurriness:{value:0},backgroundIntensity:{value:1},backgroundRotation:{value:new Ze}},vertexShader:nt.backgroundCube_vert,fragmentShader:nt.backgroundCube_frag},cube:{uniforms:{tCube:{value:null},tFlip:{value:-1},opacity:{value:1}},vertexShader:nt.cube_vert,fragmentShader:nt.cube_frag},equirect:{uniforms:{tEquirect:{value:null}},vertexShader:nt.equirect_vert,fragmentShader:nt.equirect_frag},distanceRGBA:{uniforms:en([Ce.common,Ce.displacementmap,{referencePosition:{value:new N},nearDistance:{value:1},farDistance:{value:1e3}}]),vertexShader:nt.distanceRGBA_vert,fragmentShader:nt.distanceRGBA_frag},shadow:{uniforms:en([Ce.lights,Ce.fog,{color:{value:new Pe(0)},opacity:{value:1}}]),vertexShader:nt.shadow_vert,fragmentShader:nt.shadow_frag}};Tn.physical={uniforms:en([Tn.standard.uniforms,{clearcoat:{value:0},clearcoatMap:{value:null},clearcoatMapTransform:{value:new Ze},clearcoatNormalMap:{value:null},clearcoatNormalMapTransform:{value:new Ze},clearcoatNormalScale:{value:new se(1,1)},clearcoatRoughness:{value:0},clearcoatRoughnessMap:{value:null},clearcoatRoughnessMapTransform:{value:new Ze},dispersion:{value:0},iridescence:{value:0},iridescenceMap:{value:null},iridescenceMapTransform:{value:new Ze},iridescenceIOR:{value:1.3},iridescenceThicknessMinimum:{value:100},iridescenceThicknessMaximum:{value:400},iridescenceThicknessMap:{value:null},iridescenceThicknessMapTransform:{value:new Ze},sheen:{value:0},sheenColor:{value:new Pe(0)},sheenColorMap:{value:null},sheenColorMapTransform:{value:new Ze},sheenRoughness:{value:1},sheenRoughnessMap:{value:null},sheenRoughnessMapTransform:{value:new Ze},transmission:{value:0},transmissionMap:{value:null},transmissionMapTransform:{value:new Ze},transmissionSamplerSize:{value:new se},transmissionSamplerMap:{value:null},thickness:{value:0},thicknessMap:{value:null},thicknessMapTransform:{value:new Ze},attenuationDistance:{value:0},attenuationColor:{value:new Pe(0)},specularColor:{value:new Pe(1,1,1)},specularColorMap:{value:null},specularColorMapTransform:{value:new Ze},specularIntensity:{value:1},specularIntensityMap:{value:null},specularIntensityMapTransform:{value:new Ze},anisotropyVector:{value:new se},anisotropyMap:{value:null},anisotropyMapTransform:{value:new Ze}}]),vertexShader:nt.meshphysical_vert,fragmentShader:nt.meshphysical_frag};const To={r:0,b:0,g:0},zi=new _n,fy=new qe;function py(s,e,t,n,i,r,o){const a=new Pe(0);let l=r===!0?0:1,c,u,h=null,d=0,f=null;function g(y){let _=y.isScene===!0?y.background:null;return _&&_.isTexture&&(_=(y.backgroundBlurriness>0?t:e).get(_)),_}function v(y){let _=!1;const x=g(y);x===null?p(a,l):x&&x.isColor&&(p(x,1),_=!0);const A=s.xr.getEnvironmentBlendMode();A==="additive"?n.buffers.color.setClear(0,0,0,1,o):A==="alpha-blend"&&n.buffers.color.setClear(0,0,0,0,o),(s.autoClear||_)&&(n.buffers.depth.setTest(!0),n.buffers.depth.setMask(!0),n.buffers.color.setMask(!0),s.clear(s.autoClearColor,s.autoClearDepth,s.autoClearStencil))}function m(y,_){const x=g(_);x&&(x.isCubeTexture||x.mapping===Ws)?(u===void 0&&(u=new Nt(new cs(1,1,1),new Ln({name:"BackgroundCubeMaterial",uniforms:Hs(Tn.backgroundCube.uniforms),vertexShader:Tn.backgroundCube.vertexShader,fragmentShader:Tn.backgroundCube.fragmentShader,side:nn,depthTest:!1,depthWrite:!1,fog:!1})),u.geometry.deleteAttribute("normal"),u.geometry.deleteAttribute("uv"),u.onBeforeRender=function(A,b,E){this.matrixWorld.copyPosition(E.matrixWorld)},Object.defineProperty(u.material,"envMap",{get:function(){return this.uniforms.envMap.value}}),i.update(u)),zi.copy(_.backgroundRotation),zi.x*=-1,zi.y*=-1,zi.z*=-1,x.isCubeTexture&&x.isRenderTargetTexture===!1&&(zi.y*=-1,zi.z*=-1),u.material.uniforms.envMap.value=x,u.material.uniforms.flipEnvMap.value=x.isCubeTexture&&x.isRenderTargetTexture===!1?-1:1,u.material.uniforms.backgroundBlurriness.value=_.backgroundBlurriness,u.material.uniforms.backgroundIntensity.value=_.backgroundIntensity,u.material.uniforms.backgroundRotation.value.setFromMatrix4(fy.makeRotationFromEuler(zi)),u.material.toneMapped=ht.getTransfer(x.colorSpace)!==Mt,(h!==x||d!==x.version||f!==s.toneMapping)&&(u.material.needsUpdate=!0,h=x,d=x.version,f=s.toneMapping),u.layers.enableAll(),y.unshift(u,u.geometry,u.material,0,0,null)):x&&x.isTexture&&(c===void 0&&(c=new Nt(new Xs(2,2),new Ln({name:"BackgroundMaterial",uniforms:Hs(Tn.background.uniforms),vertexShader:Tn.background.vertexShader,fragmentShader:Tn.background.fragmentShader,side:oi,depthTest:!1,depthWrite:!1,fog:!1})),c.geometry.deleteAttribute("normal"),Object.defineProperty(c.material,"map",{get:function(){return this.uniforms.t2D.value}}),i.update(c)),c.material.uniforms.t2D.value=x,c.material.uniforms.backgroundIntensity.value=_.backgroundIntensity,c.material.toneMapped=ht.getTransfer(x.colorSpace)!==Mt,x.matrixAutoUpdate===!0&&x.updateMatrix(),c.material.uniforms.uvTransform.value.copy(x.matrix),(h!==x||d!==x.version||f!==s.toneMapping)&&(c.material.needsUpdate=!0,h=x,d=x.version,f=s.toneMapping),c.layers.enableAll(),y.unshift(c,c.geometry,c.material,0,0,null))}function p(y,_){y.getRGB(To,cp(s)),n.buffers.color.setClear(To.r,To.g,To.b,_,o)}return{getClearColor:function(){return a},setClearColor:function(y,_=1){a.set(y),l=_,p(a,l)},getClearAlpha:function(){return l},setClearAlpha:function(y){l=y,p(a,l)},render:v,addToRenderList:m}}function my(s,e){const t=s.getParameter(s.MAX_VERTEX_ATTRIBS),n={},i=d(null);let r=i,o=!1;function a(M,F,V,G,q){let ae=!1;const Q=h(G,V,F);r!==Q&&(r=Q,c(r.object)),ae=f(M,G,V,q),ae&&g(M,G,V,q),q!==null&&e.update(q,s.ELEMENT_ARRAY_BUFFER),(ae||o)&&(o=!1,x(M,F,V,G),q!==null&&s.bindBuffer(s.ELEMENT_ARRAY_BUFFER,e.get(q).buffer))}function l(){return s.createVertexArray()}function c(M){return s.bindVertexArray(M)}function u(M){return s.deleteVertexArray(M)}function h(M,F,V){const G=V.wireframe===!0;let q=n[M.id];q===void 0&&(q={},n[M.id]=q);let ae=q[F.id];ae===void 0&&(ae={},q[F.id]=ae);let Q=ae[G];return Q===void 0&&(Q=d(l()),ae[G]=Q),Q}function d(M){const F=[],V=[],G=[];for(let q=0;q=0){const be=q[B];let Ae=ae[B];if(Ae===void 0&&(B==="instanceMatrix"&&M.instanceMatrix&&(Ae=M.instanceMatrix),B==="instanceColor"&&M.instanceColor&&(Ae=M.instanceColor)),be===void 0||be.attribute!==Ae||Ae&&be.data!==Ae.data)return!0;Q++}return r.attributesNum!==Q||r.index!==G}function g(M,F,V,G){const q={},ae=F.attributes;let Q=0;const oe=V.getAttributes();for(const B in oe)if(oe[B].location>=0){let be=ae[B];be===void 0&&(B==="instanceMatrix"&&M.instanceMatrix&&(be=M.instanceMatrix),B==="instanceColor"&&M.instanceColor&&(be=M.instanceColor));const Ae={};Ae.attribute=be,be&&be.data&&(Ae.data=be.data),q[B]=Ae,Q++}r.attributes=q,r.attributesNum=Q,r.index=G}function v(){const M=r.newAttributes;for(let F=0,V=M.length;F=0){let Me=q[oe];if(Me===void 0&&(oe==="instanceMatrix"&&M.instanceMatrix&&(Me=M.instanceMatrix),oe==="instanceColor"&&M.instanceColor&&(Me=M.instanceColor)),Me!==void 0){const be=Me.normalized,Ae=Me.itemSize,ge=e.get(Me);if(ge===void 0)continue;const ze=ge.buffer,U=ge.type,D=ge.bytesPerElement,R=U===s.INT||U===s.UNSIGNED_INT||Me.gpuType===eu;if(Me.isInterleavedBufferAttribute){const T=Me.data,ie=T.stride,he=Me.offset;if(T.isInstancedInterleavedBuffer){for(let J=0;J0&&s.getShaderPrecisionFormat(s.FRAGMENT_SHADER,s.HIGH_FLOAT).precision>0)return"highp";b="mediump"}return b==="mediump"&&s.getShaderPrecisionFormat(s.VERTEX_SHADER,s.MEDIUM_FLOAT).precision>0&&s.getShaderPrecisionFormat(s.FRAGMENT_SHADER,s.MEDIUM_FLOAT).precision>0?"mediump":"lowp"}let c=t.precision!==void 0?t.precision:"highp";const u=l(c);u!==c&&(console.warn("THREE.WebGLRenderer:",c,"not supported, using",u,"instead."),c=u);const h=t.logarithmicDepthBuffer===!0,d=s.getParameter(s.MAX_TEXTURE_IMAGE_UNITS),f=s.getParameter(s.MAX_VERTEX_TEXTURE_IMAGE_UNITS),g=s.getParameter(s.MAX_TEXTURE_SIZE),v=s.getParameter(s.MAX_CUBE_MAP_TEXTURE_SIZE),m=s.getParameter(s.MAX_VERTEX_ATTRIBS),p=s.getParameter(s.MAX_VERTEX_UNIFORM_VECTORS),y=s.getParameter(s.MAX_VARYING_VECTORS),_=s.getParameter(s.MAX_FRAGMENT_UNIFORM_VECTORS),x=f>0,A=s.getParameter(s.MAX_SAMPLES);return{isWebGL2:!0,getMaxAnisotropy:r,getMaxPrecision:l,textureFormatReadable:o,textureTypeReadable:a,precision:c,logarithmicDepthBuffer:h,maxTextures:d,maxVertexTextures:f,maxTextureSize:g,maxCubemapSize:v,maxAttributes:m,maxVertexUniforms:p,maxVaryings:y,maxFragmentUniforms:_,vertexTextures:x,maxSamples:A}}function _y(s){const e=this;let t=null,n=0,i=!1,r=!1;const o=new wi,a=new Ze,l={value:null,needsUpdate:!1};this.uniform=l,this.numPlanes=0,this.numIntersection=0,this.init=function(h,d){const f=h.length!==0||d||n!==0||i;return i=d,n=h.length,f},this.beginShadows=function(){r=!0,u(null)},this.endShadows=function(){r=!1},this.setGlobalState=function(h,d){t=u(h,d,0)},this.setState=function(h,d,f){const g=h.clippingPlanes,v=h.clipIntersection,m=h.clipShadows,p=s.get(h);if(!i||g===null||g.length===0||r&&!m)r?u(null):c();else{const y=r?0:n,_=y*4;let x=p.clippingState||null;l.value=x,x=u(g,d,_,f);for(let A=0;A!==_;++A)x[A]=t[A];p.clippingState=x,this.numIntersection=v?this.numPlanes:0,this.numPlanes+=y}};function c(){l.value!==t&&(l.value=t,l.needsUpdate=n>0),e.numPlanes=n,e.numIntersection=0}function u(h,d,f,g){const v=h!==null?h.length:0;let m=null;if(v!==0){if(m=l.value,g!==!0||m===null){const p=f+v*4,y=d.matrixWorldInverse;a.getNormalMatrix(y),(m===null||m.length0){const c=new dp(l.height);return c.fromEquirectangularTexture(s,o),e.set(o,c),o.addEventListener("dispose",i),t(c.texture,o.mapping)}else return null}}return o}function i(o){const a=o.target;a.removeEventListener("dispose",i);const l=e.get(a);l!==void 0&&(e.delete(a),l.dispose())}function r(){e=new WeakMap}return{get:n,dispose:r}}class Na extends Xr{constructor(e=-1,t=1,n=1,i=-1,r=.1,o=2e3){super(),this.isOrthographicCamera=!0,this.type="OrthographicCamera",this.zoom=1,this.view=null,this.left=e,this.right=t,this.top=n,this.bottom=i,this.near=r,this.far=o,this.updateProjectionMatrix()}copy(e,t){return super.copy(e,t),this.left=e.left,this.right=e.right,this.top=e.top,this.bottom=e.bottom,this.near=e.near,this.far=e.far,this.zoom=e.zoom,this.view=e.view===null?null:Object.assign({},e.view),this}setViewOffset(e,t,n,i,r,o){this.view===null&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=e,this.view.fullHeight=t,this.view.offsetX=n,this.view.offsetY=i,this.view.width=r,this.view.height=o,this.updateProjectionMatrix()}clearViewOffset(){this.view!==null&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const e=(this.right-this.left)/(2*this.zoom),t=(this.top-this.bottom)/(2*this.zoom),n=(this.right+this.left)/2,i=(this.top+this.bottom)/2;let r=n-e,o=n+e,a=i+t,l=i-t;if(this.view!==null&&this.view.enabled){const c=(this.right-this.left)/this.view.fullWidth/this.zoom,u=(this.top-this.bottom)/this.view.fullHeight/this.zoom;r+=c*this.view.offsetX,o=r+c*this.view.width,a-=u*this.view.offsetY,l=a-u*this.view.height}this.projectionMatrix.makeOrthographic(r,o,a,l,this.near,this.far,this.coordinateSystem),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(e){const t=super.toJSON(e);return t.object.zoom=this.zoom,t.object.left=this.left,t.object.right=this.right,t.object.top=this.top,t.object.bottom=this.bottom,t.object.near=this.near,t.object.far=this.far,this.view!==null&&(t.object.view=Object.assign({},this.view)),t}}const Os=4,Mh=[.125,.215,.35,.446,.526,.582],Zi=20,El=new Na,bh=new Pe;let Cl=null,Pl=0,Rl=0,Il=!1;const Yi=(1+Math.sqrt(5))/2,Es=1/Yi,Sh=[new N(-Yi,Es,0),new N(Yi,Es,0),new N(-Es,0,Yi),new N(Es,0,Yi),new N(0,Yi,-Es),new N(0,Yi,Es),new N(-1,1,-1),new N(1,1,-1),new N(-1,1,1),new N(1,1,1)];class Ic{constructor(e){this._renderer=e,this._pingPongRenderTarget=null,this._lodMax=0,this._cubeSize=0,this._lodPlanes=[],this._sizeLods=[],this._sigmas=[],this._blurMaterial=null,this._cubemapMaterial=null,this._equirectMaterial=null,this._compileMaterial(this._blurMaterial)}fromScene(e,t=0,n=.1,i=100){Cl=this._renderer.getRenderTarget(),Pl=this._renderer.getActiveCubeFace(),Rl=this._renderer.getActiveMipmapLevel(),Il=this._renderer.xr.enabled,this._renderer.xr.enabled=!1,this._setSize(256);const r=this._allocateTargets();return r.depthBuffer=!0,this._sceneToCubeUV(e,n,i,r),t>0&&this._blur(r,0,0,t),this._applyPMREM(r),this._cleanup(r),r}fromEquirectangular(e,t=null){return this._fromTexture(e,t)}fromCubemap(e,t=null){return this._fromTexture(e,t)}compileCubemapShader(){this._cubemapMaterial===null&&(this._cubemapMaterial=Th(),this._compileMaterial(this._cubemapMaterial))}compileEquirectangularShader(){this._equirectMaterial===null&&(this._equirectMaterial=Ah(),this._compileMaterial(this._equirectMaterial))}dispose(){this._dispose(),this._cubemapMaterial!==null&&this._cubemapMaterial.dispose(),this._equirectMaterial!==null&&this._equirectMaterial.dispose()}_setSize(e){this._lodMax=Math.floor(Math.log2(e)),this._cubeSize=Math.pow(2,this._lodMax)}_dispose(){this._blurMaterial!==null&&this._blurMaterial.dispose(),this._pingPongRenderTarget!==null&&this._pingPongRenderTarget.dispose();for(let e=0;e2?_:0,_,_),u.setRenderTarget(i),v&&u.render(g,a),u.render(e,a)}g.geometry.dispose(),g.material.dispose(),u.toneMapping=d,u.autoClear=h,e.background=m}_textureToCubeUV(e,t){const n=this._renderer,i=e.mapping===ai||e.mapping===Ci;i?(this._cubemapMaterial===null&&(this._cubemapMaterial=Th()),this._cubemapMaterial.uniforms.flipEnvMap.value=e.isRenderTargetTexture===!1?-1:1):this._equirectMaterial===null&&(this._equirectMaterial=Ah());const r=i?this._cubemapMaterial:this._equirectMaterial,o=new Nt(this._lodPlanes[0],r),a=r.uniforms;a.envMap.value=e;const l=this._cubeSize;Eo(t,0,0,3*l,2*l),n.setRenderTarget(t),n.render(o,El)}_applyPMREM(e){const t=this._renderer,n=t.autoClear;t.autoClear=!1;const i=this._lodPlanes.length;for(let r=1;rZi&&console.warn(`sigmaRadians, ${r}, is too large and will clip, as it requested ${m} samples when the maximum is set to ${Zi}`);const p=[];let y=0;for(let E=0;E_-Os?i-_+Os:0),b=4*(this._cubeSize-x);Eo(t,A,b,3*x,2*x),l.setRenderTarget(t),l.render(h,El)}}function xy(s){const e=[],t=[],n=[];let i=s;const r=s-Os+1+Mh.length;for(let o=0;os-Os?l=Mh[o-s+Os-1]:o===0&&(l=0),n.push(l);const c=1/(a-2),u=-c,h=1+c,d=[u,u,h,u,h,h,u,u,h,h,u,h],f=6,g=6,v=3,m=2,p=1,y=new Float32Array(v*g*f),_=new Float32Array(m*g*f),x=new Float32Array(p*g*f);for(let b=0;b2?0:-1,w=[E,I,0,E+2/3,I,0,E+2/3,I+1,0,E,I,0,E+2/3,I+1,0,E,I+1,0];y.set(w,v*g*b),_.set(d,m*g*b);const M=[b,b,b,b,b,b];x.set(M,p*g*b)}const A=new it;A.setAttribute("position",new pt(y,v)),A.setAttribute("uv",new pt(_,m)),A.setAttribute("faceIndex",new pt(x,p)),e.push(A),i>Os&&i--}return{lodPlanes:e,sizeLods:t,sigmas:n}}function wh(s,e,t){const n=new In(s,e,t);return n.texture.mapping=Ws,n.texture.name="PMREM.cubeUv",n.scissorTest=!0,n}function Eo(s,e,t,n,i){s.viewport.set(e,t,n,i),s.scissor.set(e,t,n,i)}function My(s,e,t){const n=new Float32Array(Zi),i=new N(0,1,0);return new Ln({name:"SphericalGaussianBlur",defines:{n:Zi,CUBEUV_TEXEL_WIDTH:1/e,CUBEUV_TEXEL_HEIGHT:1/t,CUBEUV_MAX_MIP:`${s}.0`},uniforms:{envMap:{value:null},samples:{value:1},weights:{value:n},latitudinal:{value:!1},dTheta:{value:0},mipInt:{value:0},poleAxis:{value:i}},vertexShader:pu(),fragmentShader:` + + precision mediump float; + precision mediump int; + + varying vec3 vOutputDirection; + + uniform sampler2D envMap; + uniform int samples; + uniform float weights[ n ]; + uniform bool latitudinal; + uniform float dTheta; + uniform float mipInt; + uniform vec3 poleAxis; + + #define ENVMAP_TYPE_CUBE_UV + #include + + vec3 getSample( float theta, vec3 axis ) { + + float cosTheta = cos( theta ); + // Rodrigues' axis-angle rotation + vec3 sampleDirection = vOutputDirection * cosTheta + + cross( axis, vOutputDirection ) * sin( theta ) + + axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta ); + + return bilinearCubeUV( envMap, sampleDirection, mipInt ); + + } + + void main() { + + vec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection ); + + if ( all( equal( axis, vec3( 0.0 ) ) ) ) { + + axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x ); + + } + + axis = normalize( axis ); + + gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 ); + gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis ); + + for ( int i = 1; i < n; i++ ) { + + if ( i >= samples ) { + + break; + + } + + float theta = dTheta * float( i ); + gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis ); + gl_FragColor.rgb += weights[ i ] * getSample( theta, axis ); + + } + + } + `,blending:si,depthTest:!1,depthWrite:!1})}function Ah(){return new Ln({name:"EquirectangularToCubeUV",uniforms:{envMap:{value:null}},vertexShader:pu(),fragmentShader:` + + precision mediump float; + precision mediump int; + + varying vec3 vOutputDirection; + + uniform sampler2D envMap; + + #include + + void main() { + + vec3 outputDirection = normalize( vOutputDirection ); + vec2 uv = equirectUv( outputDirection ); + + gl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 ); + + } + `,blending:si,depthTest:!1,depthWrite:!1})}function Th(){return new Ln({name:"CubemapToCubeUV",uniforms:{envMap:{value:null},flipEnvMap:{value:-1}},vertexShader:pu(),fragmentShader:` + + precision mediump float; + precision mediump int; + + uniform float flipEnvMap; + + varying vec3 vOutputDirection; + + uniform samplerCube envMap; + + void main() { + + gl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) ); + + } + `,blending:si,depthTest:!1,depthWrite:!1})}function pu(){return` + + precision mediump float; + precision mediump int; + + attribute float faceIndex; + + varying vec3 vOutputDirection; + + // RH coordinate system; PMREM face-indexing convention + vec3 getDirection( vec2 uv, float face ) { + + uv = 2.0 * uv - 1.0; + + vec3 direction = vec3( uv, 1.0 ); + + if ( face == 0.0 ) { + + direction = direction.zyx; // ( 1, v, u ) pos x + + } else if ( face == 1.0 ) { + + direction = direction.xzy; + direction.xz *= -1.0; // ( -u, 1, -v ) pos y + + } else if ( face == 2.0 ) { + + direction.x *= -1.0; // ( -u, v, 1 ) pos z + + } else if ( face == 3.0 ) { + + direction = direction.zyx; + direction.xz *= -1.0; // ( -1, v, -u ) neg x + + } else if ( face == 4.0 ) { + + direction = direction.xzy; + direction.xy *= -1.0; // ( -u, -1, v ) neg y + + } else if ( face == 5.0 ) { + + direction.z *= -1.0; // ( u, v, -1 ) neg z + + } + + return direction; + + } + + void main() { + + vOutputDirection = getDirection( uv, faceIndex ); + gl_Position = vec4( position, 1.0 ); + + } + `}function by(s){let e=new WeakMap,t=null;function n(a){if(a&&a.isTexture){const l=a.mapping,c=l===yr||l===xr,u=l===ai||l===Ci;if(c||u){let h=e.get(a);const d=h!==void 0?h.texture.pmremVersion:0;if(a.isRenderTargetTexture&&a.pmremVersion!==d)return t===null&&(t=new Ic(s)),h=c?t.fromEquirectangular(a,h):t.fromCubemap(a,h),h.texture.pmremVersion=a.pmremVersion,e.set(a,h),h.texture;if(h!==void 0)return h.texture;{const f=a.image;return c&&f&&f.height>0||u&&f&&i(f)?(t===null&&(t=new Ic(s)),h=c?t.fromEquirectangular(a):t.fromCubemap(a),h.texture.pmremVersion=a.pmremVersion,e.set(a,h),a.addEventListener("dispose",r),h.texture):null}}}return a}function i(a){let l=0;const c=6;for(let u=0;ue.maxTextureSize&&(A=Math.ceil(x/e.maxTextureSize),x=e.maxTextureSize);const b=new Float32Array(x*A*4*h),E=new Ia(b,x,A,h);E.type=gn,E.needsUpdate=!0;const I=_*4;for(let M=0;M0)return s;const i=e*t;let r=Eh[i];if(r===void 0&&(r=new Float32Array(i),Eh[i]=r),e!==0){n.toArray(r,0);for(let o=1,a=0;o!==e;++o)a+=t,s[o].toArray(r,a)}return r}function Ft(s,e){if(s.length!==e.length)return!1;for(let t=0,n=s.length;t":" "} ${a}: ${t[o]}`)}return n.join(` +`)}function bx(s){const e=ht.getPrimaries(ht.workingColorSpace),t=ht.getPrimaries(s);let n;switch(e===t?n="":e===Cr&&t===Er?n="LinearDisplayP3ToLinearSRGB":e===Er&&t===Cr&&(n="LinearSRGBToLinearDisplayP3"),s){case ci:case $r:return[n,"LinearTransferOETF"];case ln:case Ra:return[n,"sRGBTransferOETF"];default:return console.warn("THREE.WebGLProgram: Unsupported color space:",s),[n,"LinearTransferOETF"]}}function Dh(s,e,t){const n=s.getShaderParameter(e,s.COMPILE_STATUS),i=s.getShaderInfoLog(e).trim();if(n&&i==="")return"";const r=/ERROR: 0:(\d+)/.exec(i);if(r){const o=parseInt(r[1]);return t.toUpperCase()+` + +`+i+` + +`+Mx(s.getShaderSource(e),o)}else return i}function Sx(s,e){const t=bx(e);return`vec4 ${s}( vec4 value ) { return ${t[0]}( ${t[1]}( value ) ); }`}function wx(s,e){let t;switch(e){case Ef:t="Linear";break;case Cf:t="Reinhard";break;case Pf:t="OptimizedCineon";break;case Ea:t="ACESFilmic";break;case If:t="AgX";break;case Lf:t="Neutral";break;case Rf:t="Custom";break;default:console.warn("THREE.WebGLProgram: Unsupported toneMapping:",e),t="Linear"}return"vec3 "+s+"( vec3 color ) { return "+t+"ToneMapping( color ); }"}function Ax(s){return[s.extensionClipCullDistance?"#extension GL_ANGLE_clip_cull_distance : require":"",s.extensionMultiDraw?"#extension GL_ANGLE_multi_draw : require":""].filter(ur).join(` +`)}function Tx(s){const e=[];for(const t in s){const n=s[t];n!==!1&&e.push("#define "+t+" "+n)}return e.join(` +`)}function Ex(s,e){const t={},n=s.getProgramParameter(e,s.ACTIVE_ATTRIBUTES);for(let i=0;i/gm;function Lc(s){return s.replace(Cx,Rx)}const Px=new Map;function Rx(s,e){let t=nt[e];if(t===void 0){const n=Px.get(e);if(n!==void 0)t=nt[n],console.warn('THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.',e,n);else throw new Error("Can not resolve #include <"+e+">")}return Lc(t)}const Ix=/#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g;function Fh(s){return s.replace(Ix,Lx)}function Lx(s,e,t,n){let i="";for(let r=parseInt(e);r0&&(m+=` +`),p=["#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,g].filter(ur).join(` +`),p.length>0&&(p+=` +`)):(m=[kh(t),"#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,g,t.extensionClipCullDistance?"#define USE_CLIP_DISTANCE":"",t.batching?"#define USE_BATCHING":"",t.batchingColor?"#define USE_BATCHING_COLOR":"",t.instancing?"#define USE_INSTANCING":"",t.instancingColor?"#define USE_INSTANCING_COLOR":"",t.instancingMorph?"#define USE_INSTANCING_MORPH":"",t.useFog&&t.fog?"#define USE_FOG":"",t.useFog&&t.fogExp2?"#define FOG_EXP2":"",t.map?"#define USE_MAP":"",t.envMap?"#define USE_ENVMAP":"",t.envMap?"#define "+u:"",t.lightMap?"#define USE_LIGHTMAP":"",t.aoMap?"#define USE_AOMAP":"",t.bumpMap?"#define USE_BUMPMAP":"",t.normalMap?"#define USE_NORMALMAP":"",t.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",t.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",t.displacementMap?"#define USE_DISPLACEMENTMAP":"",t.emissiveMap?"#define USE_EMISSIVEMAP":"",t.anisotropy?"#define USE_ANISOTROPY":"",t.anisotropyMap?"#define USE_ANISOTROPYMAP":"",t.clearcoatMap?"#define USE_CLEARCOATMAP":"",t.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",t.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",t.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",t.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",t.specularMap?"#define USE_SPECULARMAP":"",t.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",t.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",t.roughnessMap?"#define USE_ROUGHNESSMAP":"",t.metalnessMap?"#define USE_METALNESSMAP":"",t.alphaMap?"#define USE_ALPHAMAP":"",t.alphaHash?"#define USE_ALPHAHASH":"",t.transmission?"#define USE_TRANSMISSION":"",t.transmissionMap?"#define USE_TRANSMISSIONMAP":"",t.thicknessMap?"#define USE_THICKNESSMAP":"",t.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",t.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",t.mapUv?"#define MAP_UV "+t.mapUv:"",t.alphaMapUv?"#define ALPHAMAP_UV "+t.alphaMapUv:"",t.lightMapUv?"#define LIGHTMAP_UV "+t.lightMapUv:"",t.aoMapUv?"#define AOMAP_UV "+t.aoMapUv:"",t.emissiveMapUv?"#define EMISSIVEMAP_UV "+t.emissiveMapUv:"",t.bumpMapUv?"#define BUMPMAP_UV "+t.bumpMapUv:"",t.normalMapUv?"#define NORMALMAP_UV "+t.normalMapUv:"",t.displacementMapUv?"#define DISPLACEMENTMAP_UV "+t.displacementMapUv:"",t.metalnessMapUv?"#define METALNESSMAP_UV "+t.metalnessMapUv:"",t.roughnessMapUv?"#define ROUGHNESSMAP_UV "+t.roughnessMapUv:"",t.anisotropyMapUv?"#define ANISOTROPYMAP_UV "+t.anisotropyMapUv:"",t.clearcoatMapUv?"#define CLEARCOATMAP_UV "+t.clearcoatMapUv:"",t.clearcoatNormalMapUv?"#define CLEARCOAT_NORMALMAP_UV "+t.clearcoatNormalMapUv:"",t.clearcoatRoughnessMapUv?"#define CLEARCOAT_ROUGHNESSMAP_UV "+t.clearcoatRoughnessMapUv:"",t.iridescenceMapUv?"#define IRIDESCENCEMAP_UV "+t.iridescenceMapUv:"",t.iridescenceThicknessMapUv?"#define IRIDESCENCE_THICKNESSMAP_UV "+t.iridescenceThicknessMapUv:"",t.sheenColorMapUv?"#define SHEEN_COLORMAP_UV "+t.sheenColorMapUv:"",t.sheenRoughnessMapUv?"#define SHEEN_ROUGHNESSMAP_UV "+t.sheenRoughnessMapUv:"",t.specularMapUv?"#define SPECULARMAP_UV "+t.specularMapUv:"",t.specularColorMapUv?"#define SPECULAR_COLORMAP_UV "+t.specularColorMapUv:"",t.specularIntensityMapUv?"#define SPECULAR_INTENSITYMAP_UV "+t.specularIntensityMapUv:"",t.transmissionMapUv?"#define TRANSMISSIONMAP_UV "+t.transmissionMapUv:"",t.thicknessMapUv?"#define THICKNESSMAP_UV "+t.thicknessMapUv:"",t.vertexTangents&&t.flatShading===!1?"#define USE_TANGENT":"",t.vertexColors?"#define USE_COLOR":"",t.vertexAlphas?"#define USE_COLOR_ALPHA":"",t.vertexUv1s?"#define USE_UV1":"",t.vertexUv2s?"#define USE_UV2":"",t.vertexUv3s?"#define USE_UV3":"",t.pointsUvs?"#define USE_POINTS_UV":"",t.flatShading?"#define FLAT_SHADED":"",t.skinning?"#define USE_SKINNING":"",t.morphTargets?"#define USE_MORPHTARGETS":"",t.morphNormals&&t.flatShading===!1?"#define USE_MORPHNORMALS":"",t.morphColors?"#define USE_MORPHCOLORS":"",t.morphTargetsCount>0?"#define MORPHTARGETS_TEXTURE_STRIDE "+t.morphTextureStride:"",t.morphTargetsCount>0?"#define MORPHTARGETS_COUNT "+t.morphTargetsCount:"",t.doubleSided?"#define DOUBLE_SIDED":"",t.flipSided?"#define FLIP_SIDED":"",t.shadowMapEnabled?"#define USE_SHADOWMAP":"",t.shadowMapEnabled?"#define "+l:"",t.sizeAttenuation?"#define USE_SIZEATTENUATION":"",t.numLightProbes>0?"#define USE_LIGHT_PROBES":"",t.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"","uniform mat4 modelMatrix;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform mat4 viewMatrix;","uniform mat3 normalMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;","#ifdef USE_INSTANCING"," attribute mat4 instanceMatrix;","#endif","#ifdef USE_INSTANCING_COLOR"," attribute vec3 instanceColor;","#endif","#ifdef USE_INSTANCING_MORPH"," uniform sampler2D morphTexture;","#endif","attribute vec3 position;","attribute vec3 normal;","attribute vec2 uv;","#ifdef USE_UV1"," attribute vec2 uv1;","#endif","#ifdef USE_UV2"," attribute vec2 uv2;","#endif","#ifdef USE_UV3"," attribute vec2 uv3;","#endif","#ifdef USE_TANGENT"," attribute vec4 tangent;","#endif","#if defined( USE_COLOR_ALPHA )"," attribute vec4 color;","#elif defined( USE_COLOR )"," attribute vec3 color;","#endif","#ifdef USE_SKINNING"," attribute vec4 skinIndex;"," attribute vec4 skinWeight;","#endif",` +`].filter(ur).join(` +`),p=[kh(t),"#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,g,t.useFog&&t.fog?"#define USE_FOG":"",t.useFog&&t.fogExp2?"#define FOG_EXP2":"",t.alphaToCoverage?"#define ALPHA_TO_COVERAGE":"",t.map?"#define USE_MAP":"",t.matcap?"#define USE_MATCAP":"",t.envMap?"#define USE_ENVMAP":"",t.envMap?"#define "+c:"",t.envMap?"#define "+u:"",t.envMap?"#define "+h:"",d?"#define CUBEUV_TEXEL_WIDTH "+d.texelWidth:"",d?"#define CUBEUV_TEXEL_HEIGHT "+d.texelHeight:"",d?"#define CUBEUV_MAX_MIP "+d.maxMip+".0":"",t.lightMap?"#define USE_LIGHTMAP":"",t.aoMap?"#define USE_AOMAP":"",t.bumpMap?"#define USE_BUMPMAP":"",t.normalMap?"#define USE_NORMALMAP":"",t.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",t.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",t.emissiveMap?"#define USE_EMISSIVEMAP":"",t.anisotropy?"#define USE_ANISOTROPY":"",t.anisotropyMap?"#define USE_ANISOTROPYMAP":"",t.clearcoat?"#define USE_CLEARCOAT":"",t.clearcoatMap?"#define USE_CLEARCOATMAP":"",t.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",t.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",t.dispersion?"#define USE_DISPERSION":"",t.iridescence?"#define USE_IRIDESCENCE":"",t.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",t.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",t.specularMap?"#define USE_SPECULARMAP":"",t.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",t.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",t.roughnessMap?"#define USE_ROUGHNESSMAP":"",t.metalnessMap?"#define USE_METALNESSMAP":"",t.alphaMap?"#define USE_ALPHAMAP":"",t.alphaTest?"#define USE_ALPHATEST":"",t.alphaHash?"#define USE_ALPHAHASH":"",t.sheen?"#define USE_SHEEN":"",t.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",t.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",t.transmission?"#define USE_TRANSMISSION":"",t.transmissionMap?"#define USE_TRANSMISSIONMAP":"",t.thicknessMap?"#define USE_THICKNESSMAP":"",t.vertexTangents&&t.flatShading===!1?"#define USE_TANGENT":"",t.vertexColors||t.instancingColor||t.batchingColor?"#define USE_COLOR":"",t.vertexAlphas?"#define USE_COLOR_ALPHA":"",t.vertexUv1s?"#define USE_UV1":"",t.vertexUv2s?"#define USE_UV2":"",t.vertexUv3s?"#define USE_UV3":"",t.pointsUvs?"#define USE_POINTS_UV":"",t.gradientMap?"#define USE_GRADIENTMAP":"",t.flatShading?"#define FLAT_SHADED":"",t.doubleSided?"#define DOUBLE_SIDED":"",t.flipSided?"#define FLIP_SIDED":"",t.shadowMapEnabled?"#define USE_SHADOWMAP":"",t.shadowMapEnabled?"#define "+l:"",t.premultipliedAlpha?"#define PREMULTIPLIED_ALPHA":"",t.numLightProbes>0?"#define USE_LIGHT_PROBES":"",t.decodeVideoTexture?"#define DECODE_VIDEO_TEXTURE":"",t.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;",t.toneMapping!==Hn?"#define TONE_MAPPING":"",t.toneMapping!==Hn?nt.tonemapping_pars_fragment:"",t.toneMapping!==Hn?wx("toneMapping",t.toneMapping):"",t.dithering?"#define DITHERING":"",t.opaque?"#define OPAQUE":"",nt.colorspace_pars_fragment,Sx("linearToOutputTexel",t.outputColorSpace),t.useDepthPacking?"#define DEPTH_PACKING "+t.depthPacking:"",` +`].filter(ur).join(` +`)),o=Lc(o),o=Uh(o,t),o=Oh(o,t),a=Lc(a),a=Uh(a,t),a=Oh(a,t),o=Fh(o),a=Fh(a),t.isRawShaderMaterial!==!0&&(y=`#version 300 es +`,m=[f,"#define attribute in","#define varying out","#define texture2D texture"].join(` +`)+` +`+m,p=["#define varying in",t.glslVersion===Rc?"":"layout(location = 0) out highp vec4 pc_fragColor;",t.glslVersion===Rc?"":"#define gl_FragColor pc_fragColor","#define gl_FragDepthEXT gl_FragDepth","#define texture2D texture","#define textureCube texture","#define texture2DProj textureProj","#define texture2DLodEXT textureLod","#define texture2DProjLodEXT textureProjLod","#define textureCubeLodEXT textureLod","#define texture2DGradEXT textureGrad","#define texture2DProjGradEXT textureProjGrad","#define textureCubeGradEXT textureGrad"].join(` +`)+` +`+p);const _=y+m+o,x=y+p+a,A=Nh(i,i.VERTEX_SHADER,_),b=Nh(i,i.FRAGMENT_SHADER,x);i.attachShader(v,A),i.attachShader(v,b),t.index0AttributeName!==void 0?i.bindAttribLocation(v,0,t.index0AttributeName):t.morphTargets===!0&&i.bindAttribLocation(v,0,"position"),i.linkProgram(v);function E(F){if(s.debug.checkShaderErrors){const V=i.getProgramInfoLog(v).trim(),G=i.getShaderInfoLog(A).trim(),q=i.getShaderInfoLog(b).trim();let ae=!0,Q=!0;if(i.getProgramParameter(v,i.LINK_STATUS)===!1)if(ae=!1,typeof s.debug.onShaderError=="function")s.debug.onShaderError(i,v,A,b);else{const oe=Dh(i,A,"vertex"),B=Dh(i,b,"fragment");console.error("THREE.WebGLProgram: Shader Error "+i.getError()+" - VALIDATE_STATUS "+i.getProgramParameter(v,i.VALIDATE_STATUS)+` + +Material Name: `+F.name+` +Material Type: `+F.type+` + +Program Info Log: `+V+` +`+oe+` +`+B)}else V!==""?console.warn("THREE.WebGLProgram: Program Info Log:",V):(G===""||q==="")&&(Q=!1);Q&&(F.diagnostics={runnable:ae,programLog:V,vertexShader:{log:G,prefix:m},fragmentShader:{log:q,prefix:p}})}i.deleteShader(A),i.deleteShader(b),I=new ua(i,v),w=Ex(i,v)}let I;this.getUniforms=function(){return I===void 0&&E(this),I};let w;this.getAttributes=function(){return w===void 0&&E(this),w};let M=t.rendererExtensionParallelShaderCompile===!1;return this.isReady=function(){return M===!1&&(M=i.getProgramParameter(v,yx)),M},this.destroy=function(){n.releaseStatesOfProgram(this),i.deleteProgram(v),this.program=void 0},this.type=t.shaderType,this.name=t.shaderName,this.id=xx++,this.cacheKey=e,this.usedTimes=1,this.program=v,this.vertexShader=A,this.fragmentShader=b,this}let Bx=0;class zx{constructor(){this.shaderCache=new Map,this.materialCache=new Map}update(e){const t=e.vertexShader,n=e.fragmentShader,i=this._getShaderStage(t),r=this._getShaderStage(n),o=this._getShaderCacheForMaterial(e);return o.has(i)===!1&&(o.add(i),i.usedTimes++),o.has(r)===!1&&(o.add(r),r.usedTimes++),this}remove(e){const t=this.materialCache.get(e);for(const n of t)n.usedTimes--,n.usedTimes===0&&this.shaderCache.delete(n.code);return this.materialCache.delete(e),this}getVertexShaderID(e){return this._getShaderStage(e.vertexShader).id}getFragmentShaderID(e){return this._getShaderStage(e.fragmentShader).id}dispose(){this.shaderCache.clear(),this.materialCache.clear()}_getShaderCacheForMaterial(e){const t=this.materialCache;let n=t.get(e);return n===void 0&&(n=new Set,t.set(e,n)),n}_getShaderStage(e){const t=this.shaderCache;let n=t.get(e);return n===void 0&&(n=new Vx(e),t.set(e,n)),n}}class Vx{constructor(e){this.id=Bx++,this.code=e,this.usedTimes=0}}function Hx(s,e,t,n,i,r,o){const a=new La,l=new zx,c=new Set,u=[],h=i.logarithmicDepthBuffer,d=i.vertexTextures;let f=i.precision;const g={MeshDepthMaterial:"depth",MeshDistanceMaterial:"distanceRGBA",MeshNormalMaterial:"normal",MeshBasicMaterial:"basic",MeshLambertMaterial:"lambert",MeshPhongMaterial:"phong",MeshToonMaterial:"toon",MeshStandardMaterial:"physical",MeshPhysicalMaterial:"physical",MeshMatcapMaterial:"matcap",LineBasicMaterial:"basic",LineDashedMaterial:"dashed",PointsMaterial:"points",ShadowMaterial:"shadow",SpriteMaterial:"sprite"};function v(w){return c.add(w),w===0?"uv":`uv${w}`}function m(w,M,F,V,G){const q=V.fog,ae=G.geometry,Q=w.isMeshStandardMaterial?V.environment:null,oe=(w.isMeshStandardMaterial?t:e).get(w.envMap||Q),B=oe&&oe.mapping===Ws?oe.image.height:null,Me=g[w.type];w.precision!==null&&(f=i.getMaxPrecision(w.precision),f!==w.precision&&console.warn("THREE.WebGLProgram.getParameters:",w.precision,"not supported, using",f,"instead."));const be=ae.morphAttributes.position||ae.morphAttributes.normal||ae.morphAttributes.color,Ae=be!==void 0?be.length:0;let ge=0;ae.morphAttributes.position!==void 0&&(ge=1),ae.morphAttributes.normal!==void 0&&(ge=2),ae.morphAttributes.color!==void 0&&(ge=3);let ze,U,D,R;if(Me){const vt=Tn[Me];ze=vt.vertexShader,U=vt.fragmentShader}else ze=w.vertexShader,U=w.fragmentShader,l.update(w),D=l.getVertexShaderID(w),R=l.getFragmentShaderID(w);const T=s.getRenderTarget(),ie=G.isInstancedMesh===!0,he=G.isBatchedMesh===!0,J=!!w.map,L=!!w.matcap,X=!!oe,K=!!w.aoMap,H=!!w.lightMap,$=!!w.bumpMap,te=!!w.normalMap,le=!!w.displacementMap,k=!!w.emissiveMap,O=!!w.metalnessMap,P=!!w.roughnessMap,S=w.anisotropy>0,ee=w.clearcoat>0,pe=w.dispersion>0,ce=w.iridescence>0,ve=w.sheen>0,Ve=w.transmission>0,Ee=S&&!!w.anisotropyMap,Te=ee&&!!w.clearcoatMap,Qe=ee&&!!w.clearcoatNormalMap,xe=ee&&!!w.clearcoatRoughnessMap,Ue=ce&&!!w.iridescenceMap,st=ce&&!!w.iridescenceThicknessMap,Je=ve&&!!w.sheenColorMap,Re=ve&&!!w.sheenRoughnessMap,rt=!!w.specularMap,at=!!w.specularColorMap,Rt=!!w.specularIntensityMap,z=Ve&&!!w.transmissionMap,Ie=Ve&&!!w.thicknessMap,de=!!w.gradientMap,_e=!!w.alphaMap,we=w.alphaTest>0,et=!!w.alphaHash,ut=!!w.extensions;let It=Hn;w.toneMapped&&(T===null||T.isXRRenderTarget===!0)&&(It=s.toneMapping);const Bt={shaderID:Me,shaderType:w.type,shaderName:w.name,vertexShader:ze,fragmentShader:U,defines:w.defines,customVertexShaderID:D,customFragmentShaderID:R,isRawShaderMaterial:w.isRawShaderMaterial===!0,glslVersion:w.glslVersion,precision:f,batching:he,batchingColor:he&&G._colorsTexture!==null,instancing:ie,instancingColor:ie&&G.instanceColor!==null,instancingMorph:ie&&G.morphTexture!==null,supportsVertexTextures:d,outputColorSpace:T===null?s.outputColorSpace:T.isXRRenderTarget===!0?T.texture.colorSpace:ci,alphaToCoverage:!!w.alphaToCoverage,map:J,matcap:L,envMap:X,envMapMode:X&&oe.mapping,envMapCubeUVHeight:B,aoMap:K,lightMap:H,bumpMap:$,normalMap:te,displacementMap:d&&le,emissiveMap:k,normalMapObjectSpace:te&&w.normalMapType===Yf,normalMapTangentSpace:te&&w.normalMapType===Ii,metalnessMap:O,roughnessMap:P,anisotropy:S,anisotropyMap:Ee,clearcoat:ee,clearcoatMap:Te,clearcoatNormalMap:Qe,clearcoatRoughnessMap:xe,dispersion:pe,iridescence:ce,iridescenceMap:Ue,iridescenceThicknessMap:st,sheen:ve,sheenColorMap:Je,sheenRoughnessMap:Re,specularMap:rt,specularColorMap:at,specularIntensityMap:Rt,transmission:Ve,transmissionMap:z,thicknessMap:Ie,gradientMap:de,opaque:w.transparent===!1&&w.blending===es&&w.alphaToCoverage===!1,alphaMap:_e,alphaTest:we,alphaHash:et,combine:w.combine,mapUv:J&&v(w.map.channel),aoMapUv:K&&v(w.aoMap.channel),lightMapUv:H&&v(w.lightMap.channel),bumpMapUv:$&&v(w.bumpMap.channel),normalMapUv:te&&v(w.normalMap.channel),displacementMapUv:le&&v(w.displacementMap.channel),emissiveMapUv:k&&v(w.emissiveMap.channel),metalnessMapUv:O&&v(w.metalnessMap.channel),roughnessMapUv:P&&v(w.roughnessMap.channel),anisotropyMapUv:Ee&&v(w.anisotropyMap.channel),clearcoatMapUv:Te&&v(w.clearcoatMap.channel),clearcoatNormalMapUv:Qe&&v(w.clearcoatNormalMap.channel),clearcoatRoughnessMapUv:xe&&v(w.clearcoatRoughnessMap.channel),iridescenceMapUv:Ue&&v(w.iridescenceMap.channel),iridescenceThicknessMapUv:st&&v(w.iridescenceThicknessMap.channel),sheenColorMapUv:Je&&v(w.sheenColorMap.channel),sheenRoughnessMapUv:Re&&v(w.sheenRoughnessMap.channel),specularMapUv:rt&&v(w.specularMap.channel),specularColorMapUv:at&&v(w.specularColorMap.channel),specularIntensityMapUv:Rt&&v(w.specularIntensityMap.channel),transmissionMapUv:z&&v(w.transmissionMap.channel),thicknessMapUv:Ie&&v(w.thicknessMap.channel),alphaMapUv:_e&&v(w.alphaMap.channel),vertexTangents:!!ae.attributes.tangent&&(te||S),vertexColors:w.vertexColors,vertexAlphas:w.vertexColors===!0&&!!ae.attributes.color&&ae.attributes.color.itemSize===4,pointsUvs:G.isPoints===!0&&!!ae.attributes.uv&&(J||_e),fog:!!q,useFog:w.fog===!0,fogExp2:!!q&&q.isFogExp2,flatShading:w.flatShading===!0,sizeAttenuation:w.sizeAttenuation===!0,logarithmicDepthBuffer:h,skinning:G.isSkinnedMesh===!0,morphTargets:ae.morphAttributes.position!==void 0,morphNormals:ae.morphAttributes.normal!==void 0,morphColors:ae.morphAttributes.color!==void 0,morphTargetsCount:Ae,morphTextureStride:ge,numDirLights:M.directional.length,numPointLights:M.point.length,numSpotLights:M.spot.length,numSpotLightMaps:M.spotLightMap.length,numRectAreaLights:M.rectArea.length,numHemiLights:M.hemi.length,numDirLightShadows:M.directionalShadowMap.length,numPointLightShadows:M.pointShadowMap.length,numSpotLightShadows:M.spotShadowMap.length,numSpotLightShadowsWithMaps:M.numSpotLightShadowsWithMaps,numLightProbes:M.numLightProbes,numClippingPlanes:o.numPlanes,numClipIntersection:o.numIntersection,dithering:w.dithering,shadowMapEnabled:s.shadowMap.enabled&&F.length>0,shadowMapType:s.shadowMap.type,toneMapping:It,decodeVideoTexture:J&&w.map.isVideoTexture===!0&&ht.getTransfer(w.map.colorSpace)===Mt,premultipliedAlpha:w.premultipliedAlpha,doubleSided:w.side===En,flipSided:w.side===nn,useDepthPacking:w.depthPacking>=0,depthPacking:w.depthPacking||0,index0AttributeName:w.index0AttributeName,extensionClipCullDistance:ut&&w.extensions.clipCullDistance===!0&&n.has("WEBGL_clip_cull_distance"),extensionMultiDraw:ut&&w.extensions.multiDraw===!0&&n.has("WEBGL_multi_draw"),rendererExtensionParallelShaderCompile:n.has("KHR_parallel_shader_compile"),customProgramCacheKey:w.customProgramCacheKey()};return Bt.vertexUv1s=c.has(1),Bt.vertexUv2s=c.has(2),Bt.vertexUv3s=c.has(3),c.clear(),Bt}function p(w){const M=[];if(w.shaderID?M.push(w.shaderID):(M.push(w.customVertexShaderID),M.push(w.customFragmentShaderID)),w.defines!==void 0)for(const F in w.defines)M.push(F),M.push(w.defines[F]);return w.isRawShaderMaterial===!1&&(y(M,w),_(M,w),M.push(s.outputColorSpace)),M.push(w.customProgramCacheKey),M.join()}function y(w,M){w.push(M.precision),w.push(M.outputColorSpace),w.push(M.envMapMode),w.push(M.envMapCubeUVHeight),w.push(M.mapUv),w.push(M.alphaMapUv),w.push(M.lightMapUv),w.push(M.aoMapUv),w.push(M.bumpMapUv),w.push(M.normalMapUv),w.push(M.displacementMapUv),w.push(M.emissiveMapUv),w.push(M.metalnessMapUv),w.push(M.roughnessMapUv),w.push(M.anisotropyMapUv),w.push(M.clearcoatMapUv),w.push(M.clearcoatNormalMapUv),w.push(M.clearcoatRoughnessMapUv),w.push(M.iridescenceMapUv),w.push(M.iridescenceThicknessMapUv),w.push(M.sheenColorMapUv),w.push(M.sheenRoughnessMapUv),w.push(M.specularMapUv),w.push(M.specularColorMapUv),w.push(M.specularIntensityMapUv),w.push(M.transmissionMapUv),w.push(M.thicknessMapUv),w.push(M.combine),w.push(M.fogExp2),w.push(M.sizeAttenuation),w.push(M.morphTargetsCount),w.push(M.morphAttributeCount),w.push(M.numDirLights),w.push(M.numPointLights),w.push(M.numSpotLights),w.push(M.numSpotLightMaps),w.push(M.numHemiLights),w.push(M.numRectAreaLights),w.push(M.numDirLightShadows),w.push(M.numPointLightShadows),w.push(M.numSpotLightShadows),w.push(M.numSpotLightShadowsWithMaps),w.push(M.numLightProbes),w.push(M.shadowMapType),w.push(M.toneMapping),w.push(M.numClippingPlanes),w.push(M.numClipIntersection),w.push(M.depthPacking)}function _(w,M){a.disableAll(),M.supportsVertexTextures&&a.enable(0),M.instancing&&a.enable(1),M.instancingColor&&a.enable(2),M.instancingMorph&&a.enable(3),M.matcap&&a.enable(4),M.envMap&&a.enable(5),M.normalMapObjectSpace&&a.enable(6),M.normalMapTangentSpace&&a.enable(7),M.clearcoat&&a.enable(8),M.iridescence&&a.enable(9),M.alphaTest&&a.enable(10),M.vertexColors&&a.enable(11),M.vertexAlphas&&a.enable(12),M.vertexUv1s&&a.enable(13),M.vertexUv2s&&a.enable(14),M.vertexUv3s&&a.enable(15),M.vertexTangents&&a.enable(16),M.anisotropy&&a.enable(17),M.alphaHash&&a.enable(18),M.batching&&a.enable(19),M.dispersion&&a.enable(20),M.batchingColor&&a.enable(21),w.push(a.mask),a.disableAll(),M.fog&&a.enable(0),M.useFog&&a.enable(1),M.flatShading&&a.enable(2),M.logarithmicDepthBuffer&&a.enable(3),M.skinning&&a.enable(4),M.morphTargets&&a.enable(5),M.morphNormals&&a.enable(6),M.morphColors&&a.enable(7),M.premultipliedAlpha&&a.enable(8),M.shadowMapEnabled&&a.enable(9),M.doubleSided&&a.enable(10),M.flipSided&&a.enable(11),M.useDepthPacking&&a.enable(12),M.dithering&&a.enable(13),M.transmission&&a.enable(14),M.sheen&&a.enable(15),M.opaque&&a.enable(16),M.pointsUvs&&a.enable(17),M.decodeVideoTexture&&a.enable(18),M.alphaToCoverage&&a.enable(19),w.push(a.mask)}function x(w){const M=g[w.type];let F;if(M){const V=Tn[M];F=up.clone(V.uniforms)}else F=w.uniforms;return F}function A(w,M){let F;for(let V=0,G=u.length;V0?n.push(p):f.transparent===!0?i.push(p):t.push(p)}function l(h,d,f,g,v,m){const p=o(h,d,f,g,v,m);f.transmission>0?n.unshift(p):f.transparent===!0?i.unshift(p):t.unshift(p)}function c(h,d){t.length>1&&t.sort(h||Wx),n.length>1&&n.sort(d||Bh),i.length>1&&i.sort(d||Bh)}function u(){for(let h=e,d=s.length;h=r.length?(o=new zh,r.push(o)):o=r[i],o}function t(){s=new WeakMap}return{get:e,dispose:t}}function Xx(){const s={};return{get:function(e){if(s[e.id]!==void 0)return s[e.id];let t;switch(e.type){case"DirectionalLight":t={direction:new N,color:new Pe};break;case"SpotLight":t={position:new N,direction:new N,color:new Pe,distance:0,coneCos:0,penumbraCos:0,decay:0};break;case"PointLight":t={position:new N,color:new Pe,distance:0,decay:0};break;case"HemisphereLight":t={direction:new N,skyColor:new Pe,groundColor:new Pe};break;case"RectAreaLight":t={color:new Pe,position:new N,halfWidth:new N,halfHeight:new N};break}return s[e.id]=t,t}}}function qx(){const s={};return{get:function(e){if(s[e.id]!==void 0)return s[e.id];let t;switch(e.type){case"DirectionalLight":t={shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new se};break;case"SpotLight":t={shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new se};break;case"PointLight":t={shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new se,shadowCameraNear:1,shadowCameraFar:1e3};break}return s[e.id]=t,t}}}let Yx=0;function Zx(s,e){return(e.castShadow?2:0)-(s.castShadow?2:0)+(e.map?1:0)-(s.map?1:0)}function Jx(s){const e=new Xx,t=qx(),n={version:0,hash:{directionalLength:-1,pointLength:-1,spotLength:-1,rectAreaLength:-1,hemiLength:-1,numDirectionalShadows:-1,numPointShadows:-1,numSpotShadows:-1,numSpotMaps:-1,numLightProbes:-1},ambient:[0,0,0],probe:[],directional:[],directionalShadow:[],directionalShadowMap:[],directionalShadowMatrix:[],spot:[],spotLightMap:[],spotShadow:[],spotShadowMap:[],spotLightMatrix:[],rectArea:[],rectAreaLTC1:null,rectAreaLTC2:null,point:[],pointShadow:[],pointShadowMap:[],pointShadowMatrix:[],hemi:[],numSpotLightShadowsWithMaps:0,numLightProbes:0};for(let c=0;c<9;c++)n.probe.push(new N);const i=new N,r=new qe,o=new qe;function a(c){let u=0,h=0,d=0;for(let w=0;w<9;w++)n.probe[w].set(0,0,0);let f=0,g=0,v=0,m=0,p=0,y=0,_=0,x=0,A=0,b=0,E=0;c.sort(Zx);for(let w=0,M=c.length;w0&&(s.has("OES_texture_float_linear")===!0?(n.rectAreaLTC1=Ce.LTC_FLOAT_1,n.rectAreaLTC2=Ce.LTC_FLOAT_2):(n.rectAreaLTC1=Ce.LTC_HALF_1,n.rectAreaLTC2=Ce.LTC_HALF_2)),n.ambient[0]=u,n.ambient[1]=h,n.ambient[2]=d;const I=n.hash;(I.directionalLength!==f||I.pointLength!==g||I.spotLength!==v||I.rectAreaLength!==m||I.hemiLength!==p||I.numDirectionalShadows!==y||I.numPointShadows!==_||I.numSpotShadows!==x||I.numSpotMaps!==A||I.numLightProbes!==E)&&(n.directional.length=f,n.spot.length=v,n.rectArea.length=m,n.point.length=g,n.hemi.length=p,n.directionalShadow.length=y,n.directionalShadowMap.length=y,n.pointShadow.length=_,n.pointShadowMap.length=_,n.spotShadow.length=x,n.spotShadowMap.length=x,n.directionalShadowMatrix.length=y,n.pointShadowMatrix.length=_,n.spotLightMatrix.length=x+A-b,n.spotLightMap.length=A,n.numSpotLightShadowsWithMaps=b,n.numLightProbes=E,I.directionalLength=f,I.pointLength=g,I.spotLength=v,I.rectAreaLength=m,I.hemiLength=p,I.numDirectionalShadows=y,I.numPointShadows=_,I.numSpotShadows=x,I.numSpotMaps=A,I.numLightProbes=E,n.version=Yx++)}function l(c,u){let h=0,d=0,f=0,g=0,v=0;const m=u.matrixWorldInverse;for(let p=0,y=c.length;p=o.length?(a=new Vh(s),o.push(a)):a=o[r],a}function n(){e=new WeakMap}return{get:t,dispose:n}}class gu extends Kt{constructor(e){super(),this.isMeshDepthMaterial=!0,this.type="MeshDepthMaterial",this.depthPacking=Xf,this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.setValues(e)}copy(e){return super.copy(e),this.depthPacking=e.depthPacking,this.map=e.map,this.alphaMap=e.alphaMap,this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this}}class vu extends Kt{constructor(e){super(),this.isMeshDistanceMaterial=!0,this.type="MeshDistanceMaterial",this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.setValues(e)}copy(e){return super.copy(e),this.map=e.map,this.alphaMap=e.alphaMap,this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this}}const jx=`void main() { + gl_Position = vec4( position, 1.0 ); +}`,Qx=`uniform sampler2D shadow_pass; +uniform vec2 resolution; +uniform float radius; +#include +void main() { + const float samples = float( VSM_SAMPLES ); + float mean = 0.0; + float squared_mean = 0.0; + float uvStride = samples <= 1.0 ? 0.0 : 2.0 / ( samples - 1.0 ); + float uvStart = samples <= 1.0 ? 0.0 : - 1.0; + for ( float i = 0.0; i < samples; i ++ ) { + float uvOffset = uvStart + i * uvStride; + #ifdef HORIZONTAL_PASS + vec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( uvOffset, 0.0 ) * radius ) / resolution ) ); + mean += distribution.x; + squared_mean += distribution.y * distribution.y + distribution.x * distribution.x; + #else + float depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, uvOffset ) * radius ) / resolution ) ); + mean += depth; + squared_mean += depth * depth; + #endif + } + mean = mean / samples; + squared_mean = squared_mean / samples; + float std_dev = sqrt( squared_mean - mean * mean ); + gl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) ); +}`;function eM(s,e,t){let n=new Yr;const i=new se,r=new se,o=new gt,a=new gu({depthPacking:qf}),l=new vu,c={},u=t.maxTextureSize,h={[oi]:nn,[nn]:oi,[En]:En},d=new Ln({defines:{VSM_SAMPLES:8},uniforms:{shadow_pass:{value:null},resolution:{value:new se},radius:{value:4}},vertexShader:jx,fragmentShader:Qx}),f=d.clone();f.defines.HORIZONTAL_PASS=1;const g=new it;g.setAttribute("position",new pt(new Float32Array([-1,-1,.5,3,-1,.5,-1,3,.5]),3));const v=new Nt(g,d),m=this;this.enabled=!1,this.autoUpdate=!0,this.needsUpdate=!1,this.type=Kc;let p=this.type;this.render=function(b,E,I){if(m.enabled===!1||m.autoUpdate===!1&&m.needsUpdate===!1||b.length===0)return;const w=s.getRenderTarget(),M=s.getActiveCubeFace(),F=s.getActiveMipmapLevel(),V=s.state;V.setBlending(si),V.buffers.color.setClear(1,1,1,1),V.buffers.depth.setTest(!0),V.setScissorTest(!1);const G=p!==kn&&this.type===kn,q=p===kn&&this.type!==kn;for(let ae=0,Q=b.length;aeu||i.y>u)&&(i.x>u&&(r.x=Math.floor(u/Me.x),i.x=r.x*Me.x,B.mapSize.x=r.x),i.y>u&&(r.y=Math.floor(u/Me.y),i.y=r.y*Me.y,B.mapSize.y=r.y)),B.map===null||G===!0||q===!0){const Ae=this.type!==kn?{minFilter:Gt,magFilter:Gt}:{};B.map!==null&&B.map.dispose(),B.map=new In(i.x,i.y,Ae),B.map.texture.name=oe.name+".shadowMap",B.camera.updateProjectionMatrix()}s.setRenderTarget(B.map),s.clear();const be=B.getViewportCount();for(let Ae=0;Ae0||E.map&&E.alphaTest>0){const V=M.uuid,G=E.uuid;let q=c[V];q===void 0&&(q={},c[V]=q);let ae=q[G];ae===void 0&&(ae=M.clone(),q[G]=ae,E.addEventListener("dispose",A)),M=ae}if(M.visible=E.visible,M.wireframe=E.wireframe,w===kn?M.side=E.shadowSide!==null?E.shadowSide:E.side:M.side=E.shadowSide!==null?E.shadowSide:h[E.side],M.alphaMap=E.alphaMap,M.alphaTest=E.alphaTest,M.map=E.map,M.clipShadows=E.clipShadows,M.clippingPlanes=E.clippingPlanes,M.clipIntersection=E.clipIntersection,M.displacementMap=E.displacementMap,M.displacementScale=E.displacementScale,M.displacementBias=E.displacementBias,M.wireframeLinewidth=E.wireframeLinewidth,M.linewidth=E.linewidth,I.isPointLight===!0&&M.isMeshDistanceMaterial===!0){const V=s.properties.get(M);V.light=I}return M}function x(b,E,I,w,M){if(b.visible===!1)return;if(b.layers.test(E.layers)&&(b.isMesh||b.isLine||b.isPoints)&&(b.castShadow||b.receiveShadow&&M===kn)&&(!b.frustumCulled||n.intersectsObject(b))){b.modelViewMatrix.multiplyMatrices(I.matrixWorldInverse,b.matrixWorld);const G=e.update(b),q=b.material;if(Array.isArray(q)){const ae=G.groups;for(let Q=0,oe=ae.length;Q=1):oe.indexOf("OpenGL ES")!==-1&&(Q=parseFloat(/^OpenGL ES (\d)/.exec(oe)[1]),ae=Q>=2);let B=null,Me={};const be=s.getParameter(s.SCISSOR_BOX),Ae=s.getParameter(s.VIEWPORT),ge=new gt().fromArray(be),ze=new gt().fromArray(Ae);function U(z,Ie,de,_e){const we=new Uint8Array(4),et=s.createTexture();s.bindTexture(z,et),s.texParameteri(z,s.TEXTURE_MIN_FILTER,s.NEAREST),s.texParameteri(z,s.TEXTURE_MAG_FILTER,s.NEAREST);for(let ut=0;ut"u"?!1:/OculusBrowser/g.test(navigator.userAgent),c=new se,u=new WeakMap;let h;const d=new WeakMap;let f=!1;try{f=typeof OffscreenCanvas<"u"&&new OffscreenCanvas(1,1).getContext("2d")!==null}catch{}function g(P,S){return f?new OffscreenCanvas(P,S):Ir("canvas")}function v(P,S,ee){let pe=1;const ce=O(P);if((ce.width>ee||ce.height>ee)&&(pe=ee/Math.max(ce.width,ce.height)),pe<1)if(typeof HTMLImageElement<"u"&&P instanceof HTMLImageElement||typeof HTMLCanvasElement<"u"&&P instanceof HTMLCanvasElement||typeof ImageBitmap<"u"&&P instanceof ImageBitmap||typeof VideoFrame<"u"&&P instanceof VideoFrame){const ve=Math.floor(pe*ce.width),Ve=Math.floor(pe*ce.height);h===void 0&&(h=g(ve,Ve));const Ee=S?g(ve,Ve):h;return Ee.width=ve,Ee.height=Ve,Ee.getContext("2d").drawImage(P,0,0,ve,Ve),console.warn("THREE.WebGLRenderer: Texture has been resized from ("+ce.width+"x"+ce.height+") to ("+ve+"x"+Ve+")."),Ee}else return"data"in P&&console.warn("THREE.WebGLRenderer: Image in DataTexture is too big ("+ce.width+"x"+ce.height+")."),P;return P}function m(P){return P.generateMipmaps&&P.minFilter!==Gt&&P.minFilter!==Ot}function p(P){s.generateMipmap(P)}function y(P,S,ee,pe,ce=!1){if(P!==null){if(s[P]!==void 0)return s[P];console.warn("THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format '"+P+"'")}let ve=S;if(S===s.RED&&(ee===s.FLOAT&&(ve=s.R32F),ee===s.HALF_FLOAT&&(ve=s.R16F),ee===s.UNSIGNED_BYTE&&(ve=s.R8)),S===s.RED_INTEGER&&(ee===s.UNSIGNED_BYTE&&(ve=s.R8UI),ee===s.UNSIGNED_SHORT&&(ve=s.R16UI),ee===s.UNSIGNED_INT&&(ve=s.R32UI),ee===s.BYTE&&(ve=s.R8I),ee===s.SHORT&&(ve=s.R16I),ee===s.INT&&(ve=s.R32I)),S===s.RG&&(ee===s.FLOAT&&(ve=s.RG32F),ee===s.HALF_FLOAT&&(ve=s.RG16F),ee===s.UNSIGNED_BYTE&&(ve=s.RG8)),S===s.RG_INTEGER&&(ee===s.UNSIGNED_BYTE&&(ve=s.RG8UI),ee===s.UNSIGNED_SHORT&&(ve=s.RG16UI),ee===s.UNSIGNED_INT&&(ve=s.RG32UI),ee===s.BYTE&&(ve=s.RG8I),ee===s.SHORT&&(ve=s.RG16I),ee===s.INT&&(ve=s.RG32I)),S===s.RGB&&ee===s.UNSIGNED_INT_5_9_9_9_REV&&(ve=s.RGB9_E5),S===s.RGBA){const Ve=ce?Tr:ht.getTransfer(pe);ee===s.FLOAT&&(ve=s.RGBA32F),ee===s.HALF_FLOAT&&(ve=s.RGBA16F),ee===s.UNSIGNED_BYTE&&(ve=Ve===Mt?s.SRGB8_ALPHA8:s.RGBA8),ee===s.UNSIGNED_SHORT_4_4_4_4&&(ve=s.RGBA4),ee===s.UNSIGNED_SHORT_5_5_5_1&&(ve=s.RGB5_A1)}return(ve===s.R16F||ve===s.R32F||ve===s.RG16F||ve===s.RG32F||ve===s.RGBA16F||ve===s.RGBA32F)&&e.get("EXT_color_buffer_float"),ve}function _(P,S){let ee;return P?S===null||S===ss||S===rs?ee=s.DEPTH24_STENCIL8:S===gn?ee=s.DEPTH32F_STENCIL8:S===Sr&&(ee=s.DEPTH24_STENCIL8,console.warn("DepthTexture: 16 bit depth attachment is not supported with stencil. Using 24-bit attachment.")):S===null||S===ss||S===rs?ee=s.DEPTH_COMPONENT24:S===gn?ee=s.DEPTH_COMPONENT32F:S===Sr&&(ee=s.DEPTH_COMPONENT16),ee}function x(P,S){return m(P)===!0||P.isFramebufferTexture&&P.minFilter!==Gt&&P.minFilter!==Ot?Math.log2(Math.max(S.width,S.height))+1:P.mipmaps!==void 0&&P.mipmaps.length>0?P.mipmaps.length:P.isCompressedTexture&&Array.isArray(P.image)?S.mipmaps.length:1}function A(P){const S=P.target;S.removeEventListener("dispose",A),E(S),S.isVideoTexture&&u.delete(S)}function b(P){const S=P.target;S.removeEventListener("dispose",b),w(S)}function E(P){const S=n.get(P);if(S.__webglInit===void 0)return;const ee=P.source,pe=d.get(ee);if(pe){const ce=pe[S.__cacheKey];ce.usedTimes--,ce.usedTimes===0&&I(P),Object.keys(pe).length===0&&d.delete(ee)}n.remove(P)}function I(P){const S=n.get(P);s.deleteTexture(S.__webglTexture);const ee=P.source,pe=d.get(ee);delete pe[S.__cacheKey],o.memory.textures--}function w(P){const S=n.get(P);if(P.depthTexture&&P.depthTexture.dispose(),P.isWebGLCubeRenderTarget)for(let pe=0;pe<6;pe++){if(Array.isArray(S.__webglFramebuffer[pe]))for(let ce=0;ce=i.maxTextures&&console.warn("THREE.WebGLTextures: Trying to use "+P+" texture units while this GPU supports only "+i.maxTextures),M+=1,P}function G(P){const S=[];return S.push(P.wrapS),S.push(P.wrapT),S.push(P.wrapR||0),S.push(P.magFilter),S.push(P.minFilter),S.push(P.anisotropy),S.push(P.internalFormat),S.push(P.format),S.push(P.type),S.push(P.generateMipmaps),S.push(P.premultiplyAlpha),S.push(P.flipY),S.push(P.unpackAlignment),S.push(P.colorSpace),S.join()}function q(P,S){const ee=n.get(P);if(P.isVideoTexture&&le(P),P.isRenderTargetTexture===!1&&P.version>0&&ee.__version!==P.version){const pe=P.image;if(pe===null)console.warn("THREE.WebGLRenderer: Texture marked for update but no image data found.");else if(pe.complete===!1)console.warn("THREE.WebGLRenderer: Texture marked for update but image is incomplete");else{ze(ee,P,S);return}}t.bindTexture(s.TEXTURE_2D,ee.__webglTexture,s.TEXTURE0+S)}function ae(P,S){const ee=n.get(P);if(P.version>0&&ee.__version!==P.version){ze(ee,P,S);return}t.bindTexture(s.TEXTURE_2D_ARRAY,ee.__webglTexture,s.TEXTURE0+S)}function Q(P,S){const ee=n.get(P);if(P.version>0&&ee.__version!==P.version){ze(ee,P,S);return}t.bindTexture(s.TEXTURE_3D,ee.__webglTexture,s.TEXTURE0+S)}function oe(P,S){const ee=n.get(P);if(P.version>0&&ee.__version!==P.version){U(ee,P,S);return}t.bindTexture(s.TEXTURE_CUBE_MAP,ee.__webglTexture,s.TEXTURE0+S)}const B={[Mr]:s.REPEAT,[Mn]:s.CLAMP_TO_EDGE,[br]:s.MIRRORED_REPEAT},Me={[Gt]:s.NEAREST,[Qc]:s.NEAREST_MIPMAP_NEAREST,[Ds]:s.NEAREST_MIPMAP_LINEAR,[Ot]:s.LINEAR,[hr]:s.LINEAR_MIPMAP_NEAREST,[zn]:s.LINEAR_MIPMAP_LINEAR},be={[Jf]:s.NEVER,[np]:s.ALWAYS,[Kf]:s.LESS,[lu]:s.LEQUAL,[jf]:s.EQUAL,[tp]:s.GEQUAL,[Qf]:s.GREATER,[ep]:s.NOTEQUAL};function Ae(P,S){if(S.type===gn&&e.has("OES_texture_float_linear")===!1&&(S.magFilter===Ot||S.magFilter===hr||S.magFilter===Ds||S.magFilter===zn||S.minFilter===Ot||S.minFilter===hr||S.minFilter===Ds||S.minFilter===zn)&&console.warn("THREE.WebGLRenderer: Unable to use linear filtering with floating point textures. OES_texture_float_linear not supported on this device."),s.texParameteri(P,s.TEXTURE_WRAP_S,B[S.wrapS]),s.texParameteri(P,s.TEXTURE_WRAP_T,B[S.wrapT]),(P===s.TEXTURE_3D||P===s.TEXTURE_2D_ARRAY)&&s.texParameteri(P,s.TEXTURE_WRAP_R,B[S.wrapR]),s.texParameteri(P,s.TEXTURE_MAG_FILTER,Me[S.magFilter]),s.texParameteri(P,s.TEXTURE_MIN_FILTER,Me[S.minFilter]),S.compareFunction&&(s.texParameteri(P,s.TEXTURE_COMPARE_MODE,s.COMPARE_REF_TO_TEXTURE),s.texParameteri(P,s.TEXTURE_COMPARE_FUNC,be[S.compareFunction])),e.has("EXT_texture_filter_anisotropic")===!0){if(S.magFilter===Gt||S.minFilter!==Ds&&S.minFilter!==zn||S.type===gn&&e.has("OES_texture_float_linear")===!1)return;if(S.anisotropy>1||n.get(S).__currentAnisotropy){const ee=e.get("EXT_texture_filter_anisotropic");s.texParameterf(P,ee.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(S.anisotropy,i.getMaxAnisotropy())),n.get(S).__currentAnisotropy=S.anisotropy}}}function ge(P,S){let ee=!1;P.__webglInit===void 0&&(P.__webglInit=!0,S.addEventListener("dispose",A));const pe=S.source;let ce=d.get(pe);ce===void 0&&(ce={},d.set(pe,ce));const ve=G(S);if(ve!==P.__cacheKey){ce[ve]===void 0&&(ce[ve]={texture:s.createTexture(),usedTimes:0},o.memory.textures++,ee=!0),ce[ve].usedTimes++;const Ve=ce[P.__cacheKey];Ve!==void 0&&(ce[P.__cacheKey].usedTimes--,Ve.usedTimes===0&&I(S)),P.__cacheKey=ve,P.__webglTexture=ce[ve].texture}return ee}function ze(P,S,ee){let pe=s.TEXTURE_2D;(S.isDataArrayTexture||S.isCompressedArrayTexture)&&(pe=s.TEXTURE_2D_ARRAY),S.isData3DTexture&&(pe=s.TEXTURE_3D);const ce=ge(P,S),ve=S.source;t.bindTexture(pe,P.__webglTexture,s.TEXTURE0+ee);const Ve=n.get(ve);if(ve.version!==Ve.__version||ce===!0){t.activeTexture(s.TEXTURE0+ee);const Ee=ht.getPrimaries(ht.workingColorSpace),Te=S.colorSpace===ti?null:ht.getPrimaries(S.colorSpace),Qe=S.colorSpace===ti||Ee===Te?s.NONE:s.BROWSER_DEFAULT_WEBGL;s.pixelStorei(s.UNPACK_FLIP_Y_WEBGL,S.flipY),s.pixelStorei(s.UNPACK_PREMULTIPLY_ALPHA_WEBGL,S.premultiplyAlpha),s.pixelStorei(s.UNPACK_ALIGNMENT,S.unpackAlignment),s.pixelStorei(s.UNPACK_COLORSPACE_CONVERSION_WEBGL,Qe);let xe=v(S.image,!1,i.maxTextureSize);xe=k(S,xe);const Ue=r.convert(S.format,S.colorSpace),st=r.convert(S.type);let Je=y(S.internalFormat,Ue,st,S.colorSpace,S.isVideoTexture);Ae(pe,S);let Re;const rt=S.mipmaps,at=S.isVideoTexture!==!0,Rt=Ve.__version===void 0||ce===!0,z=ve.dataReady,Ie=x(S,xe);if(S.isDepthTexture)Je=_(S.format===os,S.type),Rt&&(at?t.texStorage2D(s.TEXTURE_2D,1,Je,xe.width,xe.height):t.texImage2D(s.TEXTURE_2D,0,Je,xe.width,xe.height,0,Ue,st,null));else if(S.isDataTexture)if(rt.length>0){at&&Rt&&t.texStorage2D(s.TEXTURE_2D,Ie,Je,rt[0].width,rt[0].height);for(let de=0,_e=rt.length;de<_e;de++)Re=rt[de],at?z&&t.texSubImage2D(s.TEXTURE_2D,de,0,0,Re.width,Re.height,Ue,st,Re.data):t.texImage2D(s.TEXTURE_2D,de,Je,Re.width,Re.height,0,Ue,st,Re.data);S.generateMipmaps=!1}else at?(Rt&&t.texStorage2D(s.TEXTURE_2D,Ie,Je,xe.width,xe.height),z&&t.texSubImage2D(s.TEXTURE_2D,0,0,0,xe.width,xe.height,Ue,st,xe.data)):t.texImage2D(s.TEXTURE_2D,0,Je,xe.width,xe.height,0,Ue,st,xe.data);else if(S.isCompressedTexture)if(S.isCompressedArrayTexture){at&&Rt&&t.texStorage3D(s.TEXTURE_2D_ARRAY,Ie,Je,rt[0].width,rt[0].height,xe.depth);for(let de=0,_e=rt.length;de<_e;de++)if(Re=rt[de],S.format!==un)if(Ue!==null)if(at){if(z)if(S.layerUpdates.size>0){for(const we of S.layerUpdates){const et=Re.width*Re.height;t.compressedTexSubImage3D(s.TEXTURE_2D_ARRAY,de,0,0,we,Re.width,Re.height,1,Ue,Re.data.slice(et*we,et*(we+1)),0,0)}S.clearLayerUpdates()}else t.compressedTexSubImage3D(s.TEXTURE_2D_ARRAY,de,0,0,0,Re.width,Re.height,xe.depth,Ue,Re.data,0,0)}else t.compressedTexImage3D(s.TEXTURE_2D_ARRAY,de,Je,Re.width,Re.height,xe.depth,0,Re.data,0,0);else console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()");else at?z&&t.texSubImage3D(s.TEXTURE_2D_ARRAY,de,0,0,0,Re.width,Re.height,xe.depth,Ue,st,Re.data):t.texImage3D(s.TEXTURE_2D_ARRAY,de,Je,Re.width,Re.height,xe.depth,0,Ue,st,Re.data)}else{at&&Rt&&t.texStorage2D(s.TEXTURE_2D,Ie,Je,rt[0].width,rt[0].height);for(let de=0,_e=rt.length;de<_e;de++)Re=rt[de],S.format!==un?Ue!==null?at?z&&t.compressedTexSubImage2D(s.TEXTURE_2D,de,0,0,Re.width,Re.height,Ue,Re.data):t.compressedTexImage2D(s.TEXTURE_2D,de,Je,Re.width,Re.height,0,Re.data):console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()"):at?z&&t.texSubImage2D(s.TEXTURE_2D,de,0,0,Re.width,Re.height,Ue,st,Re.data):t.texImage2D(s.TEXTURE_2D,de,Je,Re.width,Re.height,0,Ue,st,Re.data)}else if(S.isDataArrayTexture)if(at){if(Rt&&t.texStorage3D(s.TEXTURE_2D_ARRAY,Ie,Je,xe.width,xe.height,xe.depth),z)if(S.layerUpdates.size>0){let de;switch(st){case s.UNSIGNED_BYTE:switch(Ue){case s.ALPHA:de=1;break;case s.LUMINANCE:de=1;break;case s.LUMINANCE_ALPHA:de=2;break;case s.RGB:de=3;break;case s.RGBA:de=4;break;default:throw new Error(`Unknown texel size for format ${Ue}.`)}break;case s.UNSIGNED_SHORT_4_4_4_4:case s.UNSIGNED_SHORT_5_5_5_1:case s.UNSIGNED_SHORT_5_6_5:de=1;break;default:throw new Error(`Unknown texel size for type ${st}.`)}const _e=xe.width*xe.height*de;for(const we of S.layerUpdates)t.texSubImage3D(s.TEXTURE_2D_ARRAY,0,0,0,we,xe.width,xe.height,1,Ue,st,xe.data.slice(_e*we,_e*(we+1)));S.clearLayerUpdates()}else t.texSubImage3D(s.TEXTURE_2D_ARRAY,0,0,0,0,xe.width,xe.height,xe.depth,Ue,st,xe.data)}else t.texImage3D(s.TEXTURE_2D_ARRAY,0,Je,xe.width,xe.height,xe.depth,0,Ue,st,xe.data);else if(S.isData3DTexture)at?(Rt&&t.texStorage3D(s.TEXTURE_3D,Ie,Je,xe.width,xe.height,xe.depth),z&&t.texSubImage3D(s.TEXTURE_3D,0,0,0,0,xe.width,xe.height,xe.depth,Ue,st,xe.data)):t.texImage3D(s.TEXTURE_3D,0,Je,xe.width,xe.height,xe.depth,0,Ue,st,xe.data);else if(S.isFramebufferTexture){if(Rt)if(at)t.texStorage2D(s.TEXTURE_2D,Ie,Je,xe.width,xe.height);else{let de=xe.width,_e=xe.height;for(let we=0;we>=1,_e>>=1}}else if(rt.length>0){if(at&&Rt){const de=O(rt[0]);t.texStorage2D(s.TEXTURE_2D,Ie,Je,de.width,de.height)}for(let de=0,_e=rt.length;de<_e;de++)Re=rt[de],at?z&&t.texSubImage2D(s.TEXTURE_2D,de,0,0,Ue,st,Re):t.texImage2D(s.TEXTURE_2D,de,Je,Ue,st,Re);S.generateMipmaps=!1}else if(at){if(Rt){const de=O(xe);t.texStorage2D(s.TEXTURE_2D,Ie,Je,de.width,de.height)}z&&t.texSubImage2D(s.TEXTURE_2D,0,0,0,Ue,st,xe)}else t.texImage2D(s.TEXTURE_2D,0,Je,Ue,st,xe);m(S)&&p(pe),Ve.__version=ve.version,S.onUpdate&&S.onUpdate(S)}P.__version=S.version}function U(P,S,ee){if(S.image.length!==6)return;const pe=ge(P,S),ce=S.source;t.bindTexture(s.TEXTURE_CUBE_MAP,P.__webglTexture,s.TEXTURE0+ee);const ve=n.get(ce);if(ce.version!==ve.__version||pe===!0){t.activeTexture(s.TEXTURE0+ee);const Ve=ht.getPrimaries(ht.workingColorSpace),Ee=S.colorSpace===ti?null:ht.getPrimaries(S.colorSpace),Te=S.colorSpace===ti||Ve===Ee?s.NONE:s.BROWSER_DEFAULT_WEBGL;s.pixelStorei(s.UNPACK_FLIP_Y_WEBGL,S.flipY),s.pixelStorei(s.UNPACK_PREMULTIPLY_ALPHA_WEBGL,S.premultiplyAlpha),s.pixelStorei(s.UNPACK_ALIGNMENT,S.unpackAlignment),s.pixelStorei(s.UNPACK_COLORSPACE_CONVERSION_WEBGL,Te);const Qe=S.isCompressedTexture||S.image[0].isCompressedTexture,xe=S.image[0]&&S.image[0].isDataTexture,Ue=[];for(let _e=0;_e<6;_e++)!Qe&&!xe?Ue[_e]=v(S.image[_e],!0,i.maxCubemapSize):Ue[_e]=xe?S.image[_e].image:S.image[_e],Ue[_e]=k(S,Ue[_e]);const st=Ue[0],Je=r.convert(S.format,S.colorSpace),Re=r.convert(S.type),rt=y(S.internalFormat,Je,Re,S.colorSpace),at=S.isVideoTexture!==!0,Rt=ve.__version===void 0||pe===!0,z=ce.dataReady;let Ie=x(S,st);Ae(s.TEXTURE_CUBE_MAP,S);let de;if(Qe){at&&Rt&&t.texStorage2D(s.TEXTURE_CUBE_MAP,Ie,rt,st.width,st.height);for(let _e=0;_e<6;_e++){de=Ue[_e].mipmaps;for(let we=0;we0&&Ie++;const _e=O(Ue[0]);t.texStorage2D(s.TEXTURE_CUBE_MAP,Ie,rt,_e.width,_e.height)}for(let _e=0;_e<6;_e++)if(xe){at?z&&t.texSubImage2D(s.TEXTURE_CUBE_MAP_POSITIVE_X+_e,0,0,0,Ue[_e].width,Ue[_e].height,Je,Re,Ue[_e].data):t.texImage2D(s.TEXTURE_CUBE_MAP_POSITIVE_X+_e,0,rt,Ue[_e].width,Ue[_e].height,0,Je,Re,Ue[_e].data);for(let we=0;we>ve),Ue=Math.max(1,S.height>>ve);ce===s.TEXTURE_3D||ce===s.TEXTURE_2D_ARRAY?t.texImage3D(ce,ve,Te,xe,Ue,S.depth,0,Ve,Ee,null):t.texImage2D(ce,ve,Te,xe,Ue,0,Ve,Ee,null)}t.bindFramebuffer(s.FRAMEBUFFER,P),te(S)?a.framebufferTexture2DMultisampleEXT(s.FRAMEBUFFER,pe,ce,n.get(ee).__webglTexture,0,$(S)):(ce===s.TEXTURE_2D||ce>=s.TEXTURE_CUBE_MAP_POSITIVE_X&&ce<=s.TEXTURE_CUBE_MAP_NEGATIVE_Z)&&s.framebufferTexture2D(s.FRAMEBUFFER,pe,ce,n.get(ee).__webglTexture,ve),t.bindFramebuffer(s.FRAMEBUFFER,null)}function R(P,S,ee){if(s.bindRenderbuffer(s.RENDERBUFFER,P),S.depthBuffer){const pe=S.depthTexture,ce=pe&&pe.isDepthTexture?pe.type:null,ve=_(S.stencilBuffer,ce),Ve=S.stencilBuffer?s.DEPTH_STENCIL_ATTACHMENT:s.DEPTH_ATTACHMENT,Ee=$(S);te(S)?a.renderbufferStorageMultisampleEXT(s.RENDERBUFFER,Ee,ve,S.width,S.height):ee?s.renderbufferStorageMultisample(s.RENDERBUFFER,Ee,ve,S.width,S.height):s.renderbufferStorage(s.RENDERBUFFER,ve,S.width,S.height),s.framebufferRenderbuffer(s.FRAMEBUFFER,Ve,s.RENDERBUFFER,P)}else{const pe=S.textures;for(let ce=0;ce1;if(Ve||(pe.__webglTexture===void 0&&(pe.__webglTexture=s.createTexture()),pe.__version=S.version,o.memory.textures++),ve){ee.__webglFramebuffer=[];for(let Ee=0;Ee<6;Ee++)if(S.mipmaps&&S.mipmaps.length>0){ee.__webglFramebuffer[Ee]=[];for(let Te=0;Te0){ee.__webglFramebuffer=[];for(let Ee=0;Ee0&&te(P)===!1){ee.__webglMultisampledFramebuffer=s.createFramebuffer(),ee.__webglColorRenderbuffer=[],t.bindFramebuffer(s.FRAMEBUFFER,ee.__webglMultisampledFramebuffer);for(let Ee=0;Ee0)for(let Te=0;Te0)for(let Te=0;Te0){if(te(P)===!1){const S=P.textures,ee=P.width,pe=P.height;let ce=s.COLOR_BUFFER_BIT;const ve=P.stencilBuffer?s.DEPTH_STENCIL_ATTACHMENT:s.DEPTH_ATTACHMENT,Ve=n.get(P),Ee=S.length>1;if(Ee)for(let Te=0;Te0&&e.has("WEBGL_multisampled_render_to_texture")===!0&&S.__useRenderToTexture!==!1}function le(P){const S=o.render.frame;u.get(P)!==S&&(u.set(P,S),P.update())}function k(P,S){const ee=P.colorSpace,pe=P.format,ce=P.type;return P.isCompressedTexture===!0||P.isVideoTexture===!0||ee!==ci&&ee!==ti&&(ht.getTransfer(ee)===Mt?(pe!==un||ce!==li)&&console.warn("THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType."):console.error("THREE.WebGLTextures: Unsupported texture color space:",ee)),S}function O(P){return typeof HTMLImageElement<"u"&&P instanceof HTMLImageElement?(c.width=P.naturalWidth||P.width,c.height=P.naturalHeight||P.height):typeof VideoFrame<"u"&&P instanceof VideoFrame?(c.width=P.displayWidth,c.height=P.displayHeight):(c.width=P.width,c.height=P.height),c}this.allocateTextureUnit=V,this.resetTextureUnits=F,this.setTexture2D=q,this.setTexture2DArray=ae,this.setTexture3D=Q,this.setTextureCube=oe,this.rebindTextures=he,this.setupRenderTarget=J,this.updateRenderTargetMipmap=L,this.updateMultisampleRenderTarget=H,this.setupDepthRenderbuffer=ie,this.setupFrameBufferTexture=D,this.useMultisampledRTT=te}function yp(s,e){function t(n,i=ti){let r;const o=ht.getTransfer(i);if(n===li)return s.UNSIGNED_BYTE;if(n===tu)return s.UNSIGNED_SHORT_4_4_4_4;if(n===nu)return s.UNSIGNED_SHORT_5_5_5_1;if(n===Of)return s.UNSIGNED_INT_5_9_9_9_REV;if(n===Df)return s.BYTE;if(n===Uf)return s.SHORT;if(n===Sr)return s.UNSIGNED_SHORT;if(n===eu)return s.INT;if(n===ss)return s.UNSIGNED_INT;if(n===gn)return s.FLOAT;if(n===Wr)return s.HALF_FLOAT;if(n===Ff)return s.ALPHA;if(n===kf)return s.RGB;if(n===un)return s.RGBA;if(n===Bf)return s.LUMINANCE;if(n===zf)return s.LUMINANCE_ALPHA;if(n===ts)return s.DEPTH_COMPONENT;if(n===os)return s.DEPTH_STENCIL;if(n===iu)return s.RED;if(n===su)return s.RED_INTEGER;if(n===Vf)return s.RG;if(n===ru)return s.RG_INTEGER;if(n===ou)return s.RGBA_INTEGER;if(n===sa||n===ra||n===oa||n===aa)if(o===Mt)if(r=e.get("WEBGL_compressed_texture_s3tc_srgb"),r!==null){if(n===sa)return r.COMPRESSED_SRGB_S3TC_DXT1_EXT;if(n===ra)return r.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;if(n===oa)return r.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;if(n===aa)return r.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT}else return null;else if(r=e.get("WEBGL_compressed_texture_s3tc"),r!==null){if(n===sa)return r.COMPRESSED_RGB_S3TC_DXT1_EXT;if(n===ra)return r.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(n===oa)return r.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(n===aa)return r.COMPRESSED_RGBA_S3TC_DXT5_EXT}else return null;if(n===ic||n===sc||n===rc||n===oc)if(r=e.get("WEBGL_compressed_texture_pvrtc"),r!==null){if(n===ic)return r.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(n===sc)return r.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(n===rc)return r.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;if(n===oc)return r.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}else return null;if(n===ac||n===lc||n===cc)if(r=e.get("WEBGL_compressed_texture_etc"),r!==null){if(n===ac||n===lc)return o===Mt?r.COMPRESSED_SRGB8_ETC2:r.COMPRESSED_RGB8_ETC2;if(n===cc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:r.COMPRESSED_RGBA8_ETC2_EAC}else return null;if(n===uc||n===hc||n===dc||n===fc||n===pc||n===mc||n===gc||n===vc||n===_c||n===yc||n===xc||n===Mc||n===bc||n===Sc)if(r=e.get("WEBGL_compressed_texture_astc"),r!==null){if(n===uc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:r.COMPRESSED_RGBA_ASTC_4x4_KHR;if(n===hc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:r.COMPRESSED_RGBA_ASTC_5x4_KHR;if(n===dc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:r.COMPRESSED_RGBA_ASTC_5x5_KHR;if(n===fc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:r.COMPRESSED_RGBA_ASTC_6x5_KHR;if(n===pc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:r.COMPRESSED_RGBA_ASTC_6x6_KHR;if(n===mc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:r.COMPRESSED_RGBA_ASTC_8x5_KHR;if(n===gc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:r.COMPRESSED_RGBA_ASTC_8x6_KHR;if(n===vc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:r.COMPRESSED_RGBA_ASTC_8x8_KHR;if(n===_c)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:r.COMPRESSED_RGBA_ASTC_10x5_KHR;if(n===yc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:r.COMPRESSED_RGBA_ASTC_10x6_KHR;if(n===xc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:r.COMPRESSED_RGBA_ASTC_10x8_KHR;if(n===Mc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:r.COMPRESSED_RGBA_ASTC_10x10_KHR;if(n===bc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:r.COMPRESSED_RGBA_ASTC_12x10_KHR;if(n===Sc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:r.COMPRESSED_RGBA_ASTC_12x12_KHR}else return null;if(n===la||n===wc||n===Ac)if(r=e.get("EXT_texture_compression_bptc"),r!==null){if(n===la)return o===Mt?r.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT:r.COMPRESSED_RGBA_BPTC_UNORM_EXT;if(n===wc)return r.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT;if(n===Ac)return r.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT}else return null;if(n===Hf||n===Tc||n===Ec||n===Cc)if(r=e.get("EXT_texture_compression_rgtc"),r!==null){if(n===la)return r.COMPRESSED_RED_RGTC1_EXT;if(n===Tc)return r.COMPRESSED_SIGNED_RED_RGTC1_EXT;if(n===Ec)return r.COMPRESSED_RED_GREEN_RGTC2_EXT;if(n===Cc)return r.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT}else return null;return n===rs?s.UNSIGNED_INT_24_8:s[n]!==void 0?s[n]:null}return{convert:t}}class xp extends Ut{constructor(e=[]){super(),this.isArrayCamera=!0,this.cameras=e}}class Fs extends ct{constructor(){super(),this.isGroup=!0,this.type="Group"}}const iM={type:"move"};class Nl{constructor(){this._targetRay=null,this._grip=null,this._hand=null}getHandSpace(){return this._hand===null&&(this._hand=new Fs,this._hand.matrixAutoUpdate=!1,this._hand.visible=!1,this._hand.joints={},this._hand.inputState={pinching:!1}),this._hand}getTargetRaySpace(){return this._targetRay===null&&(this._targetRay=new Fs,this._targetRay.matrixAutoUpdate=!1,this._targetRay.visible=!1,this._targetRay.hasLinearVelocity=!1,this._targetRay.linearVelocity=new N,this._targetRay.hasAngularVelocity=!1,this._targetRay.angularVelocity=new N),this._targetRay}getGripSpace(){return this._grip===null&&(this._grip=new Fs,this._grip.matrixAutoUpdate=!1,this._grip.visible=!1,this._grip.hasLinearVelocity=!1,this._grip.linearVelocity=new N,this._grip.hasAngularVelocity=!1,this._grip.angularVelocity=new N),this._grip}dispatchEvent(e){return this._targetRay!==null&&this._targetRay.dispatchEvent(e),this._grip!==null&&this._grip.dispatchEvent(e),this._hand!==null&&this._hand.dispatchEvent(e),this}connect(e){if(e&&e.hand){const t=this._hand;if(t)for(const n of e.hand.values())this._getHandJoint(t,n)}return this.dispatchEvent({type:"connected",data:e}),this}disconnect(e){return this.dispatchEvent({type:"disconnected",data:e}),this._targetRay!==null&&(this._targetRay.visible=!1),this._grip!==null&&(this._grip.visible=!1),this._hand!==null&&(this._hand.visible=!1),this}update(e,t,n){let i=null,r=null,o=null;const a=this._targetRay,l=this._grip,c=this._hand;if(e&&t.session.visibilityState!=="visible-blurred"){if(c&&e.hand){o=!0;for(const v of e.hand.values()){const m=t.getJointPose(v,n),p=this._getHandJoint(c,v);m!==null&&(p.matrix.fromArray(m.transform.matrix),p.matrix.decompose(p.position,p.rotation,p.scale),p.matrixWorldNeedsUpdate=!0,p.jointRadius=m.radius),p.visible=m!==null}const u=c.joints["index-finger-tip"],h=c.joints["thumb-tip"],d=u.position.distanceTo(h.position),f=.02,g=.005;c.inputState.pinching&&d>f+g?(c.inputState.pinching=!1,this.dispatchEvent({type:"pinchend",handedness:e.handedness,target:this})):!c.inputState.pinching&&d<=f-g&&(c.inputState.pinching=!0,this.dispatchEvent({type:"pinchstart",handedness:e.handedness,target:this}))}else l!==null&&e.gripSpace&&(r=t.getPose(e.gripSpace,n),r!==null&&(l.matrix.fromArray(r.transform.matrix),l.matrix.decompose(l.position,l.rotation,l.scale),l.matrixWorldNeedsUpdate=!0,r.linearVelocity?(l.hasLinearVelocity=!0,l.linearVelocity.copy(r.linearVelocity)):l.hasLinearVelocity=!1,r.angularVelocity?(l.hasAngularVelocity=!0,l.angularVelocity.copy(r.angularVelocity)):l.hasAngularVelocity=!1));a!==null&&(i=t.getPose(e.targetRaySpace,n),i===null&&r!==null&&(i=r),i!==null&&(a.matrix.fromArray(i.transform.matrix),a.matrix.decompose(a.position,a.rotation,a.scale),a.matrixWorldNeedsUpdate=!0,i.linearVelocity?(a.hasLinearVelocity=!0,a.linearVelocity.copy(i.linearVelocity)):a.hasLinearVelocity=!1,i.angularVelocity?(a.hasAngularVelocity=!0,a.angularVelocity.copy(i.angularVelocity)):a.hasAngularVelocity=!1,this.dispatchEvent(iM)))}return a!==null&&(a.visible=i!==null),l!==null&&(l.visible=r!==null),c!==null&&(c.visible=o!==null),this}_getHandJoint(e,t){if(e.joints[t.jointName]===void 0){const n=new Fs;n.matrixAutoUpdate=!1,n.visible=!1,e.joints[t.jointName]=n,e.add(n)}return e.joints[t.jointName]}}const sM=` +void main() { + + gl_Position = vec4( position, 1.0 ); + +}`,rM=` +uniform sampler2DArray depthColor; +uniform float depthWidth; +uniform float depthHeight; + +void main() { + + vec2 coord = vec2( gl_FragCoord.x / depthWidth, gl_FragCoord.y / depthHeight ); + + if ( coord.x >= 1.0 ) { + + gl_FragDepth = texture( depthColor, vec3( coord.x - 1.0, coord.y, 1 ) ).r; + + } else { + + gl_FragDepth = texture( depthColor, vec3( coord.x, coord.y, 0 ) ).r; + + } + +}`;class oM{constructor(){this.texture=null,this.mesh=null,this.depthNear=0,this.depthFar=0}init(e,t,n){if(this.texture===null){const i=new Pt,r=e.properties.get(i);r.__webglTexture=t.texture,(t.depthNear!=n.depthNear||t.depthFar!=n.depthFar)&&(this.depthNear=t.depthNear,this.depthFar=t.depthFar),this.texture=i}}getMesh(e){if(this.texture!==null&&this.mesh===null){const t=e.cameras[0].viewport,n=new Ln({vertexShader:sM,fragmentShader:rM,uniforms:{depthColor:{value:this.texture},depthWidth:{value:t.z},depthHeight:{value:t.w}}});this.mesh=new Nt(new Xs(20,20),n)}return this.mesh}reset(){this.texture=null,this.mesh=null}}class aM extends ui{constructor(e,t){super();const n=this;let i=null,r=1,o=null,a="local-floor",l=1,c=null,u=null,h=null,d=null,f=null,g=null;const v=new oM,m=t.getContextAttributes();let p=null,y=null;const _=[],x=[],A=new se;let b=null;const E=new Ut;E.layers.enable(1),E.viewport=new gt;const I=new Ut;I.layers.enable(2),I.viewport=new gt;const w=[E,I],M=new xp;M.layers.enable(1),M.layers.enable(2);let F=null,V=null;this.cameraAutoUpdate=!0,this.enabled=!1,this.isPresenting=!1,this.getController=function(U){let D=_[U];return D===void 0&&(D=new Nl,_[U]=D),D.getTargetRaySpace()},this.getControllerGrip=function(U){let D=_[U];return D===void 0&&(D=new Nl,_[U]=D),D.getGripSpace()},this.getHand=function(U){let D=_[U];return D===void 0&&(D=new Nl,_[U]=D),D.getHandSpace()};function G(U){const D=x.indexOf(U.inputSource);if(D===-1)return;const R=_[D];R!==void 0&&(R.update(U.inputSource,U.frame,c||o),R.dispatchEvent({type:U.type,data:U.inputSource}))}function q(){i.removeEventListener("select",G),i.removeEventListener("selectstart",G),i.removeEventListener("selectend",G),i.removeEventListener("squeeze",G),i.removeEventListener("squeezestart",G),i.removeEventListener("squeezeend",G),i.removeEventListener("end",q),i.removeEventListener("inputsourceschange",ae);for(let U=0;U<_.length;U++){const D=x[U];D!==null&&(x[U]=null,_[U].disconnect(D))}F=null,V=null,v.reset(),e.setRenderTarget(p),f=null,d=null,h=null,i=null,y=null,ze.stop(),n.isPresenting=!1,e.setPixelRatio(b),e.setSize(A.width,A.height,!1),n.dispatchEvent({type:"sessionend"})}this.setFramebufferScaleFactor=function(U){r=U,n.isPresenting===!0&&console.warn("THREE.WebXRManager: Cannot change framebuffer scale while presenting.")},this.setReferenceSpaceType=function(U){a=U,n.isPresenting===!0&&console.warn("THREE.WebXRManager: Cannot change reference space type while presenting.")},this.getReferenceSpace=function(){return c||o},this.setReferenceSpace=function(U){c=U},this.getBaseLayer=function(){return d!==null?d:f},this.getBinding=function(){return h},this.getFrame=function(){return g},this.getSession=function(){return i},this.setSession=async function(U){if(i=U,i!==null){if(p=e.getRenderTarget(),i.addEventListener("select",G),i.addEventListener("selectstart",G),i.addEventListener("selectend",G),i.addEventListener("squeeze",G),i.addEventListener("squeezestart",G),i.addEventListener("squeezeend",G),i.addEventListener("end",q),i.addEventListener("inputsourceschange",ae),m.xrCompatible!==!0&&await t.makeXRCompatible(),b=e.getPixelRatio(),e.getSize(A),i.renderState.layers===void 0){const D={antialias:m.antialias,alpha:!0,depth:m.depth,stencil:m.stencil,framebufferScaleFactor:r};f=new XRWebGLLayer(i,t,D),i.updateRenderState({baseLayer:f}),e.setPixelRatio(1),e.setSize(f.framebufferWidth,f.framebufferHeight,!1),y=new In(f.framebufferWidth,f.framebufferHeight,{format:un,type:li,colorSpace:e.outputColorSpace,stencilBuffer:m.stencil})}else{let D=null,R=null,T=null;m.depth&&(T=m.stencil?t.DEPTH24_STENCIL8:t.DEPTH_COMPONENT24,D=m.stencil?os:ts,R=m.stencil?rs:ss);const ie={colorFormat:t.RGBA8,depthFormat:T,scaleFactor:r};h=new XRWebGLBinding(i,t),d=h.createProjectionLayer(ie),i.updateRenderState({layers:[d]}),e.setPixelRatio(1),e.setSize(d.textureWidth,d.textureHeight,!1),y=new In(d.textureWidth,d.textureHeight,{format:un,type:li,depthTexture:new mu(d.textureWidth,d.textureHeight,R,void 0,void 0,void 0,void 0,void 0,void 0,D),stencilBuffer:m.stencil,colorSpace:e.outputColorSpace,samples:m.antialias?4:0,resolveDepthBuffer:d.ignoreDepthValues===!1})}y.isXRRenderTarget=!0,this.setFoveation(l),c=null,o=await i.requestReferenceSpace(a),ze.setContext(i),ze.start(),n.isPresenting=!0,n.dispatchEvent({type:"sessionstart"})}},this.getEnvironmentBlendMode=function(){if(i!==null)return i.environmentBlendMode};function ae(U){for(let D=0;D=0&&(x[T]=null,_[T].disconnect(R))}for(let D=0;D=x.length){x.push(R),T=he;break}else if(x[he]===null){x[he]=R,T=he;break}if(T===-1)break}const ie=_[T];ie&&ie.connect(R)}}const Q=new N,oe=new N;function B(U,D,R){Q.setFromMatrixPosition(D.matrixWorld),oe.setFromMatrixPosition(R.matrixWorld);const T=Q.distanceTo(oe),ie=D.projectionMatrix.elements,he=R.projectionMatrix.elements,J=ie[14]/(ie[10]-1),L=ie[14]/(ie[10]+1),X=(ie[9]+1)/ie[5],K=(ie[9]-1)/ie[5],H=(ie[8]-1)/ie[0],$=(he[8]+1)/he[0],te=J*H,le=J*$,k=T/(-H+$),O=k*-H;D.matrixWorld.decompose(U.position,U.quaternion,U.scale),U.translateX(O),U.translateZ(k),U.matrixWorld.compose(U.position,U.quaternion,U.scale),U.matrixWorldInverse.copy(U.matrixWorld).invert();const P=J+k,S=L+k,ee=te-O,pe=le+(T-O),ce=X*L/S*P,ve=K*L/S*P;U.projectionMatrix.makePerspective(ee,pe,ce,ve,P,S),U.projectionMatrixInverse.copy(U.projectionMatrix).invert()}function Me(U,D){D===null?U.matrixWorld.copy(U.matrix):U.matrixWorld.multiplyMatrices(D.matrixWorld,U.matrix),U.matrixWorldInverse.copy(U.matrixWorld).invert()}this.updateCamera=function(U){if(i===null)return;v.texture!==null&&(U.near=v.depthNear,U.far=v.depthFar),M.near=I.near=E.near=U.near,M.far=I.far=E.far=U.far,(F!==M.near||V!==M.far)&&(i.updateRenderState({depthNear:M.near,depthFar:M.far}),F=M.near,V=M.far,E.near=F,E.far=V,I.near=F,I.far=V,E.updateProjectionMatrix(),I.updateProjectionMatrix(),U.updateProjectionMatrix());const D=U.parent,R=M.cameras;Me(M,D);for(let T=0;T0&&(m.alphaTest.value=p.alphaTest);const y=e.get(p),_=y.envMap,x=y.envMapRotation;_&&(m.envMap.value=_,Vi.copy(x),Vi.x*=-1,Vi.y*=-1,Vi.z*=-1,_.isCubeTexture&&_.isRenderTargetTexture===!1&&(Vi.y*=-1,Vi.z*=-1),m.envMapRotation.value.setFromMatrix4(lM.makeRotationFromEuler(Vi)),m.flipEnvMap.value=_.isCubeTexture&&_.isRenderTargetTexture===!1?-1:1,m.reflectivity.value=p.reflectivity,m.ior.value=p.ior,m.refractionRatio.value=p.refractionRatio),p.lightMap&&(m.lightMap.value=p.lightMap,m.lightMapIntensity.value=p.lightMapIntensity,t(p.lightMap,m.lightMapTransform)),p.aoMap&&(m.aoMap.value=p.aoMap,m.aoMapIntensity.value=p.aoMapIntensity,t(p.aoMap,m.aoMapTransform))}function o(m,p){m.diffuse.value.copy(p.color),m.opacity.value=p.opacity,p.map&&(m.map.value=p.map,t(p.map,m.mapTransform))}function a(m,p){m.dashSize.value=p.dashSize,m.totalSize.value=p.dashSize+p.gapSize,m.scale.value=p.scale}function l(m,p,y,_){m.diffuse.value.copy(p.color),m.opacity.value=p.opacity,m.size.value=p.size*y,m.scale.value=_*.5,p.map&&(m.map.value=p.map,t(p.map,m.uvTransform)),p.alphaMap&&(m.alphaMap.value=p.alphaMap,t(p.alphaMap,m.alphaMapTransform)),p.alphaTest>0&&(m.alphaTest.value=p.alphaTest)}function c(m,p){m.diffuse.value.copy(p.color),m.opacity.value=p.opacity,m.rotation.value=p.rotation,p.map&&(m.map.value=p.map,t(p.map,m.mapTransform)),p.alphaMap&&(m.alphaMap.value=p.alphaMap,t(p.alphaMap,m.alphaMapTransform)),p.alphaTest>0&&(m.alphaTest.value=p.alphaTest)}function u(m,p){m.specular.value.copy(p.specular),m.shininess.value=Math.max(p.shininess,1e-4)}function h(m,p){p.gradientMap&&(m.gradientMap.value=p.gradientMap)}function d(m,p){m.metalness.value=p.metalness,p.metalnessMap&&(m.metalnessMap.value=p.metalnessMap,t(p.metalnessMap,m.metalnessMapTransform)),m.roughness.value=p.roughness,p.roughnessMap&&(m.roughnessMap.value=p.roughnessMap,t(p.roughnessMap,m.roughnessMapTransform)),p.envMap&&(m.envMapIntensity.value=p.envMapIntensity)}function f(m,p,y){m.ior.value=p.ior,p.sheen>0&&(m.sheenColor.value.copy(p.sheenColor).multiplyScalar(p.sheen),m.sheenRoughness.value=p.sheenRoughness,p.sheenColorMap&&(m.sheenColorMap.value=p.sheenColorMap,t(p.sheenColorMap,m.sheenColorMapTransform)),p.sheenRoughnessMap&&(m.sheenRoughnessMap.value=p.sheenRoughnessMap,t(p.sheenRoughnessMap,m.sheenRoughnessMapTransform))),p.clearcoat>0&&(m.clearcoat.value=p.clearcoat,m.clearcoatRoughness.value=p.clearcoatRoughness,p.clearcoatMap&&(m.clearcoatMap.value=p.clearcoatMap,t(p.clearcoatMap,m.clearcoatMapTransform)),p.clearcoatRoughnessMap&&(m.clearcoatRoughnessMap.value=p.clearcoatRoughnessMap,t(p.clearcoatRoughnessMap,m.clearcoatRoughnessMapTransform)),p.clearcoatNormalMap&&(m.clearcoatNormalMap.value=p.clearcoatNormalMap,t(p.clearcoatNormalMap,m.clearcoatNormalMapTransform),m.clearcoatNormalScale.value.copy(p.clearcoatNormalScale),p.side===nn&&m.clearcoatNormalScale.value.negate())),p.dispersion>0&&(m.dispersion.value=p.dispersion),p.iridescence>0&&(m.iridescence.value=p.iridescence,m.iridescenceIOR.value=p.iridescenceIOR,m.iridescenceThicknessMinimum.value=p.iridescenceThicknessRange[0],m.iridescenceThicknessMaximum.value=p.iridescenceThicknessRange[1],p.iridescenceMap&&(m.iridescenceMap.value=p.iridescenceMap,t(p.iridescenceMap,m.iridescenceMapTransform)),p.iridescenceThicknessMap&&(m.iridescenceThicknessMap.value=p.iridescenceThicknessMap,t(p.iridescenceThicknessMap,m.iridescenceThicknessMapTransform))),p.transmission>0&&(m.transmission.value=p.transmission,m.transmissionSamplerMap.value=y.texture,m.transmissionSamplerSize.value.set(y.width,y.height),p.transmissionMap&&(m.transmissionMap.value=p.transmissionMap,t(p.transmissionMap,m.transmissionMapTransform)),m.thickness.value=p.thickness,p.thicknessMap&&(m.thicknessMap.value=p.thicknessMap,t(p.thicknessMap,m.thicknessMapTransform)),m.attenuationDistance.value=p.attenuationDistance,m.attenuationColor.value.copy(p.attenuationColor)),p.anisotropy>0&&(m.anisotropyVector.value.set(p.anisotropy*Math.cos(p.anisotropyRotation),p.anisotropy*Math.sin(p.anisotropyRotation)),p.anisotropyMap&&(m.anisotropyMap.value=p.anisotropyMap,t(p.anisotropyMap,m.anisotropyMapTransform))),m.specularIntensity.value=p.specularIntensity,m.specularColor.value.copy(p.specularColor),p.specularColorMap&&(m.specularColorMap.value=p.specularColorMap,t(p.specularColorMap,m.specularColorMapTransform)),p.specularIntensityMap&&(m.specularIntensityMap.value=p.specularIntensityMap,t(p.specularIntensityMap,m.specularIntensityMapTransform))}function g(m,p){p.matcap&&(m.matcap.value=p.matcap)}function v(m,p){const y=e.get(p).light;m.referencePosition.value.setFromMatrixPosition(y.matrixWorld),m.nearDistance.value=y.shadow.camera.near,m.farDistance.value=y.shadow.camera.far}return{refreshFogUniforms:n,refreshMaterialUniforms:i}}function uM(s,e,t,n){let i={},r={},o=[];const a=s.getParameter(s.MAX_UNIFORM_BUFFER_BINDINGS);function l(y,_){const x=_.program;n.uniformBlockBinding(y,x)}function c(y,_){let x=i[y.id];x===void 0&&(g(y),x=u(y),i[y.id]=x,y.addEventListener("dispose",m));const A=_.program;n.updateUBOMapping(y,A);const b=e.render.frame;r[y.id]!==b&&(d(y),r[y.id]=b)}function u(y){const _=h();y.__bindingPointIndex=_;const x=s.createBuffer(),A=y.__size,b=y.usage;return s.bindBuffer(s.UNIFORM_BUFFER,x),s.bufferData(s.UNIFORM_BUFFER,A,b),s.bindBuffer(s.UNIFORM_BUFFER,null),s.bindBufferBase(s.UNIFORM_BUFFER,_,x),x}function h(){for(let y=0;y0&&(x+=A-b),y.__size=x,y.__cache={},this}function v(y){const _={boundary:0,storage:0};return typeof y=="number"||typeof y=="boolean"?(_.boundary=4,_.storage=4):y.isVector2?(_.boundary=8,_.storage=8):y.isVector3||y.isColor?(_.boundary=16,_.storage=12):y.isVector4?(_.boundary=16,_.storage=16):y.isMatrix3?(_.boundary=48,_.storage=48):y.isMatrix4?(_.boundary=64,_.storage=64):y.isTexture?console.warn("THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group."):console.warn("THREE.WebGLRenderer: Unsupported uniform value type.",y),_}function m(y){const _=y.target;_.removeEventListener("dispose",m);const x=o.indexOf(_.__bindingPointIndex);o.splice(x,1),s.deleteBuffer(i[_.id]),delete i[_.id],delete r[_.id]}function p(){for(const y in i)s.deleteBuffer(i[y]);o=[],i={},r={}}return{bind:l,update:c,dispose:p}}class ha{constructor(e={}){const{canvas:t=rp(),context:n=null,depth:i=!0,stencil:r=!1,alpha:o=!1,antialias:a=!1,premultipliedAlpha:l=!0,preserveDrawingBuffer:c=!1,powerPreference:u="default",failIfMajorPerformanceCaveat:h=!1}=e;this.isWebGLRenderer=!0;let d;if(n!==null){if(typeof WebGLRenderingContext<"u"&&n instanceof WebGLRenderingContext)throw new Error("THREE.WebGLRenderer: WebGL 1 is not supported since r163.");d=n.getContextAttributes().alpha}else d=o;const f=new Uint32Array(4),g=new Int32Array(4);let v=null,m=null;const p=[],y=[];this.domElement=t,this.debug={checkShaderErrors:!0,onShaderError:null},this.autoClear=!0,this.autoClearColor=!0,this.autoClearDepth=!0,this.autoClearStencil=!0,this.sortObjects=!0,this.clippingPlanes=[],this.localClippingEnabled=!1,this._outputColorSpace=ln,this.toneMapping=Hn,this.toneMappingExposure=1;const _=this;let x=!1,A=0,b=0,E=null,I=-1,w=null;const M=new gt,F=new gt;let V=null;const G=new Pe(0);let q=0,ae=t.width,Q=t.height,oe=1,B=null,Me=null;const be=new gt(0,0,ae,Q),Ae=new gt(0,0,ae,Q);let ge=!1;const ze=new Yr;let U=!1,D=!1;const R=new qe,T=new N,ie={background:null,fog:null,environment:null,overrideMaterial:null,isScene:!0};let he=!1;function J(){return E===null?oe:1}let L=n;function X(C,W){return t.getContext(C,W)}try{const C={alpha:!0,depth:i,stencil:r,antialias:a,premultipliedAlpha:l,preserveDrawingBuffer:c,powerPreference:u,failIfMajorPerformanceCaveat:h};if("setAttribute"in t&&t.setAttribute("data-engine",`three.js r${Hr}`),t.addEventListener("webglcontextlost",Ie,!1),t.addEventListener("webglcontextrestored",de,!1),t.addEventListener("webglcontextcreationerror",_e,!1),L===null){const W="webgl2";if(L=X(W,C),L===null)throw X(W)?new Error("Error creating WebGL context with your selected attributes."):new Error("Error creating WebGL context.")}}catch(C){throw console.error("THREE.WebGLRenderer: "+C.message),C}let K,H,$,te,le,k,O,P,S,ee,pe,ce,ve,Ve,Ee,Te,Qe,xe,Ue,st,Je,Re,rt,at;function Rt(){K=new Sy(L),K.init(),Re=new yp(L,K),H=new vy(L,K,e,Re),$=new tM(L),te=new Ty(L),le=new Gx,k=new nM(L,K,$,le,H,Re,te),O=new yy(_),P=new by(_),S=new Nv(L),rt=new my(L,S),ee=new wy(L,S,te,rt),pe=new Cy(L,ee,S,te),Ue=new Ey(L,H,k),Te=new _y(le),ce=new Hx(_,O,P,K,H,rt,Te),ve=new cM(_,le),Ve=new $x,Ee=new Kx(K),xe=new py(_,O,P,$,pe,d,l),Qe=new eM(_,pe,H),at=new uM(L,te,H,$),st=new gy(L,K,te),Je=new Ay(L,K,te),te.programs=ce.programs,_.capabilities=H,_.extensions=K,_.properties=le,_.renderLists=Ve,_.shadowMap=Qe,_.state=$,_.info=te}Rt();const z=new aM(_,L);this.xr=z,this.getContext=function(){return L},this.getContextAttributes=function(){return L.getContextAttributes()},this.forceContextLoss=function(){const C=K.get("WEBGL_lose_context");C&&C.loseContext()},this.forceContextRestore=function(){const C=K.get("WEBGL_lose_context");C&&C.restoreContext()},this.getPixelRatio=function(){return oe},this.setPixelRatio=function(C){C!==void 0&&(oe=C,this.setSize(ae,Q,!1))},this.getSize=function(C){return C.set(ae,Q)},this.setSize=function(C,W,ne=!0){if(z.isPresenting){console.warn("THREE.WebGLRenderer: Can't change size while VR device is presenting.");return}ae=C,Q=W,t.width=Math.floor(C*oe),t.height=Math.floor(W*oe),ne===!0&&(t.style.width=C+"px",t.style.height=W+"px"),this.setViewport(0,0,C,W)},this.getDrawingBufferSize=function(C){return C.set(ae*oe,Q*oe).floor()},this.setDrawingBufferSize=function(C,W,ne){ae=C,Q=W,oe=ne,t.width=Math.floor(C*ne),t.height=Math.floor(W*ne),this.setViewport(0,0,C,W)},this.getCurrentViewport=function(C){return C.copy(M)},this.getViewport=function(C){return C.copy(be)},this.setViewport=function(C,W,ne,re){C.isVector4?be.set(C.x,C.y,C.z,C.w):be.set(C,W,ne,re),$.viewport(M.copy(be).multiplyScalar(oe).round())},this.getScissor=function(C){return C.copy(Ae)},this.setScissor=function(C,W,ne,re){C.isVector4?Ae.set(C.x,C.y,C.z,C.w):Ae.set(C,W,ne,re),$.scissor(F.copy(Ae).multiplyScalar(oe).round())},this.getScissorTest=function(){return ge},this.setScissorTest=function(C){$.setScissorTest(ge=C)},this.setOpaqueSort=function(C){B=C},this.setTransparentSort=function(C){Me=C},this.getClearColor=function(C){return C.copy(xe.getClearColor())},this.setClearColor=function(){xe.setClearColor.apply(xe,arguments)},this.getClearAlpha=function(){return xe.getClearAlpha()},this.setClearAlpha=function(){xe.setClearAlpha.apply(xe,arguments)},this.clear=function(C=!0,W=!0,ne=!0){let re=0;if(C){let Z=!1;if(E!==null){const Se=E.texture.format;Z=Se===ou||Se===ru||Se===su}if(Z){const Se=E.texture.type,Le=Se===li||Se===ss||Se===Sr||Se===rs||Se===tu||Se===nu,Oe=xe.getClearColor(),He=xe.getClearAlpha(),Ke=Oe.r,je=Oe.g,Xe=Oe.b;Le?(f[0]=Ke,f[1]=je,f[2]=Xe,f[3]=He,L.clearBufferuiv(L.COLOR,0,f)):(g[0]=Ke,g[1]=je,g[2]=Xe,g[3]=He,L.clearBufferiv(L.COLOR,0,g))}else re|=L.COLOR_BUFFER_BIT}W&&(re|=L.DEPTH_BUFFER_BIT),ne&&(re|=L.STENCIL_BUFFER_BIT,this.state.buffers.stencil.setMask(4294967295)),L.clear(re)},this.clearColor=function(){this.clear(!0,!1,!1)},this.clearDepth=function(){this.clear(!1,!0,!1)},this.clearStencil=function(){this.clear(!1,!1,!0)},this.dispose=function(){t.removeEventListener("webglcontextlost",Ie,!1),t.removeEventListener("webglcontextrestored",de,!1),t.removeEventListener("webglcontextcreationerror",_e,!1),Ve.dispose(),Ee.dispose(),le.dispose(),O.dispose(),P.dispose(),pe.dispose(),rt.dispose(),at.dispose(),ce.dispose(),z.dispose(),z.removeEventListener("sessionstart",On),z.removeEventListener("sessionend",Fn),Di.stop()};function Ie(C){C.preventDefault(),console.log("THREE.WebGLRenderer: Context Lost."),x=!0}function de(){console.log("THREE.WebGLRenderer: Context Restored."),x=!1;const C=te.autoReset,W=Qe.enabled,ne=Qe.autoUpdate,re=Qe.needsUpdate,Z=Qe.type;Rt(),te.autoReset=C,Qe.enabled=W,Qe.autoUpdate=ne,Qe.needsUpdate=re,Qe.type=Z}function _e(C){console.error("THREE.WebGLRenderer: A WebGL context could not be created. Reason: ",C.statusMessage)}function we(C){const W=C.target;W.removeEventListener("dispose",we),et(W)}function et(C){ut(C),le.remove(C)}function ut(C){const W=le.get(C).programs;W!==void 0&&(W.forEach(function(ne){ce.releaseProgram(ne)}),C.isShaderMaterial&&ce.releaseShaderCache(C))}this.renderBufferDirect=function(C,W,ne,re,Z,Se){W===null&&(W=ie);const Le=Z.isMesh&&Z.matrixWorld.determinant()<0,Oe=Fm(C,W,ne,re,Z);$.setMaterial(re,Le);let He=ne.index,Ke=1;if(re.wireframe===!0){if(He=ee.getWireframeAttribute(ne),He===void 0)return;Ke=2}const je=ne.drawRange,Xe=ne.attributes.position;let dt=je.start*Ke,wt=(je.start+je.count)*Ke;Se!==null&&(dt=Math.max(dt,Se.start*Ke),wt=Math.min(wt,(Se.start+Se.count)*Ke)),He!==null?(dt=Math.max(dt,0),wt=Math.min(wt,He.count)):Xe!=null&&(dt=Math.max(dt,0),wt=Math.min(wt,Xe.count));const At=wt-dt;if(At<0||At===1/0)return;rt.setup(Z,re,Oe,ne,He);let dn,mt=st;if(He!==null&&(dn=S.get(He),mt=Je,mt.setIndex(dn)),Z.isMesh)re.wireframe===!0?($.setLineWidth(re.wireframeLinewidth*J()),mt.setMode(L.LINES)):mt.setMode(L.TRIANGLES);else if(Z.isLine){let We=re.linewidth;We===void 0&&(We=1),$.setLineWidth(We*J()),Z.isLineSegments?mt.setMode(L.LINES):Z.isLineLoop?mt.setMode(L.LINE_LOOP):mt.setMode(L.LINE_STRIP)}else Z.isPoints?mt.setMode(L.POINTS):Z.isSprite&&mt.setMode(L.TRIANGLES);if(Z.isBatchedMesh)Z._multiDrawInstances!==null?mt.renderMultiDrawInstances(Z._multiDrawStarts,Z._multiDrawCounts,Z._multiDrawCount,Z._multiDrawInstances):mt.renderMultiDraw(Z._multiDrawStarts,Z._multiDrawCounts,Z._multiDrawCount);else if(Z.isInstancedMesh)mt.renderInstances(dt,At,Z.count);else if(ne.isInstancedBufferGeometry){const We=ne._maxInstanceCount!==void 0?ne._maxInstanceCount:1/0,jt=Math.min(ne.instanceCount,We);mt.renderInstances(dt,At,jt)}else mt.render(dt,At)};function It(C,W,ne){C.transparent===!0&&C.side===En&&C.forceSinglePass===!1?(C.side=nn,C.needsUpdate=!0,so(C,W,ne),C.side=oi,C.needsUpdate=!0,so(C,W,ne),C.side=En):so(C,W,ne)}this.compile=function(C,W,ne=null){ne===null&&(ne=C),m=Ee.get(ne),m.init(W),y.push(m),ne.traverseVisible(function(Z){Z.isLight&&Z.layers.test(W.layers)&&(m.pushLight(Z),Z.castShadow&&m.pushShadow(Z))}),C!==ne&&C.traverseVisible(function(Z){Z.isLight&&Z.layers.test(W.layers)&&(m.pushLight(Z),Z.castShadow&&m.pushShadow(Z))}),m.setupLights();const re=new Set;return C.traverse(function(Z){const Se=Z.material;if(Se)if(Array.isArray(Se))for(let Le=0;Le{function Se(){if(re.forEach(function(Le){le.get(Le).currentProgram.isReady()&&re.delete(Le)}),re.size===0){Z(C);return}setTimeout(Se,10)}K.get("KHR_parallel_shader_compile")!==null?Se():setTimeout(Se,10)})};let Bt=null;function vt(C){Bt&&Bt(C)}function On(){Di.stop()}function Fn(){Di.start()}const Di=new fp;Di.setAnimationLoop(vt),typeof self<"u"&&Di.setContext(self),this.setAnimationLoop=function(C){Bt=C,z.setAnimationLoop(C),C===null?Di.stop():Di.start()},z.addEventListener("sessionstart",On),z.addEventListener("sessionend",Fn),this.render=function(C,W){if(W!==void 0&&W.isCamera!==!0){console.error("THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.");return}if(x===!0)return;if(C.matrixWorldAutoUpdate===!0&&C.updateMatrixWorld(),W.parent===null&&W.matrixWorldAutoUpdate===!0&&W.updateMatrixWorld(),z.enabled===!0&&z.isPresenting===!0&&(z.cameraAutoUpdate===!0&&z.updateCamera(W),W=z.getCamera()),C.isScene===!0&&C.onBeforeRender(_,C,W,E),m=Ee.get(C,y.length),m.init(W),y.push(m),R.multiplyMatrices(W.projectionMatrix,W.matrixWorldInverse),ze.setFromProjectionMatrix(R),D=this.localClippingEnabled,U=Te.init(this.clippingPlanes,D),v=Ve.get(C,p.length),v.init(),p.push(v),z.enabled===!0&&z.isPresenting===!0){const Se=_.xr.getDepthSensingMesh();Se!==null&&rl(Se,W,-1/0,_.sortObjects)}rl(C,W,0,_.sortObjects),v.finish(),_.sortObjects===!0&&v.sort(B,Me),he=z.enabled===!1||z.isPresenting===!1||z.hasDepthSensing()===!1,he&&xe.addToRenderList(v,C),this.info.render.frame++,U===!0&&Te.beginShadows();const ne=m.state.shadowsArray;Qe.render(ne,C,W),U===!0&&Te.endShadows(),this.info.autoReset===!0&&this.info.reset();const re=v.opaque,Z=v.transmissive;if(m.setupLights(),W.isArrayCamera){const Se=W.cameras;if(Z.length>0)for(let Le=0,Oe=Se.length;Le0&&Zu(re,Z,C,W),he&&xe.render(C),Yu(v,C,W);E!==null&&(k.updateMultisampleRenderTarget(E),k.updateRenderTargetMipmap(E)),C.isScene===!0&&C.onAfterRender(_,C,W),rt.resetDefaultState(),I=-1,w=null,y.pop(),y.length>0?(m=y[y.length-1],U===!0&&Te.setGlobalState(_.clippingPlanes,m.state.camera)):m=null,p.pop(),p.length>0?v=p[p.length-1]:v=null};function rl(C,W,ne,re){if(C.visible===!1)return;if(C.layers.test(W.layers)){if(C.isGroup)ne=C.renderOrder;else if(C.isLOD)C.autoUpdate===!0&&C.update(W);else if(C.isLight)m.pushLight(C),C.castShadow&&m.pushShadow(C);else if(C.isSprite){if(!C.frustumCulled||ze.intersectsSprite(C)){re&&T.setFromMatrixPosition(C.matrixWorld).applyMatrix4(R);const Le=pe.update(C),Oe=C.material;Oe.visible&&v.push(C,Le,Oe,ne,T.z,null)}}else if((C.isMesh||C.isLine||C.isPoints)&&(!C.frustumCulled||ze.intersectsObject(C))){const Le=pe.update(C),Oe=C.material;if(re&&(C.boundingSphere!==void 0?(C.boundingSphere===null&&C.computeBoundingSphere(),T.copy(C.boundingSphere.center)):(Le.boundingSphere===null&&Le.computeBoundingSphere(),T.copy(Le.boundingSphere.center)),T.applyMatrix4(C.matrixWorld).applyMatrix4(R)),Array.isArray(Oe)){const He=Le.groups;for(let Ke=0,je=He.length;Ke0&&io(Z,W,ne),Se.length>0&&io(Se,W,ne),Le.length>0&&io(Le,W,ne),$.buffers.depth.setTest(!0),$.buffers.depth.setMask(!0),$.buffers.color.setMask(!0),$.setPolygonOffset(!1)}function Zu(C,W,ne,re){if((ne.isScene===!0?ne.overrideMaterial:null)!==null)return;m.state.transmissionRenderTarget[re.id]===void 0&&(m.state.transmissionRenderTarget[re.id]=new In(1,1,{generateMipmaps:!0,type:K.has("EXT_color_buffer_half_float")||K.has("EXT_color_buffer_float")?Wr:li,minFilter:zn,samples:4,stencilBuffer:r,resolveDepthBuffer:!1,resolveStencilBuffer:!1,colorSpace:ht.workingColorSpace}));const Se=m.state.transmissionRenderTarget[re.id],Le=re.viewport||M;Se.setSize(Le.z,Le.w);const Oe=_.getRenderTarget();_.setRenderTarget(Se),_.getClearColor(G),q=_.getClearAlpha(),q<1&&_.setClearColor(16777215,.5),he?xe.render(ne):_.clear();const He=_.toneMapping;_.toneMapping=Hn;const Ke=re.viewport;if(re.viewport!==void 0&&(re.viewport=void 0),m.setupLightsView(re),U===!0&&Te.setGlobalState(_.clippingPlanes,re),io(C,ne,re),k.updateMultisampleRenderTarget(Se),k.updateRenderTargetMipmap(Se),K.has("WEBGL_multisampled_render_to_texture")===!1){let je=!1;for(let Xe=0,dt=W.length;Xe0),Xe=!!ne.morphAttributes.position,dt=!!ne.morphAttributes.normal,wt=!!ne.morphAttributes.color;let At=Hn;re.toneMapped&&(E===null||E.isXRRenderTarget===!0)&&(At=_.toneMapping);const dn=ne.morphAttributes.position||ne.morphAttributes.normal||ne.morphAttributes.color,mt=dn!==void 0?dn.length:0,We=le.get(re),jt=m.state.lights;if(U===!0&&(D===!0||C!==w)){const yn=C===w&&re.id===I;Te.setState(re,C,yn)}let _t=!1;re.version===We.__version?(We.needsLights&&We.lightsStateVersion!==jt.state.version||We.outputColorSpace!==Oe||Z.isBatchedMesh&&We.batching===!1||!Z.isBatchedMesh&&We.batching===!0||Z.isBatchedMesh&&We.batchingColor===!0&&Z.colorTexture===null||Z.isBatchedMesh&&We.batchingColor===!1&&Z.colorTexture!==null||Z.isInstancedMesh&&We.instancing===!1||!Z.isInstancedMesh&&We.instancing===!0||Z.isSkinnedMesh&&We.skinning===!1||!Z.isSkinnedMesh&&We.skinning===!0||Z.isInstancedMesh&&We.instancingColor===!0&&Z.instanceColor===null||Z.isInstancedMesh&&We.instancingColor===!1&&Z.instanceColor!==null||Z.isInstancedMesh&&We.instancingMorph===!0&&Z.morphTexture===null||Z.isInstancedMesh&&We.instancingMorph===!1&&Z.morphTexture!==null||We.envMap!==He||re.fog===!0&&We.fog!==Se||We.numClippingPlanes!==void 0&&(We.numClippingPlanes!==Te.numPlanes||We.numIntersection!==Te.numIntersection)||We.vertexAlphas!==Ke||We.vertexTangents!==je||We.morphTargets!==Xe||We.morphNormals!==dt||We.morphColors!==wt||We.toneMapping!==At||We.morphTargetsCount!==mt)&&(_t=!0):(_t=!0,We.__version=re.version);let Yn=We.currentProgram;_t===!0&&(Yn=so(re,W,Z));let ro=!1,Ui=!1,ol=!1;const zt=Yn.getUniforms(),pi=We.uniforms;if($.useProgram(Yn.program)&&(ro=!0,Ui=!0,ol=!0),re.id!==I&&(I=re.id,Ui=!0),ro||w!==C){zt.setValue(L,"projectionMatrix",C.projectionMatrix),zt.setValue(L,"viewMatrix",C.matrixWorldInverse);const yn=zt.map.cameraPosition;yn!==void 0&&yn.setValue(L,T.setFromMatrixPosition(C.matrixWorld)),H.logarithmicDepthBuffer&&zt.setValue(L,"logDepthBufFC",2/(Math.log(C.far+1)/Math.LN2)),(re.isMeshPhongMaterial||re.isMeshToonMaterial||re.isMeshLambertMaterial||re.isMeshBasicMaterial||re.isMeshStandardMaterial||re.isShaderMaterial)&&zt.setValue(L,"isOrthographic",C.isOrthographicCamera===!0),w!==C&&(w=C,Ui=!0,ol=!0)}if(Z.isSkinnedMesh){zt.setOptional(L,Z,"bindMatrix"),zt.setOptional(L,Z,"bindMatrixInverse");const yn=Z.skeleton;yn&&(yn.boneTexture===null&&yn.computeBoneTexture(),zt.setValue(L,"boneTexture",yn.boneTexture,k))}Z.isBatchedMesh&&(zt.setOptional(L,Z,"batchingTexture"),zt.setValue(L,"batchingTexture",Z._matricesTexture,k),zt.setOptional(L,Z,"batchingColorTexture"),Z._colorsTexture!==null&&zt.setValue(L,"batchingColorTexture",Z._colorsTexture,k));const al=ne.morphAttributes;if((al.position!==void 0||al.normal!==void 0||al.color!==void 0)&&Ue.update(Z,ne,Yn),(Ui||We.receiveShadow!==Z.receiveShadow)&&(We.receiveShadow=Z.receiveShadow,zt.setValue(L,"receiveShadow",Z.receiveShadow)),re.isMeshGouraudMaterial&&re.envMap!==null&&(pi.envMap.value=He,pi.flipEnvMap.value=He.isCubeTexture&&He.isRenderTargetTexture===!1?-1:1),re.isMeshStandardMaterial&&re.envMap===null&&W.environment!==null&&(pi.envMapIntensity.value=W.environmentIntensity),Ui&&(zt.setValue(L,"toneMappingExposure",_.toneMappingExposure),We.needsLights&&km(pi,ol),Se&&re.fog===!0&&ve.refreshFogUniforms(pi,Se),ve.refreshMaterialUniforms(pi,re,oe,Q,m.state.transmissionRenderTarget[C.id]),ua.upload(L,Ku(We),pi,k)),re.isShaderMaterial&&re.uniformsNeedUpdate===!0&&(ua.upload(L,Ku(We),pi,k),re.uniformsNeedUpdate=!1),re.isSpriteMaterial&&zt.setValue(L,"center",Z.center),zt.setValue(L,"modelViewMatrix",Z.modelViewMatrix),zt.setValue(L,"normalMatrix",Z.normalMatrix),zt.setValue(L,"modelMatrix",Z.matrixWorld),re.isShaderMaterial||re.isRawShaderMaterial){const yn=re.uniformsGroups;for(let ll=0,zm=yn.length;ll0&&k.useMultisampledRTT(C)===!1?Z=le.get(C).__webglMultisampledFramebuffer:Array.isArray(je)?Z=je[ne]:Z=je,M.copy(C.viewport),F.copy(C.scissor),V=C.scissorTest}else M.copy(be).multiplyScalar(oe).floor(),F.copy(Ae).multiplyScalar(oe).floor(),V=ge;if($.bindFramebuffer(L.FRAMEBUFFER,Z)&&re&&$.drawBuffers(C,Z),$.viewport(M),$.scissor(F),$.setScissorTest(V),Se){const He=le.get(C.texture);L.framebufferTexture2D(L.FRAMEBUFFER,L.COLOR_ATTACHMENT0,L.TEXTURE_CUBE_MAP_POSITIVE_X+W,He.__webglTexture,ne)}else if(Le){const He=le.get(C.texture),Ke=W||0;L.framebufferTextureLayer(L.FRAMEBUFFER,L.COLOR_ATTACHMENT0,He.__webglTexture,ne||0,Ke)}I=-1},this.readRenderTargetPixels=function(C,W,ne,re,Z,Se,Le){if(!(C&&C.isWebGLRenderTarget)){console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");return}let Oe=le.get(C).__webglFramebuffer;if(C.isWebGLCubeRenderTarget&&Le!==void 0&&(Oe=Oe[Le]),Oe){$.bindFramebuffer(L.FRAMEBUFFER,Oe);try{const He=C.texture,Ke=He.format,je=He.type;if(!H.textureFormatReadable(Ke)){console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.");return}if(!H.textureTypeReadable(je)){console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.");return}W>=0&&W<=C.width-re&&ne>=0&&ne<=C.height-Z&&L.readPixels(W,ne,re,Z,Re.convert(Ke),Re.convert(je),Se)}finally{const He=E!==null?le.get(E).__webglFramebuffer:null;$.bindFramebuffer(L.FRAMEBUFFER,He)}}},this.readRenderTargetPixelsAsync=async function(C,W,ne,re,Z,Se,Le){if(!(C&&C.isWebGLRenderTarget))throw new Error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");let Oe=le.get(C).__webglFramebuffer;if(C.isWebGLCubeRenderTarget&&Le!==void 0&&(Oe=Oe[Le]),Oe){$.bindFramebuffer(L.FRAMEBUFFER,Oe);try{const He=C.texture,Ke=He.format,je=He.type;if(!H.textureFormatReadable(Ke))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.");if(!H.textureTypeReadable(je))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.");if(W>=0&&W<=C.width-re&&ne>=0&&ne<=C.height-Z){const Xe=L.createBuffer();L.bindBuffer(L.PIXEL_PACK_BUFFER,Xe),L.bufferData(L.PIXEL_PACK_BUFFER,Se.byteLength,L.STREAM_READ),L.readPixels(W,ne,re,Z,Re.convert(Ke),Re.convert(je),0),L.flush();const dt=L.fenceSync(L.SYNC_GPU_COMMANDS_COMPLETE,0);await sv(L,dt,4);try{L.bindBuffer(L.PIXEL_PACK_BUFFER,Xe),L.getBufferSubData(L.PIXEL_PACK_BUFFER,0,Se)}finally{L.deleteBuffer(Xe),L.deleteSync(dt)}return Se}}finally{const He=E!==null?le.get(E).__webglFramebuffer:null;$.bindFramebuffer(L.FRAMEBUFFER,He)}}},this.copyFramebufferToTexture=function(C,W=null,ne=0){C.isTexture!==!0&&(console.warn("WebGLRenderer: copyFramebufferToTexture function signature has changed."),W=arguments[0]||null,C=arguments[1]);const re=Math.pow(2,-ne),Z=Math.floor(C.image.width*re),Se=Math.floor(C.image.height*re),Le=W!==null?W.x:0,Oe=W!==null?W.y:0;k.setTexture2D(C,0),L.copyTexSubImage2D(L.TEXTURE_2D,ne,0,0,Le,Oe,Z,Se),$.unbindTexture()},this.copyTextureToTexture=function(C,W,ne=null,re=null,Z=0){C.isTexture!==!0&&(console.warn("WebGLRenderer: copyTextureToTexture function signature has changed."),re=arguments[0]||null,C=arguments[1],W=arguments[2],Z=arguments[3]||0,ne=null);let Se,Le,Oe,He,Ke,je;ne!==null?(Se=ne.max.x-ne.min.x,Le=ne.max.y-ne.min.y,Oe=ne.min.x,He=ne.min.y):(Se=C.image.width,Le=C.image.height,Oe=0,He=0),re!==null?(Ke=re.x,je=re.y):(Ke=0,je=0);const Xe=Re.convert(W.format),dt=Re.convert(W.type);k.setTexture2D(W,0),L.pixelStorei(L.UNPACK_FLIP_Y_WEBGL,W.flipY),L.pixelStorei(L.UNPACK_PREMULTIPLY_ALPHA_WEBGL,W.premultiplyAlpha),L.pixelStorei(L.UNPACK_ALIGNMENT,W.unpackAlignment);const wt=L.getParameter(L.UNPACK_ROW_LENGTH),At=L.getParameter(L.UNPACK_IMAGE_HEIGHT),dn=L.getParameter(L.UNPACK_SKIP_PIXELS),mt=L.getParameter(L.UNPACK_SKIP_ROWS),We=L.getParameter(L.UNPACK_SKIP_IMAGES),jt=C.isCompressedTexture?C.mipmaps[Z]:C.image;L.pixelStorei(L.UNPACK_ROW_LENGTH,jt.width),L.pixelStorei(L.UNPACK_IMAGE_HEIGHT,jt.height),L.pixelStorei(L.UNPACK_SKIP_PIXELS,Oe),L.pixelStorei(L.UNPACK_SKIP_ROWS,He),C.isDataTexture?L.texSubImage2D(L.TEXTURE_2D,Z,Ke,je,Se,Le,Xe,dt,jt.data):C.isCompressedTexture?L.compressedTexSubImage2D(L.TEXTURE_2D,Z,Ke,je,jt.width,jt.height,Xe,jt.data):L.texSubImage2D(L.TEXTURE_2D,Z,Ke,je,Xe,dt,jt),L.pixelStorei(L.UNPACK_ROW_LENGTH,wt),L.pixelStorei(L.UNPACK_IMAGE_HEIGHT,At),L.pixelStorei(L.UNPACK_SKIP_PIXELS,dn),L.pixelStorei(L.UNPACK_SKIP_ROWS,mt),L.pixelStorei(L.UNPACK_SKIP_IMAGES,We),Z===0&&W.generateMipmaps&&L.generateMipmap(L.TEXTURE_2D),$.unbindTexture()},this.copyTextureToTexture3D=function(C,W,ne=null,re=null,Z=0){C.isTexture!==!0&&(console.warn("WebGLRenderer: copyTextureToTexture3D function signature has changed."),ne=arguments[0]||null,re=arguments[1]||null,C=arguments[2],W=arguments[3],Z=arguments[4]||0);let Se,Le,Oe,He,Ke,je,Xe,dt,wt;const At=C.isCompressedTexture?C.mipmaps[Z]:C.image;ne!==null?(Se=ne.max.x-ne.min.x,Le=ne.max.y-ne.min.y,Oe=ne.max.z-ne.min.z,He=ne.min.x,Ke=ne.min.y,je=ne.min.z):(Se=At.width,Le=At.height,Oe=At.depth,He=0,Ke=0,je=0),re!==null?(Xe=re.x,dt=re.y,wt=re.z):(Xe=0,dt=0,wt=0);const dn=Re.convert(W.format),mt=Re.convert(W.type);let We;if(W.isData3DTexture)k.setTexture3D(W,0),We=L.TEXTURE_3D;else if(W.isDataArrayTexture||W.isCompressedArrayTexture)k.setTexture2DArray(W,0),We=L.TEXTURE_2D_ARRAY;else{console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.");return}L.pixelStorei(L.UNPACK_FLIP_Y_WEBGL,W.flipY),L.pixelStorei(L.UNPACK_PREMULTIPLY_ALPHA_WEBGL,W.premultiplyAlpha),L.pixelStorei(L.UNPACK_ALIGNMENT,W.unpackAlignment);const jt=L.getParameter(L.UNPACK_ROW_LENGTH),_t=L.getParameter(L.UNPACK_IMAGE_HEIGHT),Yn=L.getParameter(L.UNPACK_SKIP_PIXELS),ro=L.getParameter(L.UNPACK_SKIP_ROWS),Ui=L.getParameter(L.UNPACK_SKIP_IMAGES);L.pixelStorei(L.UNPACK_ROW_LENGTH,At.width),L.pixelStorei(L.UNPACK_IMAGE_HEIGHT,At.height),L.pixelStorei(L.UNPACK_SKIP_PIXELS,He),L.pixelStorei(L.UNPACK_SKIP_ROWS,Ke),L.pixelStorei(L.UNPACK_SKIP_IMAGES,je),C.isDataTexture||C.isData3DTexture?L.texSubImage3D(We,Z,Xe,dt,wt,Se,Le,Oe,dn,mt,At.data):W.isCompressedArrayTexture?L.compressedTexSubImage3D(We,Z,Xe,dt,wt,Se,Le,Oe,dn,At.data):L.texSubImage3D(We,Z,Xe,dt,wt,Se,Le,Oe,dn,mt,At),L.pixelStorei(L.UNPACK_ROW_LENGTH,jt),L.pixelStorei(L.UNPACK_IMAGE_HEIGHT,_t),L.pixelStorei(L.UNPACK_SKIP_PIXELS,Yn),L.pixelStorei(L.UNPACK_SKIP_ROWS,ro),L.pixelStorei(L.UNPACK_SKIP_IMAGES,Ui),Z===0&&W.generateMipmaps&&L.generateMipmap(We),$.unbindTexture()},this.initRenderTarget=function(C){le.get(C).__webglFramebuffer===void 0&&k.setupRenderTarget(C)},this.initTexture=function(C){C.isCubeTexture?k.setTextureCube(C,0):C.isData3DTexture?k.setTexture3D(C,0):C.isDataArrayTexture||C.isCompressedArrayTexture?k.setTexture2DArray(C,0):k.setTexture2D(C,0),$.unbindTexture()},this.resetState=function(){A=0,b=0,E=null,$.reset(),rt.reset()},typeof __THREE_DEVTOOLS__<"u"&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}get coordinateSystem(){return Vn}get outputColorSpace(){return this._outputColorSpace}set outputColorSpace(e){this._outputColorSpace=e;const t=this.getContext();t.drawingBufferColorSpace=e===Ra?"display-p3":"srgb",t.unpackColorSpace=ht.workingColorSpace===$r?"display-p3":"srgb"}}class Ua{constructor(e,t=25e-5){this.isFogExp2=!0,this.name="",this.color=new Pe(e),this.density=t}clone(){return new Ua(this.color,this.density)}toJSON(){return{type:"FogExp2",name:this.name,color:this.color.getHex(),density:this.density}}}class Oa{constructor(e,t=1,n=1e3){this.isFog=!0,this.name="",this.color=new Pe(e),this.near=t,this.far=n}clone(){return new Oa(this.color,this.near,this.far)}toJSON(){return{type:"Fog",name:this.name,color:this.color.getHex(),near:this.near,far:this.far}}}class Fa extends ct{constructor(){super(),this.isScene=!0,this.type="Scene",this.background=null,this.environment=null,this.fog=null,this.backgroundBlurriness=0,this.backgroundIntensity=1,this.backgroundRotation=new _n,this.environmentIntensity=1,this.environmentRotation=new _n,this.overrideMaterial=null,typeof __THREE_DEVTOOLS__<"u"&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}copy(e,t){return super.copy(e,t),e.background!==null&&(this.background=e.background.clone()),e.environment!==null&&(this.environment=e.environment.clone()),e.fog!==null&&(this.fog=e.fog.clone()),this.backgroundBlurriness=e.backgroundBlurriness,this.backgroundIntensity=e.backgroundIntensity,this.backgroundRotation.copy(e.backgroundRotation),this.environmentIntensity=e.environmentIntensity,this.environmentRotation.copy(e.environmentRotation),e.overrideMaterial!==null&&(this.overrideMaterial=e.overrideMaterial.clone()),this.matrixAutoUpdate=e.matrixAutoUpdate,this}toJSON(e){const t=super.toJSON(e);return this.fog!==null&&(t.object.fog=this.fog.toJSON()),this.backgroundBlurriness>0&&(t.object.backgroundBlurriness=this.backgroundBlurriness),this.backgroundIntensity!==1&&(t.object.backgroundIntensity=this.backgroundIntensity),t.object.backgroundRotation=this.backgroundRotation.toArray(),this.environmentIntensity!==1&&(t.object.environmentIntensity=this.environmentIntensity),t.object.environmentRotation=this.environmentRotation.toArray(),t}}class ka{constructor(e,t){this.isInterleavedBuffer=!0,this.array=e,this.stride=t,this.count=e!==void 0?e.length/t:0,this.usage=Pr,this._updateRange={offset:0,count:-1},this.updateRanges=[],this.version=0,this.uuid=vn()}onUploadCallback(){}set needsUpdate(e){e===!0&&this.version++}get updateRange(){return uu("THREE.InterleavedBuffer: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead."),this._updateRange}setUsage(e){return this.usage=e,this}addUpdateRange(e,t){this.updateRanges.push({start:e,count:t})}clearUpdateRanges(){this.updateRanges.length=0}copy(e){return this.array=new e.array.constructor(e.array),this.count=e.count,this.stride=e.stride,this.usage=e.usage,this}copyAt(e,t,n){e*=this.stride,n*=t.stride;for(let i=0,r=this.stride;ie.far||t.push({distance:l,point:Qs.clone(),uv:mn.getInterpolation(Qs,Co,tr,Po,Hh,Dl,Gh,new se),face:null,object:this})}copy(e,t){return super.copy(e,t),e.center!==void 0&&this.center.copy(e.center),this.material=e.material,this}}function Ro(s,e,t,n,i,r){Is.subVectors(s,t).addScalar(.5).multiply(n),i!==void 0?(er.x=r*Is.x-i*Is.y,er.y=i*Is.x+r*Is.y):er.copy(Is),s.copy(e),s.x+=er.x,s.y+=er.y,s.applyMatrix4(Mp)}const Io=new N,Wh=new N;class Sp extends ct{constructor(){super(),this._currentLevel=0,this.type="LOD",Object.defineProperties(this,{levels:{enumerable:!0,value:[]},isLOD:{value:!0}}),this.autoUpdate=!0}copy(e){super.copy(e,!1);const t=e.levels;for(let n=0,i=t.length;n0){let n,i;for(n=1,i=t.length;n0){Io.setFromMatrixPosition(this.matrixWorld);const i=e.ray.origin.distanceTo(Io);this.getObjectForDistance(i).raycast(e,t)}}update(e){const t=this.levels;if(t.length>1){Io.setFromMatrixPosition(e.matrixWorld),Wh.setFromMatrixPosition(this.matrixWorld);const n=Io.distanceTo(Wh)/e.zoom;t[0].object.visible=!0;let i,r;for(i=1,r=t.length;i=o)t[i-1].object.visible=!1,t[i].object.visible=!0;else break}for(this._currentLevel=i-1;i=n.length&&n.push({start:-1,count:-1,z:-1});const r=n[this.index];i.push(r),this.index++,r.start=e.start,r.count=e.count,r.z=t}reset(){this.list.length=0,this.index=0}}const Ns="batchId",Mi=new qe,Fl=new qe,vM=new qe,_M=new Pe(1,1,1),Qh=new qe,kl=new Yr,Do=new sn,Hi=new Zt,sr=new N,ed=new N,yM=new N,Bl=new gM,Yt=new Nt,Uo=[];function xM(s,e,t=0){const n=e.itemSize;if(s.isInterleavedBufferAttribute||s.array.constructor!==e.array.constructor){const i=s.count;for(let r=0;r65536?new Uint32Array(r):new Uint16Array(r);t.setIndex(new pt(a,1))}const o=i>65536?new Uint32Array(n):new Uint16Array(n);t.setAttribute(Ns,new pt(o,1)),this._geometryInitialized=!0}}_validateGeometry(e){if(e.getAttribute(Ns))throw new Error(`BatchedMesh: Geometry cannot use attribute "${Ns}"`);const t=this.geometry;if(!!e.getIndex()!=!!t.getIndex())throw new Error('BatchedMesh: All geometries must consistently have "index".');for(const n in t.attributes){if(n===Ns)continue;if(!e.hasAttribute(n))throw new Error(`BatchedMesh: Added geometry missing "${n}". All geometries must have consistent attributes.`);const i=e.getAttribute(n),r=t.getAttribute(n);if(i.itemSize!==r.itemSize||i.normalized!==r.normalized)throw new Error("BatchedMesh: All attributes must have a consistent itemSize and normalized value.")}}setCustomSort(e){return this.customSort=e,this}computeBoundingBox(){this.boundingBox===null&&(this.boundingBox=new sn);const e=this._geometryCount,t=this.boundingBox,n=this._active;t.makeEmpty();for(let i=0;i=this._maxGeometryCount)throw new Error("BatchedMesh: Maximum geometry count reached.");const i={vertexStart:-1,vertexCount:-1,indexStart:-1,indexCount:-1};let r=null;const o=this._reservedRanges,a=this._drawRanges,l=this._bounds;this._geometryCount!==0&&(r=o[o.length-1]),t===-1?i.vertexCount=e.getAttribute("position").count:i.vertexCount=t,r===null?i.vertexStart=0:i.vertexStart=r.vertexStart+r.vertexCount;const c=e.getIndex(),u=c!==null;if(u&&(n===-1?i.indexCount=c.count:i.indexCount=n,r===null?i.indexStart=0:i.indexStart=r.indexStart+r.indexCount),i.indexStart!==-1&&i.indexStart+i.indexCount>this._maxIndexCount||i.vertexStart+i.vertexCount>this._maxVertexCount)throw new Error("BatchedMesh: Reserved space request exceeds the maximum buffer size.");const h=this._visibility,d=this._active,f=this._matricesTexture,g=this._matricesTexture.image.data,v=this._colorsTexture;h.push(!0),d.push(!0);const m=this._geometryCount;this._geometryCount++,vM.toArray(g,m*16),f.needsUpdate=!0,v!==null&&(_M.toArray(v.image.data,m*4),v.needsUpdate=!0),o.push(i),a.push({start:u?i.indexStart:i.vertexStart,count:-1}),l.push({boxInitialized:!1,box:new sn,sphereInitialized:!1,sphere:new Zt});const p=this.geometry.getAttribute(Ns);for(let y=0;y=this._geometryCount)throw new Error("BatchedMesh: Maximum geometry count reached.");this._validateGeometry(t);const n=this.geometry,i=n.getIndex()!==null,r=n.getIndex(),o=t.getIndex(),a=this._reservedRanges[e];if(i&&o.count>a.indexCount||t.attributes.position.count>a.vertexCount)throw new Error("BatchedMesh: Reserved space not large enough for provided geometry.");const l=a.vertexStart,c=a.vertexCount;for(const f in n.attributes){if(f===Ns)continue;const g=t.getAttribute(f),v=n.getAttribute(f);xM(g,v,l);const m=g.itemSize;for(let p=g.count,y=c;p=t.length||t[e]===!1?this:(t[e]=!1,this._visibilityChanged=!0,this)}getInstanceCountAt(e){return this._multiDrawInstances===null?null:this._multiDrawInstances[e]}setInstanceCountAt(e,t){return this._multiDrawInstances===null&&(this._multiDrawInstances=new Int32Array(this._maxGeometryCount).fill(1)),this._multiDrawInstances[e]=t,e}getBoundingBoxAt(e,t){if(this._active[e]===!1)return null;const i=this._bounds[e],r=i.box,o=this.geometry;if(i.boxInitialized===!1){r.makeEmpty();const a=o.index,l=o.attributes.position,c=this._drawRanges[e];for(let u=c.start,h=c.start+c.count;u=o||n[e]===!1?this:(t.toArray(r,e*16),i.needsUpdate=!0,this)}getMatrixAt(e,t){const n=this._active,i=this._matricesTexture.image.data,r=this._geometryCount;return e>=r||n[e]===!1?null:t.fromArray(i,e*16)}setColorAt(e,t){this._colorsTexture===null&&this._initColorsTexture();const n=this._active,i=this._colorsTexture,r=this._colorsTexture.image.data,o=this._geometryCount;return e>=o||n[e]===!1?this:(t.toArray(r,e*4),i.needsUpdate=!0,this)}getColorAt(e,t){const n=this._active,i=this._colorsTexture.image.data,r=this._geometryCount;return e>=r||n[e]===!1?null:t.fromArray(i,e*4)}setVisibleAt(e,t){const n=this._visibility,i=this._active,r=this._geometryCount;return e>=r||i[e]===!1||n[e]===t?this:(n[e]=t,this._visibilityChanged=!0,this)}getVisibleAt(e){const t=this._visibility,n=this._active,i=this._geometryCount;return e>=i||n[e]===!1?!1:t[e]}raycast(e,t){const n=this._visibility,i=this._active,r=this._drawRanges,o=this._geometryCount,a=this.matrixWorld,l=this.geometry;Yt.material=this.material,Yt.geometry.index=l.index,Yt.geometry.attributes=l.attributes,Yt.geometry.boundingBox===null&&(Yt.geometry.boundingBox=new sn),Yt.geometry.boundingSphere===null&&(Yt.geometry.boundingSphere=new Zt);for(let c=0;c({...t})),this._reservedRanges=e._reservedRanges.map(t=>({...t})),this._visibility=e._visibility.slice(),this._active=e._active.slice(),this._bounds=e._bounds.map(t=>({boxInitialized:t.boxInitialized,box:t.box.clone(),sphereInitialized:t.sphereInitialized,sphere:t.sphere.clone()})),this._maxGeometryCount=e._maxGeometryCount,this._maxVertexCount=e._maxVertexCount,this._maxIndexCount=e._maxIndexCount,this._geometryInitialized=e._geometryInitialized,this._geometryCount=e._geometryCount,this._multiDrawCounts=e._multiDrawCounts.slice(),this._multiDrawStarts=e._multiDrawStarts.slice(),this._matricesTexture=e._matricesTexture.clone(),this._matricesTexture.image.data=this._matricesTexture.image.slice(),this._colorsTexture!==null&&(this._colorsTexture=e._colorsTexture.clone(),this._colorsTexture.image.data=this._colorsTexture.image.slice()),this}dispose(){return this.geometry.dispose(),this._matricesTexture.dispose(),this._matricesTexture=null,this._colorsTexture!==null&&(this._colorsTexture.dispose(),this._colorsTexture=null),this}onBeforeRender(e,t,n,i,r){if(!this._visibilityChanged&&!this.perObjectFrustumCulled&&!this.sortObjects)return;const o=i.getIndex(),a=o===null?1:o.array.BYTES_PER_ELEMENT,l=this._active,c=this._visibility,u=this._multiDrawStarts,h=this._multiDrawCounts,d=this._drawRanges,f=this.perObjectFrustumCulled;f&&(Qh.multiplyMatrices(n.projectionMatrix,n.matrixWorldInverse).multiply(this.matrixWorld),kl.setFromProjectionMatrix(Qh,e.coordinateSystem));let g=0;if(this.sortObjects){Fl.copy(this.matrixWorld).invert(),sr.setFromMatrixPosition(n.matrixWorld).applyMatrix4(Fl),ed.set(0,0,-1).transformDirection(n.matrixWorld).transformDirection(Fl);for(let p=0,y=c.length;p0){const i=t[n[0]];if(i!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let r=0,o=i.length;rn)return;zl.applyMatrix4(s.matrixWorld);const l=e.ray.origin.distanceTo(zl);if(!(le.far))return{distance:l,point:nd.clone().applyMatrix4(s.matrixWorld),index:i,face:null,faceIndex:null,object:s}}const id=new N,sd=new N;class qn extends Pi{constructor(e,t){super(e,t),this.isLineSegments=!0,this.type="LineSegments"}computeLineDistances(){const e=this.geometry;if(e.index===null){const t=e.attributes.position,n=[];for(let i=0,r=t.count;i0){const i=t[n[0]];if(i!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let r=0,o=i.length;ri.far)return;r.push({distance:c,distanceToRay:Math.sqrt(a),point:l,index:e,face:null,object:o})}}class MM extends Pt{constructor(e,t,n,i,r,o,a,l,c){super(e,t,n,i,r,o,a,l,c),this.isVideoTexture=!0,this.minFilter=o!==void 0?o:Ot,this.magFilter=r!==void 0?r:Ot,this.generateMipmaps=!1;const u=this;function h(){u.needsUpdate=!0,e.requestVideoFrameCallback(h)}"requestVideoFrameCallback"in e&&e.requestVideoFrameCallback(h)}clone(){return new this.constructor(this.image).copy(this)}update(){const e=this.image;"requestVideoFrameCallback"in e===!1&&e.readyState>=e.HAVE_CURRENT_DATA&&(this.needsUpdate=!0)}}class bM extends Pt{constructor(e,t){super({width:e,height:t}),this.isFramebufferTexture=!0,this.magFilter=Gt,this.minFilter=Gt,this.generateMipmaps=!1,this.needsUpdate=!0}}class za extends Pt{constructor(e,t,n,i,r,o,a,l,c,u,h,d){super(null,o,a,l,c,u,i,r,h,d),this.isCompressedTexture=!0,this.image={width:t,height:n},this.mipmaps=e,this.flipY=!1,this.generateMipmaps=!1}}class SM extends za{constructor(e,t,n,i,r,o){super(e,t,n,r,o),this.isCompressedArrayTexture=!0,this.image.depth=i,this.wrapR=Mn,this.layerUpdates=new Set}addLayerUpdates(e){this.layerUpdates.add(e)}clearLayerUpdates(){this.layerUpdates.clear()}}class wM extends za{constructor(e,t,n){super(void 0,e[0].width,e[0].height,t,n,ai),this.isCompressedCubeTexture=!0,this.isCubeTexture=!0,this.image=e}}class AM extends Pt{constructor(e,t,n,i,r,o,a,l,c){super(e,t,n,i,r,o,a,l,c),this.isCanvasTexture=!0,this.needsUpdate=!0}}class Dn{constructor(){this.type="Curve",this.arcLengthDivisions=200}getPoint(){return console.warn("THREE.Curve: .getPoint() not implemented."),null}getPointAt(e,t){const n=this.getUtoTmapping(e);return this.getPoint(n,t)}getPoints(e=5){const t=[];for(let n=0;n<=e;n++)t.push(this.getPoint(n/e));return t}getSpacedPoints(e=5){const t=[];for(let n=0;n<=e;n++)t.push(this.getPointAt(n/e));return t}getLength(){const e=this.getLengths();return e[e.length-1]}getLengths(e=this.arcLengthDivisions){if(this.cacheArcLengths&&this.cacheArcLengths.length===e+1&&!this.needsUpdate)return this.cacheArcLengths;this.needsUpdate=!1;const t=[];let n,i=this.getPoint(0),r=0;t.push(0);for(let o=1;o<=e;o++)n=this.getPoint(o/e),r+=n.distanceTo(i),t.push(r),i=n;return this.cacheArcLengths=t,t}updateArcLengths(){this.needsUpdate=!0,this.getLengths()}getUtoTmapping(e,t){const n=this.getLengths();let i=0;const r=n.length;let o;t?o=t:o=e*n[r-1];let a=0,l=r-1,c;for(;a<=l;)if(i=Math.floor(a+(l-a)/2),c=n[i]-o,c<0)a=i+1;else if(c>0)l=i-1;else{l=i;break}if(i=l,n[i]===o)return i/(r-1);const u=n[i],d=n[i+1]-u,f=(o-u)/d;return(i+f)/(r-1)}getTangent(e,t){let i=e-1e-4,r=e+1e-4;i<0&&(i=0),r>1&&(r=1);const o=this.getPoint(i),a=this.getPoint(r),l=t||(o.isVector2?new se:new N);return l.copy(a).sub(o).normalize(),l}getTangentAt(e,t){const n=this.getUtoTmapping(e);return this.getTangent(n,t)}computeFrenetFrames(e,t){const n=new N,i=[],r=[],o=[],a=new N,l=new qe;for(let f=0;f<=e;f++){const g=f/e;i[f]=this.getTangentAt(g,new N)}r[0]=new N,o[0]=new N;let c=Number.MAX_VALUE;const u=Math.abs(i[0].x),h=Math.abs(i[0].y),d=Math.abs(i[0].z);u<=c&&(c=u,n.set(1,0,0)),h<=c&&(c=h,n.set(0,1,0)),d<=c&&n.set(0,0,1),a.crossVectors(i[0],n).normalize(),r[0].crossVectors(i[0],a),o[0].crossVectors(i[0],r[0]);for(let f=1;f<=e;f++){if(r[f]=r[f-1].clone(),o[f]=o[f-1].clone(),a.crossVectors(i[f-1],i[f]),a.length()>Number.EPSILON){a.normalize();const g=Math.acos(Et(i[f-1].dot(i[f]),-1,1));r[f].applyMatrix4(l.makeRotationAxis(a,g))}o[f].crossVectors(i[f],r[f])}if(t===!0){let f=Math.acos(Et(r[0].dot(r[e]),-1,1));f/=e,i[0].dot(a.crossVectors(r[0],r[e]))>0&&(f=-f);for(let g=1;g<=e;g++)r[g].applyMatrix4(l.makeRotationAxis(i[g],f*g)),o[g].crossVectors(i[g],r[g])}return{tangents:i,normals:r,binormals:o}}clone(){return new this.constructor().copy(this)}copy(e){return this.arcLengthDivisions=e.arcLengthDivisions,this}toJSON(){const e={metadata:{version:4.6,type:"Curve",generator:"Curve.toJSON"}};return e.arcLengthDivisions=this.arcLengthDivisions,e.type=this.type,e}fromJSON(e){return this.arcLengthDivisions=e.arcLengthDivisions,this}}class Va extends Dn{constructor(e=0,t=0,n=1,i=1,r=0,o=Math.PI*2,a=!1,l=0){super(),this.isEllipseCurve=!0,this.type="EllipseCurve",this.aX=e,this.aY=t,this.xRadius=n,this.yRadius=i,this.aStartAngle=r,this.aEndAngle=o,this.aClockwise=a,this.aRotation=l}getPoint(e,t=new se){const n=t,i=Math.PI*2;let r=this.aEndAngle-this.aStartAngle;const o=Math.abs(r)i;)r-=i;r0?0:(Math.floor(Math.abs(a)/r)+1)*r:l===0&&a===r-1&&(a=r-2,l=1);let c,u;this.closed||a>0?c=i[(a-1)%r]:(zo.subVectors(i[0],i[1]).add(i[0]),c=zo);const h=i[a%r],d=i[(a+1)%r];if(this.closed||a+2i.length-2?i.length-1:o+1],h=i[o>i.length-3?i.length-1:o+2];return n.set(ad(a,l.x,c.x,u.x,h.x),ad(a,l.y,c.y,u.y,h.y)),n}copy(e){super.copy(e),this.points=[];for(let t=0,n=e.points.length;t=n){const o=i[r]-n,a=this.curves[r],l=a.getLength(),c=l===0?0:1-o/l;return a.getPointAt(c,t)}r++}return null}getLength(){const e=this.getCurveLengths();return e[e.length-1]}updateArcLengths(){this.needsUpdate=!0,this.cacheLengths=null,this.getCurveLengths()}getCurveLengths(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths;const e=[];let t=0;for(let n=0,i=this.curves.length;n1&&!t[t.length-1].equals(t[0])&&t.push(t[0]),t}copy(e){super.copy(e),this.curves=[];for(let t=0,n=e.curves.length;t0){const h=c.getPoint(0);h.equals(this.currentPoint)||this.lineTo(h.x,h.y)}this.curves.push(c);const u=c.getPoint(1);return this.currentPoint.copy(u),this}copy(e){return super.copy(e),this.currentPoint.copy(e.currentPoint),this}toJSON(){const e=super.toJSON();return e.currentPoint=this.currentPoint.toArray(),e}fromJSON(e){return super.fromJSON(e),this.currentPoint.fromArray(e.currentPoint),this}}class Zr extends it{constructor(e=[new se(0,-.5),new se(.5,0),new se(0,.5)],t=12,n=0,i=Math.PI*2){super(),this.type="LatheGeometry",this.parameters={points:e,segments:t,phiStart:n,phiLength:i},t=Math.floor(t),i=Et(i,0,Math.PI*2);const r=[],o=[],a=[],l=[],c=[],u=1/t,h=new N,d=new se,f=new N,g=new N,v=new N;let m=0,p=0;for(let y=0;y<=e.length-1;y++)switch(y){case 0:m=e[y+1].x-e[y].x,p=e[y+1].y-e[y].y,f.x=p*1,f.y=-m,f.z=p*0,v.copy(f),f.normalize(),l.push(f.x,f.y,f.z);break;case e.length-1:l.push(v.x,v.y,v.z);break;default:m=e[y+1].x-e[y].x,p=e[y+1].y-e[y].y,f.x=p*1,f.y=-m,f.z=p*0,g.copy(f),f.x+=v.x,f.y+=v.y,f.z+=v.z,f.normalize(),l.push(f.x,f.y,f.z),v.copy(g)}for(let y=0;y<=t;y++){const _=n+y*u*i,x=Math.sin(_),A=Math.cos(_);for(let b=0;b<=e.length-1;b++){h.x=e[b].x*x,h.y=e[b].y,h.z=e[b].x*A,o.push(h.x,h.y,h.z),d.x=y/t,d.y=b/(e.length-1),a.push(d.x,d.y);const E=l[3*b+0]*x,I=l[3*b+1],w=l[3*b+0]*A;c.push(E,I,w)}}for(let y=0;y0&&_(!0),t>0&&_(!1)),this.setIndex(u),this.setAttribute("position",new Ne(h,3)),this.setAttribute("normal",new Ne(d,3)),this.setAttribute("uv",new Ne(f,2));function y(){const x=new N,A=new N;let b=0;const E=(t-e)/n;for(let I=0;I<=r;I++){const w=[],M=I/r,F=M*(t-e)+e;for(let V=0;V<=i;V++){const G=V/i,q=G*l+a,ae=Math.sin(q),Q=Math.cos(q);A.x=F*ae,A.y=-M*n+m,A.z=F*Q,h.push(A.x,A.y,A.z),x.set(ae,E,Q).normalize(),d.push(x.x,x.y,x.z),f.push(G,1-M),w.push(g++)}v.push(w)}for(let I=0;I.9&&E<.1&&(_<.2&&(o[y+0]+=1),x<.2&&(o[y+2]+=1),A<.2&&(o[y+4]+=1))}}function d(y){r.push(y.x,y.y,y.z)}function f(y,_){const x=y*3;_.x=e[x+0],_.y=e[x+1],_.z=e[x+2]}function g(){const y=new N,_=new N,x=new N,A=new N,b=new se,E=new se,I=new se;for(let w=0,M=0;w80*t){a=c=s[0],l=u=s[1];for(let g=t;gc&&(c=h),d>u&&(u=d);f=Math.max(c-a,u-l),f=f!==0?32767/f:0}return Lr(r,o,t,a,l,f,0),o}};function Up(s,e,t,n,i){let r,o;if(i===ZM(s,e,t,n)>0)for(r=e;r=e;r-=n)o=ld(r,s[r],s[r+1],o);return o&&Xa(o,o.next)&&(Dr(o),o=o.next),o}function ls(s,e){if(!s)return s;e||(e=s);let t=s,n;do if(n=!1,!t.steiner&&(Xa(t,t.next)||St(t.prev,t,t.next)===0)){if(Dr(t),t=e=t.prev,t===t.next)break;n=!0}else t=t.next;while(n||t!==e);return e}function Lr(s,e,t,n,i,r,o){if(!s)return;!o&&r&&GM(s,n,i,r);let a=s,l,c;for(;s.prev!==s.next;){if(l=s.prev,c=s.next,r?UM(s,n,i,r):DM(s)){e.push(l.i/t|0),e.push(s.i/t|0),e.push(c.i/t|0),Dr(s),s=c.next,a=c.next;continue}if(s=c,s===a){o?o===1?(s=OM(ls(s),e,t),Lr(s,e,t,n,i,r,2)):o===2&&FM(s,e,t,n,i,r):Lr(ls(s),e,t,n,i,r,1);break}}}function DM(s){const e=s.prev,t=s,n=s.next;if(St(e,t,n)>=0)return!1;const i=e.x,r=t.x,o=n.x,a=e.y,l=t.y,c=n.y,u=ir?i>o?i:o:r>o?r:o,f=a>l?a>c?a:c:l>c?l:c;let g=n.next;for(;g!==e;){if(g.x>=u&&g.x<=d&&g.y>=h&&g.y<=f&&ks(i,a,r,l,o,c,g.x,g.y)&&St(g.prev,g,g.next)>=0)return!1;g=g.next}return!0}function UM(s,e,t,n){const i=s.prev,r=s,o=s.next;if(St(i,r,o)>=0)return!1;const a=i.x,l=r.x,c=o.x,u=i.y,h=r.y,d=o.y,f=al?a>c?a:c:l>c?l:c,m=u>h?u>d?u:d:h>d?h:d,p=Dc(f,g,e,t,n),y=Dc(v,m,e,t,n);let _=s.prevZ,x=s.nextZ;for(;_&&_.z>=p&&x&&x.z<=y;){if(_.x>=f&&_.x<=v&&_.y>=g&&_.y<=m&&_!==i&&_!==o&&ks(a,u,l,h,c,d,_.x,_.y)&&St(_.prev,_,_.next)>=0||(_=_.prevZ,x.x>=f&&x.x<=v&&x.y>=g&&x.y<=m&&x!==i&&x!==o&&ks(a,u,l,h,c,d,x.x,x.y)&&St(x.prev,x,x.next)>=0))return!1;x=x.nextZ}for(;_&&_.z>=p;){if(_.x>=f&&_.x<=v&&_.y>=g&&_.y<=m&&_!==i&&_!==o&&ks(a,u,l,h,c,d,_.x,_.y)&&St(_.prev,_,_.next)>=0)return!1;_=_.prevZ}for(;x&&x.z<=y;){if(x.x>=f&&x.x<=v&&x.y>=g&&x.y<=m&&x!==i&&x!==o&&ks(a,u,l,h,c,d,x.x,x.y)&&St(x.prev,x,x.next)>=0)return!1;x=x.nextZ}return!0}function OM(s,e,t){let n=s;do{const i=n.prev,r=n.next.next;!Xa(i,r)&&Op(i,n,n.next,r)&&Nr(i,r)&&Nr(r,i)&&(e.push(i.i/t|0),e.push(n.i/t|0),e.push(r.i/t|0),Dr(n),Dr(n.next),n=s=r),n=n.next}while(n!==s);return ls(n)}function FM(s,e,t,n,i,r){let o=s;do{let a=o.next.next;for(;a!==o.prev;){if(o.i!==a.i&&XM(o,a)){let l=Fp(o,a);o=ls(o,o.next),l=ls(l,l.next),Lr(o,e,t,n,i,r,0),Lr(l,e,t,n,i,r,0);return}a=a.next}o=o.next}while(o!==s)}function kM(s,e,t,n){const i=[];let r,o,a,l,c;for(r=0,o=e.length;r=t.next.y&&t.next.y!==t.y){const d=t.x+(o-t.y)*(t.next.x-t.x)/(t.next.y-t.y);if(d<=r&&d>n&&(n=d,i=t.x=t.x&&t.x>=l&&r!==t.x&&ks(oi.x||t.x===i.x&&HM(i,t)))&&(i=t,u=h)),t=t.next;while(t!==a);return i}function HM(s,e){return St(s.prev,s,e.prev)<0&&St(e.next,s,s.next)<0}function GM(s,e,t,n){let i=s;do i.z===0&&(i.z=Dc(i.x,i.y,e,t,n)),i.prevZ=i.prev,i.nextZ=i.next,i=i.next;while(i!==s);i.prevZ.nextZ=null,i.prevZ=null,WM(i)}function WM(s){let e,t,n,i,r,o,a,l,c=1;do{for(t=s,s=null,r=null,o=0;t;){for(o++,n=t,a=0,e=0;e0||l>0&&n;)a!==0&&(l===0||!n||t.z<=n.z)?(i=t,t=t.nextZ,a--):(i=n,n=n.nextZ,l--),r?r.nextZ=i:s=i,i.prevZ=r,r=i;t=n}r.nextZ=null,c*=2}while(o>1);return s}function Dc(s,e,t,n,i){return s=(s-t)*i|0,e=(e-n)*i|0,s=(s|s<<8)&16711935,s=(s|s<<4)&252645135,s=(s|s<<2)&858993459,s=(s|s<<1)&1431655765,e=(e|e<<8)&16711935,e=(e|e<<4)&252645135,e=(e|e<<2)&858993459,e=(e|e<<1)&1431655765,s|e<<1}function $M(s){let e=s,t=s;do(e.x=(s-o)*(r-a)&&(s-o)*(n-a)>=(t-o)*(e-a)&&(t-o)*(r-a)>=(i-o)*(n-a)}function XM(s,e){return s.next.i!==e.i&&s.prev.i!==e.i&&!qM(s,e)&&(Nr(s,e)&&Nr(e,s)&&YM(s,e)&&(St(s.prev,s,e.prev)||St(s,e.prev,e))||Xa(s,e)&&St(s.prev,s,s.next)>0&&St(e.prev,e,e.next)>0)}function St(s,e,t){return(e.y-s.y)*(t.x-e.x)-(e.x-s.x)*(t.y-e.y)}function Xa(s,e){return s.x===e.x&&s.y===e.y}function Op(s,e,t,n){const i=$o(St(s,e,t)),r=$o(St(s,e,n)),o=$o(St(t,n,s)),a=$o(St(t,n,e));return!!(i!==r&&o!==a||i===0&&Wo(s,t,e)||r===0&&Wo(s,n,e)||o===0&&Wo(t,s,n)||a===0&&Wo(t,e,n))}function Wo(s,e,t){return e.x<=Math.max(s.x,t.x)&&e.x>=Math.min(s.x,t.x)&&e.y<=Math.max(s.y,t.y)&&e.y>=Math.min(s.y,t.y)}function $o(s){return s>0?1:s<0?-1:0}function qM(s,e){let t=s;do{if(t.i!==s.i&&t.next.i!==s.i&&t.i!==e.i&&t.next.i!==e.i&&Op(t,t.next,s,e))return!0;t=t.next}while(t!==s);return!1}function Nr(s,e){return St(s.prev,s,s.next)<0?St(s,e,s.next)>=0&&St(s,s.prev,e)>=0:St(s,e,s.prev)<0||St(s,s.next,e)<0}function YM(s,e){let t=s,n=!1;const i=(s.x+e.x)/2,r=(s.y+e.y)/2;do t.y>r!=t.next.y>r&&t.next.y!==t.y&&i<(t.next.x-t.x)*(r-t.y)/(t.next.y-t.y)+t.x&&(n=!n),t=t.next;while(t!==s);return n}function Fp(s,e){const t=new Uc(s.i,s.x,s.y),n=new Uc(e.i,e.x,e.y),i=s.next,r=e.prev;return s.next=e,e.prev=s,t.next=i,i.prev=t,n.next=t,t.prev=n,r.next=n,n.prev=r,n}function ld(s,e,t,n){const i=new Uc(s,e,t);return n?(i.next=n.next,i.prev=n,n.next.prev=i,n.next=i):(i.prev=i,i.next=i),i}function Dr(s){s.next.prev=s.prev,s.prev.next=s.next,s.prevZ&&(s.prevZ.nextZ=s.nextZ),s.nextZ&&(s.nextZ.prevZ=s.prevZ)}function Uc(s,e,t){this.i=s,this.x=e,this.y=t,this.prev=null,this.next=null,this.z=0,this.prevZ=null,this.nextZ=null,this.steiner=!1}function ZM(s,e,t,n){let i=0;for(let r=e,o=t-n;r2&&s[e-1].equals(s[0])&&s.pop()}function ud(s,e){for(let t=0;tNumber.EPSILON){const ce=Math.sqrt(ee),ve=Math.sqrt(P*P+S*S),Ve=K.x-O/ce,Ee=K.y+k/ce,Te=H.x-S/ve,Qe=H.y+P/ve,xe=((Te-Ve)*S-(Qe-Ee)*P)/(k*S-O*P);$=Ve+k*xe-X.x,te=Ee+O*xe-X.y;const Ue=$*$+te*te;if(Ue<=2)return new se($,te);le=Math.sqrt(Ue/2)}else{let ce=!1;k>Number.EPSILON?P>Number.EPSILON&&(ce=!0):k<-Number.EPSILON?P<-Number.EPSILON&&(ce=!0):Math.sign(O)===Math.sign(S)&&(ce=!0),ce?($=-O,te=k,le=Math.sqrt(ee)):($=k,te=O,le=Math.sqrt(ee/2))}return new se($/le,te/le)}const Me=[];for(let X=0,K=q.length,H=K-1,$=X+1;X=0;X--){const K=X/m,H=f*Math.cos(K*Math.PI/2),$=g*Math.sin(K*Math.PI/2)+v;for(let te=0,le=q.length;te=0;){const $=H;let te=H-1;te<0&&(te=X.length-1);for(let le=0,k=u+m*2;le0)&&f.push(_,x,b),(p!==n-1||l0!=e>0&&this.version++,this._anisotropy=e}get clearcoat(){return this._clearcoat}set clearcoat(e){this._clearcoat>0!=e>0&&this.version++,this._clearcoat=e}get iridescence(){return this._iridescence}set iridescence(e){this._iridescence>0!=e>0&&this.version++,this._iridescence=e}get dispersion(){return this._dispersion}set dispersion(e){this._dispersion>0!=e>0&&this.version++,this._dispersion=e}get sheen(){return this._sheen}set sheen(e){this._sheen>0!=e>0&&this.version++,this._sheen=e}get transmission(){return this._transmission}set transmission(e){this._transmission>0!=e>0&&this.version++,this._transmission=e}copy(e){return super.copy(e),this.defines={STANDARD:"",PHYSICAL:""},this.anisotropy=e.anisotropy,this.anisotropyRotation=e.anisotropyRotation,this.anisotropyMap=e.anisotropyMap,this.clearcoat=e.clearcoat,this.clearcoatMap=e.clearcoatMap,this.clearcoatRoughness=e.clearcoatRoughness,this.clearcoatRoughnessMap=e.clearcoatRoughnessMap,this.clearcoatNormalMap=e.clearcoatNormalMap,this.clearcoatNormalScale.copy(e.clearcoatNormalScale),this.dispersion=e.dispersion,this.ior=e.ior,this.iridescence=e.iridescence,this.iridescenceMap=e.iridescenceMap,this.iridescenceIOR=e.iridescenceIOR,this.iridescenceThicknessRange=[...e.iridescenceThicknessRange],this.iridescenceThicknessMap=e.iridescenceThicknessMap,this.sheen=e.sheen,this.sheenColor.copy(e.sheenColor),this.sheenColorMap=e.sheenColorMap,this.sheenRoughness=e.sheenRoughness,this.sheenRoughnessMap=e.sheenRoughnessMap,this.transmission=e.transmission,this.transmissionMap=e.transmissionMap,this.thickness=e.thickness,this.thicknessMap=e.thicknessMap,this.attenuationDistance=e.attenuationDistance,this.attenuationColor.copy(e.attenuationColor),this.specularIntensity=e.specularIntensity,this.specularIntensityMap=e.specularIntensityMap,this.specularColor.copy(e.specularColor),this.specularColorMap=e.specularColorMap,this}}class Hp extends Kt{constructor(e){super(),this.isMeshPhongMaterial=!0,this.type="MeshPhongMaterial",this.color=new Pe(16777215),this.specular=new Pe(1118481),this.shininess=30,this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Pe(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=Ii,this.normalScale=new se(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new _n,this.combine=Gr,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.specular.copy(e.specular),this.shininess=e.shininess,this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.envMapRotation.copy(e.envMapRotation),this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.flatShading=e.flatShading,this.fog=e.fog,this}}class Gp extends Kt{constructor(e){super(),this.isMeshToonMaterial=!0,this.defines={TOON:""},this.type="MeshToonMaterial",this.color=new Pe(16777215),this.map=null,this.gradientMap=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Pe(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=Ii,this.normalScale=new se(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.gradientMap=e.gradientMap,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.alphaMap=e.alphaMap,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.fog=e.fog,this}}class Wp extends Kt{constructor(e){super(),this.isMeshNormalMaterial=!0,this.type="MeshNormalMaterial",this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=Ii,this.normalScale=new se(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.flatShading=!1,this.setValues(e)}copy(e){return super.copy(e),this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.flatShading=e.flatShading,this}}class $p extends Kt{constructor(e){super(),this.isMeshLambertMaterial=!0,this.type="MeshLambertMaterial",this.color=new Pe(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Pe(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=Ii,this.normalScale=new se(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new _n,this.combine=Gr,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.envMapRotation.copy(e.envMapRotation),this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.flatShading=e.flatShading,this.fog=e.fog,this}}class Xp extends Kt{constructor(e){super(),this.isMeshMatcapMaterial=!0,this.defines={MATCAP:""},this.type="MeshMatcapMaterial",this.color=new Pe(16777215),this.matcap=null,this.map=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=Ii,this.normalScale=new se(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.flatShading=!1,this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.defines={MATCAP:""},this.color.copy(e.color),this.matcap=e.matcap,this.map=e.map,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.alphaMap=e.alphaMap,this.flatShading=e.flatShading,this.fog=e.fog,this}}class qp extends rn{constructor(e){super(),this.isLineDashedMaterial=!0,this.type="LineDashedMaterial",this.scale=1,this.dashSize=3,this.gapSize=1,this.setValues(e)}copy(e){return super.copy(e),this.scale=e.scale,this.dashSize=e.dashSize,this.gapSize=e.gapSize,this}}function Qi(s,e,t){return!s||!t&&s.constructor===e?s:typeof e.BYTES_PER_ELEMENT=="number"?new e(s):Array.prototype.slice.call(s)}function Yp(s){return ArrayBuffer.isView(s)&&!(s instanceof DataView)}function Zp(s){function e(i,r){return s[i]-s[r]}const t=s.length,n=new Array(t);for(let i=0;i!==t;++i)n[i]=i;return n.sort(e),n}function Oc(s,e,t){const n=s.length,i=new s.constructor(n);for(let r=0,o=0;o!==n;++r){const a=t[r]*e;for(let l=0;l!==e;++l)i[o++]=s[a+l]}return i}function Cu(s,e,t,n){let i=1,r=s[0];for(;r!==void 0&&r[n]===void 0;)r=s[i++];if(r===void 0)return;let o=r[n];if(o!==void 0)if(Array.isArray(o))do o=r[n],o!==void 0&&(e.push(r.time),t.push.apply(t,o)),r=s[i++];while(r!==void 0);else if(o.toArray!==void 0)do o=r[n],o!==void 0&&(e.push(r.time),o.toArray(t,t.length)),r=s[i++];while(r!==void 0);else do o=r[n],o!==void 0&&(e.push(r.time),t.push(o)),r=s[i++];while(r!==void 0)}function QM(s,e,t,n,i=30){const r=s.clone();r.name=e;const o=[];for(let l=0;l=n)){h.push(c.times[f]);for(let v=0;vr.tracks[l].times[0]&&(a=r.tracks[l].times[0]);for(let l=0;l=a.times[g]){const p=g*h+u,y=p+h-u;v=a.values.slice(p,y)}else{const p=a.createInterpolant(),y=u,_=h-u;p.evaluate(r),v=p.resultBuffer.slice(y,_)}l==="quaternion"&&new hn().fromArray(v).normalize().conjugate().toArray(v);const m=c.times.length;for(let p=0;p=r)){const a=t[1];e=r)break t}o=n,n=0;break n}break e}for(;n>>1;et;)--o;if(++o,r!==0||o!==i){r>=o&&(o=Math.max(o,1),r=o-1);const a=this.getValueSize();this.times=n.slice(r,o),this.values=this.values.slice(r*a,o*a)}return this}validate(){let e=!0;const t=this.getValueSize();t-Math.floor(t)!==0&&(console.error("THREE.KeyframeTrack: Invalid value size in track.",this),e=!1);const n=this.times,i=this.values,r=n.length;r===0&&(console.error("THREE.KeyframeTrack: Track is empty.",this),e=!1);let o=null;for(let a=0;a!==r;a++){const l=n[a];if(typeof l=="number"&&isNaN(l)){console.error("THREE.KeyframeTrack: Time is not a valid number.",this,a,l),e=!1;break}if(o!==null&&o>l){console.error("THREE.KeyframeTrack: Out of order keys.",this,a,l,o),e=!1;break}o=l}if(i!==void 0&&Yp(i))for(let a=0,l=i.length;a!==l;++a){const c=i[a];if(isNaN(c)){console.error("THREE.KeyframeTrack: Value is not a valid number.",this,a,c),e=!1;break}}return e}optimize(){const e=this.times.slice(),t=this.values.slice(),n=this.getValueSize(),i=this.getInterpolation()===ca,r=e.length-1;let o=1;for(let a=1;a0){e[o]=e[r];for(let a=r*n,l=o*n,c=0;c!==n;++c)t[l+c]=t[a+c];++o}return o!==e.length?(this.times=e.slice(0,o),this.values=t.slice(0,o*n)):(this.times=e,this.values=t),this}clone(){const e=this.times.slice(),t=this.values.slice(),n=this.constructor,i=new n(this.name,e,t);return i.createInterpolant=this.createInterpolant,i}}Un.prototype.TimeBufferType=Float32Array;Un.prototype.ValueBufferType=Float32Array;Un.prototype.DefaultInterpolation=ya;class us extends Un{constructor(e,t,n){super(e,t,n)}}us.prototype.ValueTypeName="bool";us.prototype.ValueBufferType=Array;us.prototype.DefaultInterpolation=wr;us.prototype.InterpolantFactoryMethodLinear=void 0;us.prototype.InterpolantFactoryMethodSmooth=void 0;class Ru extends Un{}Ru.prototype.ValueTypeName="color";class Ur extends Un{}Ur.prototype.ValueTypeName="number";class jp extends jr{constructor(e,t,n,i){super(e,t,n,i)}interpolate_(e,t,n,i){const r=this.resultBuffer,o=this.sampleValues,a=this.valueSize,l=(n-t)/(i-t);let c=e*a;for(let u=c+a;c!==u;c+=4)hn.slerpFlat(r,0,o,c-a,o,c,l);return r}}class Qr extends Un{InterpolantFactoryMethodLinear(e){return new jp(this.times,this.values,this.getValueSize(),e)}}Qr.prototype.ValueTypeName="quaternion";Qr.prototype.InterpolantFactoryMethodSmooth=void 0;class hs extends Un{constructor(e,t,n){super(e,t,n)}}hs.prototype.ValueTypeName="string";hs.prototype.ValueBufferType=Array;hs.prototype.DefaultInterpolation=wr;hs.prototype.InterpolantFactoryMethodLinear=void 0;hs.prototype.InterpolantFactoryMethodSmooth=void 0;class Or extends Un{}Or.prototype.ValueTypeName="vector";class Fr{constructor(e="",t=-1,n=[],i=Pa){this.name=e,this.tracks=n,this.duration=t,this.blendMode=i,this.uuid=vn(),this.duration<0&&this.resetDuration()}static parse(e){const t=[],n=e.tracks,i=1/(e.fps||1);for(let o=0,a=n.length;o!==a;++o)t.push(ib(n[o]).scale(i));const r=new this(e.name,e.duration,t,e.blendMode);return r.uuid=e.uuid,r}static toJSON(e){const t=[],n=e.tracks,i={name:e.name,duration:e.duration,tracks:t,uuid:e.uuid,blendMode:e.blendMode};for(let r=0,o=n.length;r!==o;++r)t.push(Un.toJSON(n[r]));return i}static CreateFromMorphTargetSequence(e,t,n,i){const r=t.length,o=[];for(let a=0;a1){const h=u[1];let d=i[h];d||(i[h]=d=[]),d.push(c)}}const o=[];for(const a in i)o.push(this.CreateFromMorphTargetSequence(a,i[a],t,n));return o}static parseAnimation(e,t){if(!e)return console.error("THREE.AnimationClip: No animation in JSONLoader data."),null;const n=function(h,d,f,g,v){if(f.length!==0){const m=[],p=[];Cu(f,m,p,g),m.length!==0&&v.push(new h(d,m,p))}},i=[],r=e.name||"default",o=e.fps||30,a=e.blendMode;let l=e.length||-1;const c=e.hierarchy||[];for(let h=0;h{t&&t(r),this.manager.itemEnd(e)},0),r;if(ei[e]!==void 0){ei[e].push({onLoad:t,onProgress:n,onError:i});return}ei[e]=[],ei[e].push({onLoad:t,onProgress:n,onError:i});const o=new Request(e,{headers:new Headers(this.requestHeader),credentials:this.withCredentials?"include":"same-origin"}),a=this.mimeType,l=this.responseType;fetch(o).then(c=>{if(c.status===200||c.status===0){if(c.status===0&&console.warn("THREE.FileLoader: HTTP Status 0 received."),typeof ReadableStream>"u"||c.body===void 0||c.body.getReader===void 0)return c;const u=ei[e],h=c.body.getReader(),d=c.headers.get("X-File-Size")||c.headers.get("Content-Length"),f=d?parseInt(d):0,g=f!==0;let v=0;const m=new ReadableStream({start(p){y();function y(){h.read().then(({done:_,value:x})=>{if(_)p.close();else{v+=x.byteLength;const A=new ProgressEvent("progress",{lengthComputable:g,loaded:v,total:f});for(let b=0,E=u.length;b{p.error(_)})}}});return new Response(m)}else throw new sb(`fetch for "${c.url}" responded with ${c.status}: ${c.statusText}`,c)}).then(c=>{switch(l){case"arraybuffer":return c.arrayBuffer();case"blob":return c.blob();case"document":return c.text().then(u=>new DOMParser().parseFromString(u,a));case"json":return c.json();default:if(a===void 0)return c.text();{const h=/charset="?([^;"\s]*)"?/i.exec(a),d=h&&h[1]?h[1].toLowerCase():void 0,f=new TextDecoder(d);return c.arrayBuffer().then(g=>f.decode(g))}}}).then(c=>{ii.add(e,c);const u=ei[e];delete ei[e];for(let h=0,d=u.length;h{const u=ei[e];if(u===void 0)throw this.manager.itemError(e),c;delete ei[e];for(let h=0,d=u.length;h{this.manager.itemEnd(e)}),this.manager.itemStart(e)}setResponseType(e){return this.responseType=e,this}setMimeType(e){return this.mimeType=e,this}}class rb extends on{constructor(e){super(e)}load(e,t,n,i){const r=this,o=new $n(this.manager);o.setPath(this.path),o.setRequestHeader(this.requestHeader),o.setWithCredentials(this.withCredentials),o.load(e,function(a){try{t(r.parse(JSON.parse(a)))}catch(l){i?i(l):console.error(l),r.manager.itemError(e)}},n,i)}parse(e){const t=[];for(let n=0;n0:i.vertexColors=e.vertexColors),e.uniforms!==void 0)for(const r in e.uniforms){const o=e.uniforms[r];switch(i.uniforms[r]={},o.type){case"t":i.uniforms[r].value=n(o.value);break;case"c":i.uniforms[r].value=new Pe().setHex(o.value);break;case"v2":i.uniforms[r].value=new se().fromArray(o.value);break;case"v3":i.uniforms[r].value=new N().fromArray(o.value);break;case"v4":i.uniforms[r].value=new gt().fromArray(o.value);break;case"m3":i.uniforms[r].value=new Ze().fromArray(o.value);break;case"m4":i.uniforms[r].value=new qe().fromArray(o.value);break;default:i.uniforms[r].value=o.value}}if(e.defines!==void 0&&(i.defines=e.defines),e.vertexShader!==void 0&&(i.vertexShader=e.vertexShader),e.fragmentShader!==void 0&&(i.fragmentShader=e.fragmentShader),e.glslVersion!==void 0&&(i.glslVersion=e.glslVersion),e.extensions!==void 0)for(const r in e.extensions)i.extensions[r]=e.extensions[r];if(e.lights!==void 0&&(i.lights=e.lights),e.clipping!==void 0&&(i.clipping=e.clipping),e.size!==void 0&&(i.size=e.size),e.sizeAttenuation!==void 0&&(i.sizeAttenuation=e.sizeAttenuation),e.map!==void 0&&(i.map=n(e.map)),e.matcap!==void 0&&(i.matcap=n(e.matcap)),e.alphaMap!==void 0&&(i.alphaMap=n(e.alphaMap)),e.bumpMap!==void 0&&(i.bumpMap=n(e.bumpMap)),e.bumpScale!==void 0&&(i.bumpScale=e.bumpScale),e.normalMap!==void 0&&(i.normalMap=n(e.normalMap)),e.normalMapType!==void 0&&(i.normalMapType=e.normalMapType),e.normalScale!==void 0){let r=e.normalScale;Array.isArray(r)===!1&&(r=[r,r]),i.normalScale=new se().fromArray(r)}return e.displacementMap!==void 0&&(i.displacementMap=n(e.displacementMap)),e.displacementScale!==void 0&&(i.displacementScale=e.displacementScale),e.displacementBias!==void 0&&(i.displacementBias=e.displacementBias),e.roughnessMap!==void 0&&(i.roughnessMap=n(e.roughnessMap)),e.metalnessMap!==void 0&&(i.metalnessMap=n(e.metalnessMap)),e.emissiveMap!==void 0&&(i.emissiveMap=n(e.emissiveMap)),e.emissiveIntensity!==void 0&&(i.emissiveIntensity=e.emissiveIntensity),e.specularMap!==void 0&&(i.specularMap=n(e.specularMap)),e.specularIntensityMap!==void 0&&(i.specularIntensityMap=n(e.specularIntensityMap)),e.specularColorMap!==void 0&&(i.specularColorMap=n(e.specularColorMap)),e.envMap!==void 0&&(i.envMap=n(e.envMap)),e.envMapRotation!==void 0&&i.envMapRotation.fromArray(e.envMapRotation),e.envMapIntensity!==void 0&&(i.envMapIntensity=e.envMapIntensity),e.reflectivity!==void 0&&(i.reflectivity=e.reflectivity),e.refractionRatio!==void 0&&(i.refractionRatio=e.refractionRatio),e.lightMap!==void 0&&(i.lightMap=n(e.lightMap)),e.lightMapIntensity!==void 0&&(i.lightMapIntensity=e.lightMapIntensity),e.aoMap!==void 0&&(i.aoMap=n(e.aoMap)),e.aoMapIntensity!==void 0&&(i.aoMapIntensity=e.aoMapIntensity),e.gradientMap!==void 0&&(i.gradientMap=n(e.gradientMap)),e.clearcoatMap!==void 0&&(i.clearcoatMap=n(e.clearcoatMap)),e.clearcoatRoughnessMap!==void 0&&(i.clearcoatRoughnessMap=n(e.clearcoatRoughnessMap)),e.clearcoatNormalMap!==void 0&&(i.clearcoatNormalMap=n(e.clearcoatNormalMap)),e.clearcoatNormalScale!==void 0&&(i.clearcoatNormalScale=new se().fromArray(e.clearcoatNormalScale)),e.iridescenceMap!==void 0&&(i.iridescenceMap=n(e.iridescenceMap)),e.iridescenceThicknessMap!==void 0&&(i.iridescenceThicknessMap=n(e.iridescenceThicknessMap)),e.transmissionMap!==void 0&&(i.transmissionMap=n(e.transmissionMap)),e.thicknessMap!==void 0&&(i.thicknessMap=n(e.thicknessMap)),e.anisotropyMap!==void 0&&(i.anisotropyMap=n(e.anisotropyMap)),e.sheenColorMap!==void 0&&(i.sheenColorMap=n(e.sheenColorMap)),e.sheenRoughnessMap!==void 0&&(i.sheenRoughnessMap=n(e.sheenRoughnessMap)),i}setTextures(e){return this.textures=e,this}static createMaterialFromType(e){const t={ShadowMaterial:Bp,SpriteMaterial:_u,RawShaderMaterial:zp,ShaderMaterial:Ln,PointsMaterial:xu,MeshPhysicalMaterial:Vp,MeshStandardMaterial:Eu,MeshPhongMaterial:Hp,MeshToonMaterial:Gp,MeshNormalMaterial:Wp,MeshLambertMaterial:$p,MeshDepthMaterial:gu,MeshDistanceMaterial:vu,MeshBasicMaterial:hi,MeshMatcapMaterial:Xp,LineDashedMaterial:qp,LineBasicMaterial:rn,Material:Kt};return new t[e]}}class Fc{static decodeText(e){if(console.warn("THREE.LoaderUtils: decodeText() has been deprecated with r165 and will be removed with r175. Use TextDecoder instead."),typeof TextDecoder<"u")return new TextDecoder().decode(e);let t="";for(let n=0,i=e.length;n0){const l=new Iu(t);r=new kr(l),r.setCrossOrigin(this.crossOrigin);for(let c=0,u=e.length;c0){i=new kr(this.manager),i.setCrossOrigin(this.crossOrigin);for(let o=0,a=e.length;o{const m=new sn;m.min.fromArray(v.boxMin),m.max.fromArray(v.boxMax);const p=new Zt;return p.radius=v.sphereRadius,p.center.fromArray(v.sphereCenter),{boxInitialized:v.boxInitialized,box:m,sphereInitialized:v.sphereInitialized,sphere:p}}),o._maxGeometryCount=e.maxGeometryCount,o._maxVertexCount=e.maxVertexCount,o._maxIndexCount=e.maxIndexCount,o._geometryInitialized=e.geometryInitialized,o._geometryCount=e.geometryCount,o._matricesTexture=c(e.matricesTexture.uuid),e.colorsTexture!==void 0&&(o._colorsTexture=c(e.colorsTexture.uuid));break;case"LOD":o=new Sp;break;case"Line":o=new Pi(a(e.geometry),l(e.material));break;case"LineLoop":o=new Ep(a(e.geometry),l(e.material));break;case"LineSegments":o=new qn(a(e.geometry),l(e.material));break;case"PointCloud":case"Points":o=new Cp(a(e.geometry),l(e.material));break;case"Sprite":o=new bp(l(e.material));break;case"Group":o=new Fs;break;case"Bone":o=new yu;break;default:o=new ct}if(o.uuid=e.uuid,e.name!==void 0&&(o.name=e.name),e.matrix!==void 0?(o.matrix.fromArray(e.matrix),e.matrixAutoUpdate!==void 0&&(o.matrixAutoUpdate=e.matrixAutoUpdate),o.matrixAutoUpdate&&o.matrix.decompose(o.position,o.quaternion,o.scale)):(e.position!==void 0&&o.position.fromArray(e.position),e.rotation!==void 0&&o.rotation.fromArray(e.rotation),e.quaternion!==void 0&&o.quaternion.fromArray(e.quaternion),e.scale!==void 0&&o.scale.fromArray(e.scale)),e.up!==void 0&&o.up.fromArray(e.up),e.castShadow!==void 0&&(o.castShadow=e.castShadow),e.receiveShadow!==void 0&&(o.receiveShadow=e.receiveShadow),e.shadow&&(e.shadow.bias!==void 0&&(o.shadow.bias=e.shadow.bias),e.shadow.normalBias!==void 0&&(o.shadow.normalBias=e.shadow.normalBias),e.shadow.radius!==void 0&&(o.shadow.radius=e.shadow.radius),e.shadow.mapSize!==void 0&&o.shadow.mapSize.fromArray(e.shadow.mapSize),e.shadow.camera!==void 0&&(o.shadow.camera=this.parseObject(e.shadow.camera))),e.visible!==void 0&&(o.visible=e.visible),e.frustumCulled!==void 0&&(o.frustumCulled=e.frustumCulled),e.renderOrder!==void 0&&(o.renderOrder=e.renderOrder),e.userData!==void 0&&(o.userData=e.userData),e.layers!==void 0&&(o.layers.mask=e.layers),e.children!==void 0){const d=e.children;for(let f=0;f"u"&&console.warn("THREE.ImageBitmapLoader: createImageBitmap() not supported."),typeof fetch>"u"&&console.warn("THREE.ImageBitmapLoader: fetch() not supported."),this.options={premultiplyAlpha:"none"}}setOptions(e){return this.options=e,this}load(e,t,n,i){e===void 0&&(e=""),this.path!==void 0&&(e=this.path+e),e=this.manager.resolveURL(e);const r=this,o=ii.get(e);if(o!==void 0){if(r.manager.itemStart(e),o.then){o.then(c=>{t&&t(c),r.manager.itemEnd(e)}).catch(c=>{i&&i(c)});return}return setTimeout(function(){t&&t(o),r.manager.itemEnd(e)},0),o}const a={};a.credentials=this.crossOrigin==="anonymous"?"same-origin":"include",a.headers=this.requestHeader;const l=fetch(e,a).then(function(c){return c.blob()}).then(function(c){return createImageBitmap(c,Object.assign(r.options,{colorSpaceConversion:"none"}))}).then(function(c){return ii.add(e,c),t&&t(c),r.manager.itemEnd(e),c}).catch(function(c){i&&i(c),ii.remove(e),r.manager.itemError(e),r.manager.itemEnd(e)});ii.add(e,l),r.manager.itemStart(e)}}let Xo;class Nu{static getContext(){return Xo===void 0&&(Xo=new(window.AudioContext||window.webkitAudioContext)),Xo}static setContext(e){Xo=e}}class gb extends on{constructor(e){super(e)}load(e,t,n,i){const r=this,o=new $n(this.manager);o.setResponseType("arraybuffer"),o.setPath(this.path),o.setRequestHeader(this.requestHeader),o.setWithCredentials(this.withCredentials),o.load(e,function(l){try{const c=l.slice(0);Nu.getContext().decodeAudioData(c,function(h){t(h)}).catch(a)}catch(c){a(c)}},n,i);function a(l){i?i(l):console.error(l),r.manager.itemError(e)}}}const _d=new qe,yd=new qe,Gi=new qe;class vb{constructor(){this.type="StereoCamera",this.aspect=1,this.eyeSep=.064,this.cameraL=new Ut,this.cameraL.layers.enable(1),this.cameraL.matrixAutoUpdate=!1,this.cameraR=new Ut,this.cameraR.layers.enable(2),this.cameraR.matrixAutoUpdate=!1,this._cache={focus:null,fov:null,aspect:null,near:null,far:null,zoom:null,eyeSep:null}}update(e){const t=this._cache;if(t.focus!==e.focus||t.fov!==e.fov||t.aspect!==e.aspect*this.aspect||t.near!==e.near||t.far!==e.far||t.zoom!==e.zoom||t.eyeSep!==this.eyeSep){t.focus=e.focus,t.fov=e.fov,t.aspect=e.aspect*this.aspect,t.near=e.near,t.far=e.far,t.zoom=e.zoom,t.eyeSep=this.eyeSep,Gi.copy(e.projectionMatrix);const i=t.eyeSep/2,r=i*t.near/t.focus,o=t.near*Math.tan(ns*t.fov*.5)/t.zoom;let a,l;yd.elements[12]=-i,_d.elements[12]=i,a=-o*t.aspect+r,l=o*t.aspect+r,Gi.elements[0]=2*t.near/(l-a),Gi.elements[8]=(l+a)/(l-a),this.cameraL.projectionMatrix.copy(Gi),a=-o*t.aspect-r,l=o*t.aspect-r,Gi.elements[0]=2*t.near/(l-a),Gi.elements[8]=(l+a)/(l-a),this.cameraR.projectionMatrix.copy(Gi)}this.cameraL.matrixWorld.copy(e.matrixWorld).multiply(yd),this.cameraR.matrixWorld.copy(e.matrixWorld).multiply(_d)}}class nl{constructor(e=!0){this.autoStart=e,this.startTime=0,this.oldTime=0,this.elapsedTime=0,this.running=!1}start(){this.startTime=xd(),this.oldTime=this.startTime,this.elapsedTime=0,this.running=!0}stop(){this.getElapsedTime(),this.running=!1,this.autoStart=!1}getElapsedTime(){return this.getDelta(),this.elapsedTime}getDelta(){let e=0;if(this.autoStart&&!this.running)return this.start(),0;if(this.running){const t=xd();e=(t-this.oldTime)/1e3,this.oldTime=t,this.elapsedTime+=e}return e}}function xd(){return(typeof performance>"u"?Date:performance).now()}const Wi=new N,Md=new hn,_b=new N,$i=new N;class yb extends ct{constructor(){super(),this.type="AudioListener",this.context=Nu.getContext(),this.gain=this.context.createGain(),this.gain.connect(this.context.destination),this.filter=null,this.timeDelta=0,this._clock=new nl}getInput(){return this.gain}removeFilter(){return this.filter!==null&&(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination),this.gain.connect(this.context.destination),this.filter=null),this}getFilter(){return this.filter}setFilter(e){return this.filter!==null?(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination)):this.gain.disconnect(this.context.destination),this.filter=e,this.gain.connect(this.filter),this.filter.connect(this.context.destination),this}getMasterVolume(){return this.gain.gain.value}setMasterVolume(e){return this.gain.gain.setTargetAtTime(e,this.context.currentTime,.01),this}updateMatrixWorld(e){super.updateMatrixWorld(e);const t=this.context.listener,n=this.up;if(this.timeDelta=this._clock.getDelta(),this.matrixWorld.decompose(Wi,Md,_b),$i.set(0,0,-1).applyQuaternion(Md),t.positionX){const i=this.context.currentTime+this.timeDelta;t.positionX.linearRampToValueAtTime(Wi.x,i),t.positionY.linearRampToValueAtTime(Wi.y,i),t.positionZ.linearRampToValueAtTime(Wi.z,i),t.forwardX.linearRampToValueAtTime($i.x,i),t.forwardY.linearRampToValueAtTime($i.y,i),t.forwardZ.linearRampToValueAtTime($i.z,i),t.upX.linearRampToValueAtTime(n.x,i),t.upY.linearRampToValueAtTime(n.y,i),t.upZ.linearRampToValueAtTime(n.z,i)}else t.setPosition(Wi.x,Wi.y,Wi.z),t.setOrientation($i.x,$i.y,$i.z,n.x,n.y,n.z)}}class um extends ct{constructor(e){super(),this.type="Audio",this.listener=e,this.context=e.context,this.gain=this.context.createGain(),this.gain.connect(e.getInput()),this.autoplay=!1,this.buffer=null,this.detune=0,this.loop=!1,this.loopStart=0,this.loopEnd=0,this.offset=0,this.duration=void 0,this.playbackRate=1,this.isPlaying=!1,this.hasPlaybackControl=!0,this.source=null,this.sourceType="empty",this._startedAt=0,this._progress=0,this._connected=!1,this.filters=[]}getOutput(){return this.gain}setNodeSource(e){return this.hasPlaybackControl=!1,this.sourceType="audioNode",this.source=e,this.connect(),this}setMediaElementSource(e){return this.hasPlaybackControl=!1,this.sourceType="mediaNode",this.source=this.context.createMediaElementSource(e),this.connect(),this}setMediaStreamSource(e){return this.hasPlaybackControl=!1,this.sourceType="mediaStreamNode",this.source=this.context.createMediaStreamSource(e),this.connect(),this}setBuffer(e){return this.buffer=e,this.sourceType="buffer",this.autoplay&&this.play(),this}play(e=0){if(this.isPlaying===!0){console.warn("THREE.Audio: Audio is already playing.");return}if(this.hasPlaybackControl===!1){console.warn("THREE.Audio: this Audio has no playback control.");return}this._startedAt=this.context.currentTime+e;const t=this.context.createBufferSource();return t.buffer=this.buffer,t.loop=this.loop,t.loopStart=this.loopStart,t.loopEnd=this.loopEnd,t.onended=this.onEnded.bind(this),t.start(this._startedAt,this._progress+this.offset,this.duration),this.isPlaying=!0,this.source=t,this.setDetune(this.detune),this.setPlaybackRate(this.playbackRate),this.connect()}pause(){if(this.hasPlaybackControl===!1){console.warn("THREE.Audio: this Audio has no playback control.");return}return this.isPlaying===!0&&(this._progress+=Math.max(this.context.currentTime-this._startedAt,0)*this.playbackRate,this.loop===!0&&(this._progress=this._progress%(this.duration||this.buffer.duration)),this.source.stop(),this.source.onended=null,this.isPlaying=!1),this}stop(){if(this.hasPlaybackControl===!1){console.warn("THREE.Audio: this Audio has no playback control.");return}return this._progress=0,this.source!==null&&(this.source.stop(),this.source.onended=null),this.isPlaying=!1,this}connect(){if(this.filters.length>0){this.source.connect(this.filters[0]);for(let e=1,t=this.filters.length;e0){this.source.disconnect(this.filters[0]);for(let e=1,t=this.filters.length;e0&&this._mixBufferRegionAdditive(n,i,this._addIndex*t,1,t);for(let l=t,c=t+t;l!==c;++l)if(n[l]!==n[l+t]){a.setValue(n,i);break}}saveOriginalState(){const e=this.binding,t=this.buffer,n=this.valueSize,i=n*this._origIndex;e.getValue(t,i);for(let r=n,o=i;r!==o;++r)t[r]=t[i+r%n];this._setIdentity(),this.cumulativeWeight=0,this.cumulativeWeightAdditive=0}restoreOriginalState(){const e=this.valueSize*3;this.binding.setValue(this.buffer,e)}_setAdditiveIdentityNumeric(){const e=this._addIndex*this.valueSize,t=e+this.valueSize;for(let n=e;n=.5)for(let o=0;o!==r;++o)e[t+o]=e[n+o]}_slerp(e,t,n,i){hn.slerpFlat(e,t,e,t,e,n,i)}_slerpAdditive(e,t,n,i,r){const o=this._workIndex*r;hn.multiplyQuaternionsFlat(e,o,e,t,e,n),hn.slerpFlat(e,t,e,t,e,o,i)}_lerp(e,t,n,i,r){const o=1-i;for(let a=0;a!==r;++a){const l=t+a;e[l]=e[l]*o+e[n+a]*i}}_lerpAdditive(e,t,n,i,r){for(let o=0;o!==r;++o){const a=t+o;e[a]=e[a]+e[n+o]*i}}}const Du="\\[\\]\\.:\\/",Sb=new RegExp("["+Du+"]","g"),Uu="[^"+Du+"]",wb="[^"+Du.replace("\\.","")+"]",Ab=/((?:WC+[\/:])*)/.source.replace("WC",Uu),Tb=/(WCOD+)?/.source.replace("WCOD",wb),Eb=/(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC",Uu),Cb=/\.(WC+)(?:\[(.+)\])?/.source.replace("WC",Uu),Pb=new RegExp("^"+Ab+Tb+Eb+Cb+"$"),Rb=["material","materials","bones","map"];class Ib{constructor(e,t,n){const i=n||lt.parseTrackName(t);this._targetGroup=e,this._bindings=e.subscribe_(t,i)}getValue(e,t){this.bind();const n=this._targetGroup.nCachedObjects_,i=this._bindings[n];i!==void 0&&i.getValue(e,t)}setValue(e,t){const n=this._bindings;for(let i=this._targetGroup.nCachedObjects_,r=n.length;i!==r;++i)n[i].setValue(e,t)}bind(){const e=this._bindings;for(let t=this._targetGroup.nCachedObjects_,n=e.length;t!==n;++t)e[t].bind()}unbind(){const e=this._bindings;for(let t=this._targetGroup.nCachedObjects_,n=e.length;t!==n;++t)e[t].unbind()}}class lt{constructor(e,t,n){this.path=t,this.parsedPath=n||lt.parseTrackName(t),this.node=lt.findNode(e,this.parsedPath.nodeName),this.rootNode=e,this.getValue=this._getValue_unbound,this.setValue=this._setValue_unbound}static create(e,t,n){return e&&e.isAnimationObjectGroup?new lt.Composite(e,t,n):new lt(e,t,n)}static sanitizeNodeName(e){return e.replace(/\s/g,"_").replace(Sb,"")}static parseTrackName(e){const t=Pb.exec(e);if(t===null)throw new Error("PropertyBinding: Cannot parse trackName: "+e);const n={nodeName:t[2],objectName:t[3],objectIndex:t[4],propertyName:t[5],propertyIndex:t[6]},i=n.nodeName&&n.nodeName.lastIndexOf(".");if(i!==void 0&&i!==-1){const r=n.nodeName.substring(i+1);Rb.indexOf(r)!==-1&&(n.nodeName=n.nodeName.substring(0,i),n.objectName=r)}if(n.propertyName===null||n.propertyName.length===0)throw new Error("PropertyBinding: can not parse propertyName from trackName: "+e);return n}static findNode(e,t){if(t===void 0||t===""||t==="."||t===-1||t===e.name||t===e.uuid)return e;if(e.skeleton){const n=e.skeleton.getBoneByName(t);if(n!==void 0)return n}if(e.children){const n=function(r){for(let o=0;o=r){const h=r++,d=e[h];t[d.uuid]=u,e[u]=d,t[c]=h,e[h]=l;for(let f=0,g=i;f!==g;++f){const v=n[f],m=v[h],p=v[u];v[u]=m,v[h]=p}}}this.nCachedObjects_=r}uncache(){const e=this._objects,t=this._indicesByUUID,n=this._bindings,i=n.length;let r=this.nCachedObjects_,o=e.length;for(let a=0,l=arguments.length;a!==l;++a){const c=arguments[a],u=c.uuid,h=t[u];if(h!==void 0)if(delete t[u],h0&&(t[f.uuid]=h),e[h]=f,e.pop();for(let g=0,v=i;g!==v;++g){const m=n[g];m[h]=m[d],m.pop()}}}this.nCachedObjects_=r}subscribe_(e,t){const n=this._bindingsIndicesByPath;let i=n[e];const r=this._bindings;if(i!==void 0)return r[i];const o=this._paths,a=this._parsedPaths,l=this._objects,c=l.length,u=this.nCachedObjects_,h=new Array(c);i=r.length,n[e]=i,o.push(e),a.push(t),r.push(h);for(let d=u,f=l.length;d!==f;++d){const g=l[d];h[d]=new lt(g,e,t)}return h}unsubscribe_(e){const t=this._bindingsIndicesByPath,n=t[e];if(n!==void 0){const i=this._paths,r=this._parsedPaths,o=this._bindings,a=o.length-1,l=o[a],c=e[a];t[c]=n,o[n]=l,o.pop(),r[n]=r[a],r.pop(),i[n]=i[a],i.pop()}}}class dm{constructor(e,t,n=null,i=t.blendMode){this._mixer=e,this._clip=t,this._localRoot=n,this.blendMode=i;const r=t.tracks,o=r.length,a=new Array(o),l={endingStart:Ji,endingEnd:Ji};for(let c=0;c!==o;++c){const u=r[c].createInterpolant(null);a[c]=u,u.settings=l}this._interpolantSettings=l,this._interpolants=a,this._propertyBindings=new Array(o),this._cacheIndex=null,this._byClipCacheIndex=null,this._timeScaleInterpolant=null,this._weightInterpolant=null,this.loop=Wf,this._loopCount=-1,this._startTime=null,this.time=0,this.timeScale=1,this._effectiveTimeScale=1,this.weight=1,this._effectiveWeight=1,this.repetitions=1/0,this.paused=!1,this.enabled=!0,this.clampWhenFinished=!1,this.zeroSlopeAtStart=!0,this.zeroSlopeAtEnd=!0}play(){return this._mixer._activateAction(this),this}stop(){return this._mixer._deactivateAction(this),this.reset()}reset(){return this.paused=!1,this.enabled=!0,this.time=0,this._loopCount=-1,this._startTime=null,this.stopFading().stopWarping()}isRunning(){return this.enabled&&!this.paused&&this.timeScale!==0&&this._startTime===null&&this._mixer._isActiveAction(this)}isScheduled(){return this._mixer._isActiveAction(this)}startAt(e){return this._startTime=e,this}setLoop(e,t){return this.loop=e,this.repetitions=t,this}setEffectiveWeight(e){return this.weight=e,this._effectiveWeight=this.enabled?e:0,this.stopFading()}getEffectiveWeight(){return this._effectiveWeight}fadeIn(e){return this._scheduleFading(e,0,1)}fadeOut(e){return this._scheduleFading(e,1,0)}crossFadeFrom(e,t,n){if(e.fadeOut(t),this.fadeIn(t),n){const i=this._clip.duration,r=e._clip.duration,o=r/i,a=i/r;e.warp(1,o,t),this.warp(a,1,t)}return this}crossFadeTo(e,t,n){return e.crossFadeFrom(this,t,n)}stopFading(){const e=this._weightInterpolant;return e!==null&&(this._weightInterpolant=null,this._mixer._takeBackControlInterpolant(e)),this}setEffectiveTimeScale(e){return this.timeScale=e,this._effectiveTimeScale=this.paused?0:e,this.stopWarping()}getEffectiveTimeScale(){return this._effectiveTimeScale}setDuration(e){return this.timeScale=this._clip.duration/e,this.stopWarping()}syncWith(e){return this.time=e.time,this.timeScale=e.timeScale,this.stopWarping()}halt(e){return this.warp(this._effectiveTimeScale,0,e)}warp(e,t,n){const i=this._mixer,r=i.time,o=this.timeScale;let a=this._timeScaleInterpolant;a===null&&(a=i._lendControlInterpolant(),this._timeScaleInterpolant=a);const l=a.parameterPositions,c=a.sampleValues;return l[0]=r,l[1]=r+n,c[0]=e/o,c[1]=t/o,this}stopWarping(){const e=this._timeScaleInterpolant;return e!==null&&(this._timeScaleInterpolant=null,this._mixer._takeBackControlInterpolant(e)),this}getMixer(){return this._mixer}getClip(){return this._clip}getRoot(){return this._localRoot||this._mixer._root}_update(e,t,n,i){if(!this.enabled){this._updateWeight(e);return}const r=this._startTime;if(r!==null){const l=(e-r)*n;l<0||n===0?t=0:(this._startTime=null,t=n*l)}t*=this._updateTimeScale(e);const o=this._updateTime(t),a=this._updateWeight(e);if(a>0){const l=this._interpolants,c=this._propertyBindings;switch(this.blendMode){case au:for(let u=0,h=l.length;u!==h;++u)l[u].evaluate(o),c[u].accumulateAdditive(a);break;case Pa:default:for(let u=0,h=l.length;u!==h;++u)l[u].evaluate(o),c[u].accumulate(i,a)}}}_updateWeight(e){let t=0;if(this.enabled){t=this.weight;const n=this._weightInterpolant;if(n!==null){const i=n.evaluate(e)[0];t*=i,e>n.parameterPositions[1]&&(this.stopFading(),i===0&&(this.enabled=!1))}}return this._effectiveWeight=t,t}_updateTimeScale(e){let t=0;if(!this.paused){t=this.timeScale;const n=this._timeScaleInterpolant;if(n!==null){const i=n.evaluate(e)[0];t*=i,e>n.parameterPositions[1]&&(this.stopWarping(),t===0?this.paused=!0:this.timeScale=t)}}return this._effectiveTimeScale=t,t}_updateTime(e){const t=this._clip.duration,n=this.loop;let i=this.time+e,r=this._loopCount;const o=n===$f;if(e===0)return r===-1?i:o&&(r&1)===1?t-i:i;if(n===Gf){r===-1&&(this._loopCount=0,this._setEndings(!0,!0,!1));e:{if(i>=t)i=t;else if(i<0)i=0;else{this.time=i;break e}this.clampWhenFinished?this.paused=!0:this.enabled=!1,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:e<0?-1:1})}}else{if(r===-1&&(e>=0?(r=0,this._setEndings(!0,this.repetitions===0,o)):this._setEndings(this.repetitions===0,!0,o)),i>=t||i<0){const a=Math.floor(i/t);i-=t*a,r+=Math.abs(a);const l=this.repetitions-r;if(l<=0)this.clampWhenFinished?this.paused=!0:this.enabled=!1,i=e>0?t:0,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:e>0?1:-1});else{if(l===1){const c=e<0;this._setEndings(c,!c,o)}else this._setEndings(!1,!1,o);this._loopCount=r,this.time=i,this._mixer.dispatchEvent({type:"loop",action:this,loopDelta:a})}}else this.time=i;if(o&&(r&1)===1)return t-i}return i}_setEndings(e,t,n){const i=this._interpolantSettings;n?(i.endingStart=Ki,i.endingEnd=Ki):(e?i.endingStart=this.zeroSlopeAtStart?Ki:Ji:i.endingStart=Ar,t?i.endingEnd=this.zeroSlopeAtEnd?Ki:Ji:i.endingEnd=Ar)}_scheduleFading(e,t,n){const i=this._mixer,r=i.time;let o=this._weightInterpolant;o===null&&(o=i._lendControlInterpolant(),this._weightInterpolant=o);const a=o.parameterPositions,l=o.sampleValues;return a[0]=r,l[0]=t,a[1]=r+e,l[1]=n,this}}const Nb=new Float32Array(1);class Db extends ui{constructor(e){super(),this._root=e,this._initMemoryManager(),this._accuIndex=0,this.time=0,this.timeScale=1}_bindAction(e,t){const n=e._localRoot||this._root,i=e._clip.tracks,r=i.length,o=e._propertyBindings,a=e._interpolants,l=n.uuid,c=this._bindingsByRootAndName;let u=c[l];u===void 0&&(u={},c[l]=u);for(let h=0;h!==r;++h){const d=i[h],f=d.name;let g=u[f];if(g!==void 0)++g.referenceCount,o[h]=g;else{if(g=o[h],g!==void 0){g._cacheIndex===null&&(++g.referenceCount,this._addInactiveBinding(g,l,f));continue}const v=t&&t._propertyBindings[h].binding.parsedPath;g=new hm(lt.create(n,f,v),d.ValueTypeName,d.getValueSize()),++g.referenceCount,this._addInactiveBinding(g,l,f),o[h]=g}a[h].resultBuffer=g.buffer}}_activateAction(e){if(!this._isActiveAction(e)){if(e._cacheIndex===null){const n=(e._localRoot||this._root).uuid,i=e._clip.uuid,r=this._actionsByClip[i];this._bindAction(e,r&&r.knownActions[0]),this._addInactiveAction(e,i,n)}const t=e._propertyBindings;for(let n=0,i=t.length;n!==i;++n){const r=t[n];r.useCount++===0&&(this._lendBinding(r),r.saveOriginalState())}this._lendAction(e)}}_deactivateAction(e){if(this._isActiveAction(e)){const t=e._propertyBindings;for(let n=0,i=t.length;n!==i;++n){const r=t[n];--r.useCount===0&&(r.restoreOriginalState(),this._takeBackBinding(r))}this._takeBackAction(e)}}_initMemoryManager(){this._actions=[],this._nActiveActions=0,this._actionsByClip={},this._bindings=[],this._nActiveBindings=0,this._bindingsByRootAndName={},this._controlInterpolants=[],this._nActiveControlInterpolants=0;const e=this;this.stats={actions:{get total(){return e._actions.length},get inUse(){return e._nActiveActions}},bindings:{get total(){return e._bindings.length},get inUse(){return e._nActiveBindings}},controlInterpolants:{get total(){return e._controlInterpolants.length},get inUse(){return e._nActiveControlInterpolants}}}}_isActiveAction(e){const t=e._cacheIndex;return t!==null&&t=0;--n)e[n].stop();return this}update(e){e*=this.timeScale;const t=this._actions,n=this._nActiveActions,i=this.time+=e,r=Math.sign(e),o=this._accuIndex^=1;for(let c=0;c!==n;++c)t[c]._update(i,e,r,o);const a=this._bindings,l=this._nActiveBindings;for(let c=0;c!==l;++c)a[c].apply(o);return this}setTime(e){this.time=0;for(let t=0;tthis.max.x||e.ythis.max.y)}containsBox(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y}getParameter(e,t){return t.set((e.x-this.min.x)/(this.max.x-this.min.x),(e.y-this.min.y)/(this.max.y-this.min.y))}intersectsBox(e){return!(e.max.xthis.max.x||e.max.ythis.max.y)}clampPoint(e,t){return t.copy(e).clamp(this.min,this.max)}distanceToPoint(e){return this.clampPoint(e,Ad).distanceTo(e)}intersect(e){return this.min.max(e.min),this.max.min(e.max),this.isEmpty()&&this.makeEmpty(),this}union(e){return this.min.min(e.min),this.max.max(e.max),this}translate(e){return this.min.add(e),this.max.add(e),this}equals(e){return e.min.equals(this.min)&&e.max.equals(this.max)}}const Td=new N,qo=new N;class Vb{constructor(e=new N,t=new N){this.start=e,this.end=t}set(e,t){return this.start.copy(e),this.end.copy(t),this}copy(e){return this.start.copy(e.start),this.end.copy(e.end),this}getCenter(e){return e.addVectors(this.start,this.end).multiplyScalar(.5)}delta(e){return e.subVectors(this.end,this.start)}distanceSq(){return this.start.distanceToSquared(this.end)}distance(){return this.start.distanceTo(this.end)}at(e,t){return this.delta(t).multiplyScalar(e).add(this.start)}closestPointToPointParameter(e,t){Td.subVectors(e,this.start),qo.subVectors(this.end,this.start);const n=qo.dot(qo);let r=qo.dot(Td)/n;return t&&(r=Et(r,0,1)),r}closestPointToPoint(e,t,n){const i=this.closestPointToPointParameter(e,t);return this.delta(n).multiplyScalar(i).add(this.start)}applyMatrix4(e){return this.start.applyMatrix4(e),this.end.applyMatrix4(e),this}equals(e){return e.start.equals(this.start)&&e.end.equals(this.end)}clone(){return new this.constructor().copy(this)}}const Ed=new N;class Hb extends ct{constructor(e,t){super(),this.light=e,this.matrixAutoUpdate=!1,this.color=t,this.type="SpotLightHelper";const n=new it,i=[0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,-1,0,1,0,0,0,0,1,1,0,0,0,0,-1,1];for(let o=0,a=1,l=32;o1)for(let h=0;h.99999)this.quaternion.set(0,0,0,1);else if(e.y<-.99999)this.quaternion.set(1,0,0,0);else{Ld.set(e.z,0,-e.x).normalize();const t=Math.acos(e.y);this.quaternion.setFromAxisAngle(Ld,t)}}setLength(e,t=e*.2,n=t*.2){this.line.scale.set(1,Math.max(1e-4,e-t),1),this.line.updateMatrix(),this.cone.scale.set(n,t,n),this.cone.position.y=e,this.cone.updateMatrix()}setColor(e){this.line.material.color.set(e),this.cone.material.color.set(e)}copy(e){return super.copy(e,!1),this.line.copy(e.line),this.cone.copy(e.cone),this}dispose(){this.line.geometry.dispose(),this.line.material.dispose(),this.cone.geometry.dispose(),this.cone.material.dispose()}}class tS extends qn{constructor(e=1){const t=[0,0,0,e,0,0,0,0,0,0,e,0,0,0,0,0,0,e],n=[1,0,0,1,.6,0,0,1,0,.6,1,0,0,0,1,0,.6,1],i=new it;i.setAttribute("position",new Ne(t,3)),i.setAttribute("color",new Ne(n,3));const r=new rn({vertexColors:!0,toneMapped:!1});super(i,r),this.type="AxesHelper"}setColors(e,t,n){const i=new Pe,r=this.geometry.attributes.color.array;return i.set(e),i.toArray(r,0),i.toArray(r,3),i.set(t),i.toArray(r,6),i.toArray(r,9),i.set(n),i.toArray(r,12),i.toArray(r,15),this.geometry.attributes.color.needsUpdate=!0,this}dispose(){this.geometry.dispose(),this.material.dispose()}}class Si{constructor(){this.type="ShapePath",this.color=new Pe,this.subPaths=[],this.currentPath=null}moveTo(e,t){return this.currentPath=new Ti,this.subPaths.push(this.currentPath),this.currentPath.moveTo(e,t),this}lineTo(e,t){return this.currentPath.lineTo(e,t),this}quadraticCurveTo(e,t,n,i){return this.currentPath.quadraticCurveTo(e,t,n,i),this}bezierCurveTo(e,t,n,i,r,o){return this.currentPath.bezierCurveTo(e,t,n,i,r,o),this}splineThru(e){return this.currentPath.splineThru(e),this}toShapes(e){function t(p){const y=[];for(let _=0,x=p.length;_Number.EPSILON){if(M<0&&(E=y[b],w=-w,I=y[A],M=-M),p.yI.y)continue;if(p.y===E.y){if(p.x===E.x)return!0}else{const F=M*(p.x-E.x)-w*(p.y-E.y);if(F===0)return!0;if(F<0)continue;x=!x}}else{if(p.y!==E.y)continue;if(I.x<=p.x&&p.x<=E.x||E.x<=p.x&&p.x<=I.x)return!0}}return x}const i=Pn.isClockWise,r=this.subPaths;if(r.length===0)return[];let o,a,l;const c=[];if(r.length===1)return a=r[0],l=new Ei,l.curves=a.curves,c.push(l),c;let u=!i(r[0].getPoints());u=e?!u:u;const h=[],d=[];let f=[],g=0,v;d[g]=void 0,f[g]=[];for(let p=0,y=r.length;p1){let p=!1,y=0;for(let _=0,x=d.length;_0&&p===!1&&(f=h)}let m;for(let p=0,y=d.length;p{s.delete(i)};return{on:i=>{s.add(i);const r=()=>e(i);return Xn(r),{off:r}},off:e,trigger:(...i)=>Promise.all(Array.from(s).map(r=>r(...i)))}}function bt(s){return typeof s=="function"?s():j(s)}const Bc=typeof window<"u"&&typeof document<"u";typeof WorkerGlobalScope<"u"&&globalThis instanceof WorkerGlobalScope;const sS=s=>s!=null,rS=Object.prototype.toString,oS=s=>rS.call(s)==="[object Object]",zc=()=>{};function aS(s,e){function t(...n){return new Promise((i,r)=>{Promise.resolve(s(()=>e.apply(this,n),{fn:e,thisArg:this,args:n})).then(i).catch(r)})}return t}function lS(s,e={}){let t,n,i=zc;const r=a=>{clearTimeout(a),i(),i=zc};return a=>{const l=bt(s),c=bt(e.maxWait);return t&&r(t),l<=0||c!==void 0&&c<=0?(n&&(r(n),n=null),Promise.resolve(a())):new Promise((u,h)=>{i=e.rejectOnCancel?h:u,c&&!n&&(n=setTimeout(()=>{t&&r(t),n=null,u(a())},c)),t=setTimeout(()=>{n&&r(n),n=null,u(a())},l)})}}function cS(s,e,t=!1){return e.reduce((n,i)=>(i in s&&(!t||s[i]!==void 0)&&(n[i]=s[i]),n),{})}function uS(s){return ma()}function hS(s,e=200,t={}){return aS(lS(e,t),s)}function Nd(s,e=200,t={}){const n=Ge(s.value),i=hS(()=>{n.value=s.value},e,t);return Ct(s,()=>i()),n}function dS(s,e={}){if(!$d(s))return Vm(s);const t=Array.isArray(s.value)?Array.from({length:s.value.length}):{};for(const n in s.value)t[n]=Hm(()=>({get(){return s.value[n]},set(i){var r;if((r=bt(e.replaceRef))!=null?r:!0)if(Array.isArray(s.value)){const a=[...s.value];a[n]=i,s.value=a}else{const a={...s.value,[n]:i};Object.setPrototypeOf(a,Object.getPrototypeOf(s.value)),s.value=a}else s.value[n]=i}}));return t}function Fu(s,e=!0,t){uS()?Nn(s,t):e?s():qc(s)}function fS(s,e=1e3,t={}){const{immediate:n=!0,immediateCallback:i=!1}=t;let r=null;const o=Ge(!1);function a(){r&&(clearInterval(r),r=null)}function l(){o.value=!1,a()}function c(){const u=bt(e);u<=0||(o.value=!0,i&&s(),a(),r=setInterval(s,u))}if(n&&Bc&&c(),$d(e)||typeof e=="function"){const u=Ct(e,()=>{o.value&&Bc&&c()});Xn(u)}return Xn(l),{isActive:o,pause:l,resume:c}}function Cn(s){var e;const t=bt(s);return(e=t==null?void 0:t.$el)!=null?e:t}const di=Bc?window:void 0;function Br(...s){let e,t,n,i;if(typeof s[0]=="string"||Array.isArray(s[0])?([t,n,i]=s,e=di):[e,t,n,i]=s,!e)return zc;Array.isArray(t)||(t=[t]),Array.isArray(n)||(n=[n]);const r=[],o=()=>{r.forEach(u=>u()),r.length=0},a=(u,h,d,f)=>(u.addEventListener(h,d,f),()=>u.removeEventListener(h,d,f)),l=Ct(()=>[Cn(e),bt(i)],([u,h])=>{if(o(),!u)return;const d=oS(h)?{...h}:h;r.push(...t.flatMap(f=>n.map(g=>a(u,f,g,d))))},{immediate:!0,flush:"post"}),c=()=>{l(),o()};return Xn(c),c}function pS(){const s=Ge(!1),e=ma();return e&&Nn(()=>{s.value=!0},e),s}function il(s){const e=pS();return ke(()=>(e.value,!!s()))}function mS(s,e,t={}){const{window:n=di,...i}=t;let r;const o=il(()=>n&&"MutationObserver"in n),a=()=>{r&&(r.disconnect(),r=void 0)},l=ke(()=>{const d=bt(s),f=(Array.isArray(d)?d:[d]).map(Cn).filter(sS);return new Set(f)}),c=Ct(()=>l.value,d=>{a(),o.value&&d.size&&(r=new MutationObserver(e),d.forEach(f=>r.observe(f,i)))},{immediate:!0,flush:"post"}),u=()=>r==null?void 0:r.takeRecords(),h=()=>{a(),c()};return Xn(h),{isSupported:o,stop:h,takeRecords:u}}function ku(s,e={}){const{immediate:t=!0,fpsLimit:n=void 0,window:i=di}=e,r=Ge(!1),o=n?1e3/n:null;let a=0,l=null;function c(d){if(!r.value||!i)return;a||(a=d);const f=d-a;if(o&&ft&&"matchMedia"in t&&typeof t.matchMedia=="function");let i;const r=Ge(!1),o=c=>{r.value=c.matches},a=()=>{i&&("removeEventListener"in i?i.removeEventListener("change",o):i.removeListener(o))},l=Ri(()=>{n.value&&(a(),i=t.matchMedia(bt(s)),"addEventListener"in i?i.addEventListener("change",o):i.addListener(o),r.value=i.matches)});return Xn(()=>{l(),a(),i=void 0}),r}function vS(s={}){const{window:e=di}=s,t=Ge(1);if(e){let n=function(){t.value=e.devicePixelRatio,i(),r=e.matchMedia(`(resolution: ${t.value}dppx)`),r.addEventListener("change",n,{once:!0})},i=function(){r==null||r.removeEventListener("change",n)},r;n(),Xn(i)}return{pixelRatio:t}}function gm(s,e,t={}){const{window:n=di,...i}=t;let r;const o=il(()=>n&&"ResizeObserver"in n),a=()=>{r&&(r.disconnect(),r=void 0)},l=ke(()=>Array.isArray(s)?s.map(h=>Cn(h)):[Cn(s)]),c=Ct(l,h=>{if(a(),o.value&&n){r=new ResizeObserver(e);for(const d of h)d&&r.observe(d,i)}},{immediate:!0,flush:"post"}),u=()=>{a(),c()};return Xn(u),{isSupported:o,stop:u}}function _S(s,e={}){const{reset:t=!0,windowResize:n=!0,windowScroll:i=!0,immediate:r=!0}=e,o=Ge(0),a=Ge(0),l=Ge(0),c=Ge(0),u=Ge(0),h=Ge(0),d=Ge(0),f=Ge(0);function g(){const v=Cn(s);if(!v){t&&(o.value=0,a.value=0,l.value=0,c.value=0,u.value=0,h.value=0,d.value=0,f.value=0);return}const m=v.getBoundingClientRect();o.value=m.height,a.value=m.bottom,l.value=m.left,c.value=m.right,u.value=m.top,h.value=m.width,d.value=m.x,f.value=m.y}return gm(s,g),Ct(()=>Cn(s),v=>!v&&g()),mS(s,g,{attributeFilter:["style","class"]}),i&&Br("scroll",g,{capture:!0,passive:!0}),n&&Br("resize",g,{passive:!0}),Fu(()=>{r&&g()}),{height:o,bottom:a,left:l,right:c,top:u,width:h,x:d,y:f,update:g}}function yS(s,e={width:0,height:0},t={}){const{window:n=di,box:i="content-box"}=t,r=ke(()=>{var h,d;return(d=(h=Cn(s))==null?void 0:h.namespaceURI)==null?void 0:d.includes("svg")}),o=Ge(e.width),a=Ge(e.height),{stop:l}=gm(s,([h])=>{const d=i==="border-box"?h.borderBoxSize:i==="content-box"?h.contentBoxSize:h.devicePixelContentBoxSize;if(n&&r.value){const f=Cn(s);if(f){const g=f.getBoundingClientRect();o.value=g.width,a.value=g.height}}else if(d){const f=Array.isArray(d)?d:[d];o.value=f.reduce((g,{inlineSize:v})=>g+v,0),a.value=f.reduce((g,{blockSize:v})=>g+v,0)}else o.value=h.contentRect.width,a.value=h.contentRect.height},t);Fu(()=>{const h=Cn(s);h&&(o.value="offsetWidth"in h?h.offsetWidth:e.width,a.value="offsetHeight"in h?h.offsetHeight:e.height)});const c=Ct(()=>Cn(s),h=>{o.value=h?e.width:0,a.value=h?e.height:0});function u(){l(),c()}return{width:o,height:a,stop:u}}function xS(s){var e;const t=Ge(0);if(typeof performance>"u")return t;const n=(e=s==null?void 0:s.every)!=null?e:10;let i=performance.now(),r=0;return ku(()=>{if(r+=1,r>=n){const o=performance.now(),a=o-i;t.value=Math.round(1e3/(a/r)),i=o,r=0}}),t}function MS(s={}){const e=Ge(),t=il(()=>typeof performance<"u"&&"memory"in performance);if(t.value){const{interval:n=1e3}=s;fS(()=>{e.value=performance.memory},n,{immediate:s.immediate,immediateCallback:s.immediateCallback})}return{isSupported:t,memory:e}}const vm={x:0,y:0,pointerId:0,pressure:0,tiltX:0,tiltY:0,width:0,height:0,twist:0,pointerType:null},bS=Object.keys(vm);function SS(s={}){const{target:e=di}=s,t=Ge(!1),n=Ge(s.initialValue||{});Object.assign(n.value,vm,n.value);const i=r=>{t.value=!0,!(s.pointerTypes&&!s.pointerTypes.includes(r.pointerType))&&(n.value=cS(r,bS,!1))};if(e){const r={passive:!0};Br(e,["pointerdown","pointermove","pointerup"],i,r),Br(e,"pointerleave",()=>t.value=!1,r)}return{...dS(n),isInside:t}}function wS(s={}){const{window:e=di,initialWidth:t=Number.POSITIVE_INFINITY,initialHeight:n=Number.POSITIVE_INFINITY,listenOrientation:i=!0,includeScrollbar:r=!0}=s,o=Ge(t),a=Ge(n),l=()=>{e&&(r?(o.value=e.innerWidth,a.value=e.innerHeight):(o.value=e.document.documentElement.clientWidth,a.value=e.document.documentElement.clientHeight))};if(l(),Fu(l),Br("resize",l,{passive:!0}),i){const c=gS("(orientation: portrait)");Ct(c,()=>l())}return{width:o,height:a}}var AS=Object.defineProperty,TS=(s,e,t)=>e in s?AS(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t,Dd=(s,e,t)=>(TS(s,typeof e!="symbol"?e+"":e,t),t);const ES="@tresjs/core",CS="module",PS="4.0.2",RS="pnpm@9.1.4",IS="Declarative ThreeJS using Vue Components",LS="Alvaro Saburido (https://github.com/alvarosabu/)",NS="MIT",DS=["vue","3d","threejs","three","threejs-vue"],US=!1,OS={".":{types:"./dist/index.d.ts",import:"./dist/tres.js",require:"./dist/tres.umd.cjs"},"./components":{types:"./dist/src/components/index.d.ts"},"./composables":{types:"./dist/src/composables/index.d.ts"},"./types":{types:"./dist/src/types/index.d.ts"},"./utils":{types:"./dist/src/utils/index.d.ts"},"./*":"./*"},FS="./dist/tres.js",kS="./dist/tres.js",BS="./dist/index.d.ts",zS=["*.d.ts","dist"],VS={access:"public"},HS={dev:"cd playground && npm run dev",build:"vite build",playground:"cd playground && npm run dev",test:"vitest","test:ci":"vitest run","test:ui":"vitest --ui --coverage.enabled=true",release:"release-it",coverage:"vitest run --coverage",lint:"eslint .","lint:fix":"eslint . --fix","docs:dev":"vitepress dev docs","docs:build":"vitepress build docs","docs:serve":"vitepress serve docs","docs:preview":"vitepress preview docs","docs:contributors":"esno scripts/update-contributors.ts",prepare:"node .husky/install.mjs"},GS={three:">=0.133",vue:">=3.4"},WS={"@alvarosabu/utils":"^3.2.0","@vue/devtools-api":"^6.6.2","@vueuse/core":"^10.10.0"},$S={"@release-it/conventional-changelog":"^8.0.1","@stackblitz/sdk":"^1.10.0","@tresjs/cientos":"3.9.0","@tresjs/eslint-config":"^1.1.0","@types/three":"^0.165.0","@typescript-eslint/eslint-plugin":"^7.11.0","@typescript-eslint/parser":"^7.11.0","@vitejs/plugin-vue":"^5.0.5","@vitest/coverage-c8":"^0.33.0","@vitest/coverage-v8":"^1.6.0","@vitest/ui":"^1.6.0","@vue/test-utils":"^2.4.6",eslint:"^9.4.0","eslint-plugin-vue":"^9.26.0",esno:"^4.7.0",gsap:"^3.12.5",husky:"^9.0.11",jsdom:"^24.1.0",kolorist:"^1.8.0",ohmyfetch:"^0.4.21",pathe:"^1.1.2","release-it":"^17.3.0","rollup-plugin-analyzer":"^4.0.0","rollup-plugin-copy":"^3.5.0","rollup-plugin-visualizer":"^5.12.0",three:"^0.165.0",unocss:"^0.60.4",unplugin:"^1.10.1","unplugin-vue-components":"^0.27.0",vite:"^5.2.12","vite-plugin-banner":"^0.7.1","vite-plugin-dts":"3.9.1","vite-plugin-inspect":"^0.8.4","vite-plugin-require-transform":"^1.0.21","vite-svg-loader":"^5.1.0",vitepress:"1.2.2",vitest:"^1.6.0",vue:"^3.4.27","vue-demi":"^0.14.8"},XS={name:ES,type:CS,version:PS,packageManager:RS,description:IS,author:LS,license:NS,keywords:DS,sideEffects:US,exports:OS,main:FS,module:kS,types:BS,files:zS,publishConfig:VS,scripts:HS,peerDependencies:GS,dependencies:WS,devDependencies:$S},qS=({sizes:s})=>{const e=Ge([]),t=ke(()=>e.value[0]),n=o=>{const a=o instanceof Xr?o:e.value.find(c=>c.uuid===o);if(!a)return;const l=e.value.filter(({uuid:c})=>c!==a.uuid);e.value=[a,...l]},i=(o,a=!1)=>{e.value.some(({uuid:l})=>l===o.uuid)||(a?n(o):e.value.push(o))},r=o=>{e.value=e.value.filter(({uuid:a})=>a!==o.uuid)};return Ri(()=>{s.aspectRatio.value&&e.value.forEach(o=>{!o.manual&&(o instanceof Ut||YS(o))&&(o instanceof Ut?o.aspect=s.aspectRatio.value:(o.left=s.width.value*-.5,o.right=s.width.value*.5,o.top=s.height.value*.5,o.bottom=s.height.value*-.5),o.updateProjectionMatrix())})}),Wn(()=>{e.value=[]}),{camera:t,cameras:e,registerCamera:i,deregisterCamera:r,setCameraActive:n}};function YS(s){return s.hasOwnProperty("isOrthographicCamera")&&s.isOrthographicCamera}const _m=An(),ym=An(),Bu=An(),mr=new nl;let da=0,fa=0;const{pause:ZS,resume:Ud,isActive:JS}=ku(()=>{_m.trigger({delta:da,elapsed:fa,clock:mr}),ym.trigger({delta:da,elapsed:fa,clock:mr}),Bu.trigger({delta:da,elapsed:fa,clock:mr})},{immediate:!1});Bu.on(()=>{da=mr.getDelta(),fa=mr.getElapsedTime()});let Od=!1;const KS=()=>(Od||(Od=!0,Ud()),{onBeforeLoop:_m.on,onLoop:ym.on,onAfterLoop:Bu.on,pause:ZS,resume:Ud,isActive:JS}),Qo="[TresJS ▲ ■ ●] ";function eo(){function s(...n){typeof n[0]=="string"?n[0]=Qo+n[0]:n.unshift(Qo),console.error(...n)}function e(...n){typeof n[0]=="string"?n[0]=Qo+n[0]:n.unshift(Qo),console.warn(...n)}function t(n,i){}return{logError:s,logWarning:e,logMessage:t}}function jS(s){return s instanceof Pe?s:Array.isArray(s)?new Pe(...s):new Pe(s)}class QS extends Nt{constructor(...e){super(...e),Dd(this,"type","HightlightMesh"),Dd(this,"createTime"),this.createTime=Date.now()}onBeforeRender(){const e=(Date.now()-this.createTime)/1e3,t=1+.07*Math.sin(2.5*e);this.scale.set(t,t,t)}}const xm=(s,e)=>{for(const t of Object.keys(e))e[t]instanceof Object&&Object.assign(e[t],xm(s[t],e[t]));return Object.assign(s||{},e),s},ew="html,body,base,head,link,meta,style,title,address,article,aside,footer,header,hgroup,h1,h2,h3,h4,h5,h6,nav,section,div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,ruby,s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,output,progress,select,textarea,details,dialog,menu,summary,template,blockquote,iframe,tfoot",tw=sw(ew);function Fd(s){return s&&s.nodeType===1}function ea(s){return s.replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}const nw=/\B([A-Z])/g;function iw(s){return s.replace(nw,"-$1").toLowerCase()}function sw(s,e){const t=Object.create(null),n=s.split(",");for(let i=0;i!!t[i]}const kd=(s,e)=>{if(!e)return;const t=Array.isArray(e)?e:e.match(/([^[.\]])+/g);return t==null?void 0:t.reduce((n,i)=>n&&n[i],s)},rw=(s,e,t)=>{const n=Array.isArray(e)?e:e.match(/([^[.\]])+/g);n&&n.reduce((i,r,o)=>(i[r]===void 0&&(i[r]={}),o===n.length-1&&(i[r]=t),i[r]),s)};function Mm(s,e){if(Fd(s)&&Fd(e)){const i=s.attributes,r=e.attributes;return i.length!==r.length?!1:Array.from(i).every(({name:o,value:a})=>e.getAttribute(o)===a)}if(s===e)return!0;if(s===null||typeof s!="object"||e===null||typeof e!="object")return!1;const t=Object.keys(s),n=Object.keys(e);if(t.length!==n.length)return!1;for(const i of t)if(!n.includes(i)||!Mm(s[i],e[i]))return!1;return!0}function ow(s,e){if(!Array.isArray(s)||!Array.isArray(e)||s.length!==e.length)return!1;for(let t=0;t{if(l.uuid===e)return l;for(const c of l.children){const u=i(c);if(u)return u}},r=i(s);if(!r){console.warn("Object with UUID not found in the scene.");return}let o=r;for(let l=0;lzu(n)),!(s instanceof Fa)){const n=s;s&&((t=s.dispose)==null||t.call(s)),n.geometry&&(n.geometry.dispose(),delete n.geometry),Array.isArray(n.material)?(n.material.forEach(i=>Bd(i)),delete n.material):n.material&&(Bd(n.material),delete n.material)}}const uw=Number.parseInt(Hr.replace("dev","")),ta={realistic:{shadows:!0,physicallyCorrectLights:!0,outputColorSpace:ln,toneMapping:Ea,toneMappingExposure:3,shadowMap:{enabled:!0,type:jc}},flat:{toneMapping:Hn,toneMappingExposure:1}};function hw({canvas:s,options:e,contextParts:{sizes:t,render:n,invalidate:i,advance:r}}){const o=ke(()=>({alpha:bt(e.alpha)??!0,depth:bt(e.depth),canvas:Cn(s),context:bt(e.context),stencil:bt(e.stencil),antialias:bt(e.antialias)??!0,precision:bt(e.precision),powerPreference:bt(e.powerPreference),premultipliedAlpha:bt(e.premultipliedAlpha),preserveDrawingBuffer:bt(e.preserveDrawingBuffer),logarithmicDepthBuffer:bt(e.logarithmicDepthBuffer),failIfMajorPerformanceCaveat:bt(e.failIfMajorPerformanceCaveat)})),a=Rn(new ha(o.value));function l(){e.renderMode==="on-demand"&&i()}Ct(o,()=>{a.value.dispose(),a.value=new ha(o.value),l()}),Ct([t.width,t.height],()=>{a.value.setSize(t.width.value,t.height.value),l()},{immediate:!0}),Ct(()=>e.clearColor,l);const{pixelRatio:c}=vS();Ct(c,()=>{a.value.setPixelRatio(c.value)});const{logError:u}=eo(),h=(()=>{const f=new ha,g={shadowMap:{enabled:f.shadowMap.enabled,type:f.shadowMap.type},toneMapping:f.toneMapping,toneMappingExposure:f.toneMappingExposure,outputColorSpace:f.outputColorSpace};return f.dispose(),g})(),d=bt(e.renderMode);return d==="on-demand"&&i(),d==="manual"&&setTimeout(()=>{r()},100),Ri(()=>{const f=bt(e.preset);f&&(f in ta||u(`Renderer Preset must be one of these: ${Object.keys(ta).join(", ")}`),xm(a.value,ta[f])),d==="always"&&(n.frames.value=Math.max(1,n.frames.value));const g=(p,y)=>{const _=bt(p),x=()=>{if(f)return kd(ta[f],y)};if(_!==void 0)return _;const A=x();return A!==void 0?A:kd(h,y)},v=(p,y)=>rw(a.value,y,g(p,y));v(e.shadows,"shadowMap.enabled"),v(e.toneMapping??Ea,"toneMapping"),v(e.shadowMapType,"shadowMap.type"),uw<150&&v(!e.useLegacyLights,"physicallyCorrectLights"),v(e.outputColorSpace,"outputColorSpace"),v(e.toneMappingExposure,"toneMappingExposure");const m=g(e.clearColor,"clearColor");m&&a.value.setClearColor(m?jS(m):new Pe(0))}),Wn(()=>{a.value.dispose(),a.value.forceContextLoss()}),{renderer:a}}const na=s=>typeof s=="function",dw=s=>s.constructor===Array;function fw(s){const e={nodes:{},materials:{}};return s&&s.traverse(t=>{t.name&&(e.nodes[t.name]=t),t.material&&!e.materials[t.material.name]&&(e.materials[t.material.name]=t.material)}),e}async function pw(s,e,t,n,i){const{logError:r}=eo(),o=new s,a=(Array.isArray(e)?e:[e]).map(l=>new Promise((c,u)=>{o.load(l,h=>{h.scene&&Object.assign(h,fw(h.scene)),c(h)},n,h=>u(r("[useLoader] - Failed to load resource",h)))}));return dw(e)?await Promise.all(a):await a[0]}const mw=(s,e)=>{const t=ke(()=>e.renderer.value.domElement),n=Rn([]),{x:i,y:r}=SS({target:t}),o=ke(()=>s.value.filter(ge=>{var ze;return((ze=ge.__tres)==null?void 0:ze.eventCount)>0}));let a=0;const{width:l,height:c,top:u,left:h}=_S(t),d=({x:ge,y:ze})=>{if(t.value)return{x:(ge-h.value)/l.value*2-1,y:-((ze-u.value)/c.value)*2+1}},f=({x:ge,y:ze})=>{if(e.camera.value)return e.raycaster.value.setFromCamera(new se(ge,ze),e.camera.value),n.value=e.raycaster.value.intersectObjects(o.value,!0),n.value},g=ge=>{const ze=d({x:(ge==null?void 0:ge.clientX)??i.value,y:(ge==null?void 0:ge.clientY)??r.value});return ze?f(ze)||[]:[]},v=An(),m=An(),p=An(),y=An(),_=An(),x=An(),A=An(),b=An();function E(ge){const ze={};for(const U in ge)typeof U!="function"&&(ze[U]=ge[U]);return ze}const I=(ge,ze)=>{var U,D,R;const T=E(ze),ie=new N(ze==null?void 0:ze.clientX,ze==null?void 0:ze.clientY,0).unproject((U=e.camera)==null?void 0:U.value);ge.trigger({...T,intersections:n.value,unprojectedPoint:ie,ray:(D=e.raycaster)==null?void 0:D.value.ray,camera:(R=e.camera)==null?void 0:R.value,sourceEvent:ze,delta:a,stopPropagating:!1})};let w;const M=ge=>{g(ge),I(p,ge),w=ge},F=()=>{w&&M(w)};let V,G,q;const ae=ge=>{var ze;V=(ze=n.value[0])==null?void 0:ze.object,a=0,G=new se((ge==null?void 0:ge.clientX)??i.value,(ge==null?void 0:ge.clientY)??r.value),I(_,ge)};let Q,oe=!1;const B=ge=>{var ze,U,D;ge instanceof PointerEvent&&(n.value.length===0&&I(x,ge),V===((ze=n.value[0])==null?void 0:ze.object)&&(q=new se((ge==null?void 0:ge.clientX)??i.value,(ge==null?void 0:ge.clientY)??r.value),a=G==null?void 0:G.distanceTo(q),ge.button===0?(I(v,ge),Q===((U=n.value[0])==null?void 0:U.object)?oe=!0:(Q=(D=n.value[0])==null?void 0:D.object,oe=!1)):ge.button===2&&I(A,ge)),I(y,ge))},Me=ge=>{oe&&(I(m,ge),Q=void 0,oe=!1)},be=ge=>I(p,ge),Ae=ge=>I(b,ge);return t.value.addEventListener("pointerup",B),t.value.addEventListener("pointerdown",ae),t.value.addEventListener("pointermove",M),t.value.addEventListener("pointerleave",be),t.value.addEventListener("dblclick",Me),t.value.addEventListener("wheel",Ae),Wn(()=>{t!=null&&t.value&&(t.value.removeEventListener("pointerup",B),t.value.removeEventListener("pointerdown",ae),t.value.removeEventListener("pointermove",M),t.value.removeEventListener("pointerleave",be),t.value.removeEventListener("dblclick",Me),t.value.removeEventListener("wheel",Ae))}),{intersects:n,onClick:ge=>v.on(ge).off,onDblClick:ge=>m.on(ge).off,onContextMenu:ge=>A.on(ge).off,onPointerMove:ge=>p.on(ge).off,onPointerUp:ge=>y.on(ge).off,onPointerDown:ge=>_.on(ge).off,onPointerMissed:ge=>x.on(ge).off,onWheel:ge=>b.on(ge).off,forceUpdate:F}};function Vu(s){let e=0;return s.traverse(t=>{if(t.isMesh&&t.geometry){const n=t.geometry,i=n.attributes.position.count*3*Float32Array.BYTES_PER_ELEMENT,r=n.index?n.index.count*Uint32Array.BYTES_PER_ELEMENT:0,o=n.attributes.normal?n.attributes.normal.count*3*Float32Array.BYTES_PER_ELEMENT:0,a=n.attributes.uv?n.attributes.uv.count*2*Float32Array.BYTES_PER_ELEMENT:0,l=i+r+o+a;e+=l}}),e}function gw(s){return(s/1024).toFixed(2)}const Vc=Ge({}),Hc=s=>Object.assign(Vc.value,s);function vw(s,e,t=10){const n=bt(s)?wS():yS(ke(()=>bt(e).parentElement)),i=gr(Nd(n.width,t)),r=gr(Nd(n.height,t)),o=ke(()=>i.value/r.value);return{height:r,width:i,aspectRatio:o}}function Zl(){const s=new Map,e=new Set;let t=0,n=!1;const i=()=>{const o=Array.from(s.entries()).sort((a,l)=>{const c=a[1].priority-l[1].priority;return c===0?a[1].addI-l[1].addI:c});e.clear(),o.forEach(a=>e.add(a[0]))},r=o=>{s.delete(o),e.delete(o)};return{on:(o,a=0)=>{s.set(o,{priority:a,addI:t++});const l=()=>r(o);return Xn(l),n=!0,{off:l}},off:r,trigger:(...o)=>{n&&(i(),n=!1),e.forEach(a=>a(...o))},dispose:()=>{s.clear(),e.clear()},get count(){return s.size}}}function _w(){const s=new nl(!1),e=Ge(!1),t=Ge(!1);let n;const i=ip.generateUUID();let r=null;const o=Zl(),a=Zl(),l=Zl();let c={};function u(_){c=_}function h(_,x,A=0){switch(x){case"before":return o.on(_,A);case"render":return r||(r=_),a.dispose(),a.on(_);case"after":return l.on(_,A)}}function d(){e.value||(s.start(),e.value=!0,y())}function f(){e.value&&(s.stop(),cancelAnimationFrame(n),e.value=!1)}function g(){s.stop(),e.value=!1}function v(){s.start(),e.value=!0}function m(){t.value=!0}function p(){t.value=!1}function y(){const _=s.getDelta(),x=s.getElapsedTime(),A={camera:j(c.camera),scene:j(c.scene),renderer:j(c.renderer),raycaster:j(c.raycaster),controls:j(c.controls),invalidate:c.invalidate,advance:c.advance},b={delta:_,elapsed:x,clock:s,...A};e.value&&o.trigger(b),t.value||(a.count?a.trigger(b):r&&r(b)),e.value&&l.trigger(b),n=requestAnimationFrame(y)}return{loopId:i,register:(_,x,A)=>h(_,x,A),start:d,stop:f,pause:g,resume:v,pauseRender:m,resumeRender:p,isRenderPaused:t,isActive:e,setContext:u}}function yw({scene:s,canvas:e,windowSize:t,disableRender:n,rendererOptions:i,emit:r}){const{logWarning:o}=eo(),a=Rn(s),l=vw(t,e),{camera:c,cameras:u,registerCamera:h,deregisterCamera:d,setCameraActive:f}=qS({sizes:l,scene:s}),g={mode:Ge(i.renderMode||"always"),priority:Ge(0),frames:Ge(0),maxFrames:60,canBeInvalidated:ke(()=>g.mode.value==="on-demand"&&g.frames.value===0)};function v(G=1){i.renderMode==="on-demand"?g.frames.value=Math.min(g.maxFrames,g.frames.value+G):o("`invalidate` can only be used when `renderMode` is set to `on-demand`")}function m(){i.renderMode==="manual"?g.frames.value=1:o("`advance` can only be used when `renderMode` is set to `manual`")}const{renderer:p}=hw({scene:s,canvas:e,options:i,emit:r,contextParts:{sizes:l,camera:c,render:g,invalidate:v,advance:m},disableRender:n}),y={sizes:l,scene:a,camera:c,cameras:gr(u),renderer:p,raycaster:Rn(new fm),controls:Ge(null),perf:{maxFrames:160,fps:{value:0,accumulator:[]},memory:{currentMem:0,allocatedMem:0,accumulator:[]}},render:g,advance:m,extend:Hc,invalidate:v,registerCamera:h,setCameraActive:f,deregisterCamera:d,loop:_w()};vr("useTres",y),y.scene.value.__tres={root:y},y.loop.register(()=>{c.value&&g.frames.value>0&&(p.value.render(s,c.value),r("render",y.renderer.value)),g.priority.value=0,g.mode.value==="always"?g.frames.value=1:g.frames.value=Math.max(0,g.frames.value-1)},"render"),y.loop.start(),Wn(()=>{y.loop.stop()});const _=100,x=xS({every:_}),{isSupported:A,memory:b}=MS({interval:_}),E=160;let I=performance.now();const w=({timestamp:G})=>{y.scene.value&&(y.perf.memory.allocatedMem=Vu(y.scene.value)),G-I>=_&&(I=G,y.perf.fps.accumulator.push(x.value),y.perf.fps.accumulator.length>E&&y.perf.fps.accumulator.shift(),y.perf.fps.value=x.value,A.value&&b.value&&(y.perf.memory.accumulator.push(b.value.usedJSHeapSize/1024/1024),y.perf.memory.accumulator.length>E&&y.perf.memory.accumulator.shift(),y.perf.memory.currentMem=y.perf.memory.accumulator.reduce((q,ae)=>q+ae,0)/y.perf.memory.accumulator.length))};let M=0;const F=1,{pause:V}=ku(({delta:G})=>{window.__TRES__DEVTOOLS__&&(w({timestamp:performance.now()}),M+=G,M>=F&&(window.__TRES__DEVTOOLS__.cb(y),M=0))},{immediate:!0});return Wn(()=>{V()}),y}function xw(){const s=zr("useTres");if(!s)throw new Error("useTresContext must be used together with useTresContextProvider");return s}function Mw(s,e,t){const n=Rn(),i=Rn();s&&(n.value=s),e&&(i.value=e);const r=ke(()=>n.value?n.value.children:[]);function o(A,b){if(Array.isArray(A))for(const E of A)E(b);typeof A=="function"&&A(b)}function a(A,b){const E=[],I=()=>b.stopPropagating=!0;b.stopPropagation=I;for(const w of b==null?void 0:b.intersections){if(b.stopPropagating)return;b={...b,...w};const{object:M}=w;b.eventObject=M,o(M[A],b),E.push(M);let F=M.parent;for(;F!==null&&!b.stopPropagating&&!E.includes(F);)b.eventObject=F,o(F[A],b),E.push(F),F=F.parent;const V=iw(A.slice(2));t(V,{intersection:w,event:b})}}const{onClick:l,onDblClick:c,onContextMenu:u,onPointerMove:h,onPointerDown:d,onPointerUp:f,onPointerMissed:g,onWheel:v,forceUpdate:m}=mw(r,e);f(A=>a("onPointerUp",A)),d(A=>a("onPointerDown",A)),l(A=>a("onClick",A)),c(A=>a("onDoubleClick",A)),u(A=>a("onContextMenu",A)),v(A=>a("onWheel",A));let p=[];h(A=>{const b=A.intersections.map(({object:I})=>I),E=A.intersections;p.forEach(({object:I})=>{b.includes(I)||(A.intersections=p,a("onPointerLeave",A),a("onPointerOut",A))}),A.intersections=E,A.intersections.forEach(({object:I})=>{p.includes(I)||(a("onPointerEnter",A),a("onPointerOver",A))}),a("onPointerMove",A),p=A.intersections});const y=[];g(A=>{const b=()=>A.stopPropagating=!0;A.stopPropagation=b,y.forEach(E=>{A.stopPropagating||(A.eventObject=E,o(E.onPointerMissed,A))}),t("pointer-missed",{event:A})});function _(A){y.push(A)}function x(A){const b=y.indexOf(A);b>-1&&y.splice(b,1)}return e.eventManager={forceUpdate:m,registerPointerMissedObject:_,deregisterPointerMissedObject:x},{forceUpdate:m,registerPointerMissedObject:_,deregisterPointerMissedObject:x}}const{logError:zd}=eo(),Vd=["onClick","onContextMenu","onPointerMove","onPointerEnter","onPointerLeave","onPointerOver","onPointerOut","onDoubleClick","onPointerDown","onPointerUp","onPointerCancel","onPointerMissed","onLostPointerCapture","onWheel"];function Hd(s){var e;const t=(e=s==null?void 0:s.__tres)==null?void 0:e.root;t&&t.render&&t.render.canBeInvalidated.value&&t.invalidate()}const bw=()=>{let s=null;function e(l,c,u,h){if(h||(h={}),h.args||(h.args=[]),l==="template"||tw(l))return null;let d=l.replace("Tres",""),f;if(l==="primitive"){(h==null?void 0:h.object)===void 0&&zd("Tres primitives need a prop 'object'");const g=h.object;d=g.type,f=Object.assign(g.clone(),{type:d})}else{const g=Vc.value[d];g||zd(`${d} is not defined on the THREE namespace. Use extend to add it to the catalog.`),f=new g(...h.args)}return f?(f.isCamera&&(h!=null&&h.position||f.position.set(3,3,3),h!=null&&h.lookAt||f.lookAt(0,0,0)),(h==null?void 0:h.attach)===void 0&&(f.isMaterial?f.attach="material":f.isBufferGeometry&&(f.attach="geometry")),f.__tres={...f.__tres,type:d,memoizedProps:h,eventCount:0,disposable:!0,primitive:l==="primitive"},f.isObject3D&&f.__tres&&(h!=null&&h.material||h!=null&&h.geometry)&&(f.__tres.disposable=!1),f):null}function t(l,c){var u,h,d,f,g;if(!l)return;c&&c.isScene&&(s=c),s&&l.__tres&&(l.__tres.root=s.__tres.root);const v=c||s;if(l!=null&&l.isObject3D){const{registerCamera:m}=(u=l==null?void 0:l.__tres)==null?void 0:u.root;l!=null&&l.isCamera&&m(l),l.onPointerMissed&&(h=l==null?void 0:l.__tres)!=null&&h.root&&((g=(f=(d=l==null?void 0:l.__tres)==null?void 0:d.root)==null?void 0:f.eventManager)==null||g.registerPointerMissedObject(l))}l!=null&&l.isObject3D&&v!=null&&v.isObject3D?(v.add(l),l.dispatchEvent({type:"added"})):l!=null&&l.isFog?v.fog=l:typeof(l==null?void 0:l.attach)=="string"&&(l.__previousAttach=l[v==null?void 0:v.attach],v&&(v[l.attach]=l))}function n(l){var c,u,h,d;if(!l)return;const f=l.__tres;if(l.parent=l.parent||s,l.isObject3D){const g=v=>{var m,p;const y=(p=(m=l==null?void 0:l.__tres)==null?void 0:m.root)==null?void 0:p.deregisterCamera;v.isCamera&&(y==null||y(v))};(c=l.removeFromParent)==null||c.call(l),l.traverse(v=>{var m,p;g(v),v.onPointerMissed&&((p=(m=f==null?void 0:f.root)==null?void 0:m.eventManager)==null||p.deregisterPointerMissedObject(v))}),g(l),Hd(l),!((u=l.__tres)!=null&&u.primitive)&&(h=l.__tres)!=null&&h.disposable&&zu(l),(d=l.dispose)==null||d.call(l)}}function i(l,c,u,h){var d,f;if(l){let g=l,v=c;if((d=l==null?void 0:l.__tres)!=null&&d.primitive&&v==="object"&&u!==null){const _=e("primitive",void 0,void 0,{object:h});for(const x in _){if(x==="uuid")continue;const A=l[x],b=_[x];!(A!=null&&A.set)&&!na(A)?l[x]=b:A.constructor===b.constructor&&A!=null&&A.copy?A==null||A.copy(b):Array.isArray(b)?A.set(...b):!A.isColor&&A.setScalar?A.setScalar(b):A.set(b)}_!=null&&_.__tres&&(_.__tres.root=s==null?void 0:s.__tres.root),_!=null&&_.isGroup?(l.geometry=void 0,l.material=void 0):delete l.isGroup}if(l!=null&&l.isObject3D&&v==="blocks-pointer-events"){h||h===""?l[v]=h:delete l[v];return}Vd.includes(c)&&(l.__tres.eventCount+=1);let m=ea(v),p=g==null?void 0:g[m];if(v==="args"){const _=l,x=u??[],A=h??[],b=((f=l==null?void 0:l.__tres)==null?void 0:f.type)||l.type;b&&x.length&&!ow(x,A)&&(g=Object.assign(_,new Vc.value[b](...h)));return}if(g.type==="BufferGeometry"){if(v==="args")return;g.setAttribute(ea(v),new pt(...h));return}if(v.includes("-")&&p===void 0){const _=v.split("-");p=_.reduce((x,A)=>x[ea(A)],g),v=_.pop(),m=v,p!=null&&p.set||(g=_.reduce((x,A)=>x[ea(A)],g))}let y=h;if(y===""&&(y=!0),na(p)){Vd.includes(c)||(Array.isArray(y)?l[m](...y):l[m](y)),m.startsWith("on")&&na(y)&&(g[m]=y);return}!(p!=null&&p.set)&&!na(p)?g[m]=y:p.constructor===y.constructor&&p!=null&&p.copy?p==null||p.copy(y):Array.isArray(y)?p.set(...y):!p.isColor&&p.setScalar?p.setScalar(y):p.set(y),Hd(l)}}function r(l){return(l==null?void 0:l.parent)||null}function o(l){const c=new ct;return c.name=l,c.__tres={type:"Comment"},c.__tres.root=s==null?void 0:s.__tres.root,c}function a(l){if(!l)return null;const c=l.parent||s,u=c.children.indexOf(l);return c.children[u+1]||null}return{insert:t,remove:n,createElement:e,patchProp:i,parentNode:r,createText:()=>{},createComment:o,setText:()=>{},setElementText:()=>{},nextSibling:a,querySelector:()=>{},setScopeId:()=>{},cloneNode:()=>{},insertStaticContent:()=>{}}};function Sw(){return bm().__VUE_DEVTOOLS_GLOBAL_HOOK__}function bm(){return typeof navigator<"u"&&typeof window<"u"?window:typeof globalThis<"u"?globalThis:{}}const ww=typeof Proxy=="function",Aw="devtools-plugin:setup",Tw="plugin:settings:set";let ar,Gc;function Ew(){var s;return ar!==void 0||(typeof window<"u"&&window.performance?(ar=!0,Gc=window.performance):typeof globalThis<"u"&&!((s=globalThis.perf_hooks)===null||s===void 0)&&s.performance?(ar=!0,Gc=globalThis.perf_hooks.performance):ar=!1),ar}function Cw(){return Ew()?Gc.now():Date.now()}class Pw{constructor(e,t){this.target=null,this.targetQueue=[],this.onQueue=[],this.plugin=e,this.hook=t;const n={};if(e.settings)for(const o in e.settings){const a=e.settings[o];n[o]=a.defaultValue}const i=`__vue-devtools-plugin-settings__${e.id}`;let r=Object.assign({},n);try{const o=localStorage.getItem(i),a=JSON.parse(o);Object.assign(r,a)}catch{}this.fallbacks={getSettings(){return r},setSettings(o){try{localStorage.setItem(i,JSON.stringify(o))}catch{}r=o},now(){return Cw()}},t&&t.on(Tw,(o,a)=>{o===this.plugin.id&&this.fallbacks.setSettings(a)}),this.proxiedOn=new Proxy({},{get:(o,a)=>this.target?this.target.on[a]:(...l)=>{this.onQueue.push({method:a,args:l})}}),this.proxiedTarget=new Proxy({},{get:(o,a)=>this.target?this.target[a]:a==="on"?this.proxiedOn:Object.keys(this.fallbacks).includes(a)?(...l)=>(this.targetQueue.push({method:a,args:l,resolve:()=>{}}),this.fallbacks[a](...l)):(...l)=>new Promise(c=>{this.targetQueue.push({method:a,args:l,resolve:c})})})}async setRealTarget(e){this.target=e;for(const t of this.onQueue)this.target.on[t.method](...t.args);for(const t of this.targetQueue)t.resolve(await this.target[t.method](...t.args))}}function Rw(s,e){const t=s,n=bm(),i=Sw(),r=ww&&t.enableEarlyProxy;if(i&&(n.__VUE_DEVTOOLS_PLUGIN_API_AVAILABLE__||!r))i.emit(Aw,s,e);else{const o=r?new Pw(t,i):null;(n.__VUE_DEVTOOLS_PLUGINS__=n.__VUE_DEVTOOLS_PLUGINS__||[]).push({pluginDescriptor:t,setupFn:e,proxy:o}),o&&e(o.proxiedTarget)}}function Iw(s,e){const t=`▲ ■ ●${s}`;typeof Gd=="function"?Gd(t,e):console.log(t)}function Gd(s,e){throw new Error(s+e)}const Sm=s=>{const e={id:s.uuid,label:s.type,children:[],tags:[]};s.name!==""&&e.tags.push({label:s.name,textColor:5750629,backgroundColor:15793395});const t=Vu(s);return t>0&&e.tags.push({label:`${gw(t)} KB`,textColor:15707189,backgroundColor:16775644,tooltip:"Memory usage"}),s.type.includes("Light")&&(e.tags.push({label:`${s.intensity}`,textColor:9738662,backgroundColor:16316922,tooltip:"Intensity"}),e.tags.push({label:`#${s.color.getHexString()}`,textColor:9738662,backgroundColor:16316922,tooltip:"Color"})),s.type.includes("Camera")&&(e.tags.push({label:`${s.fov}°`,textColor:9738662,backgroundColor:16316922,tooltip:"Field of view"}),e.tags.push({label:`x: ${Math.round(s.position.x)} y: ${Math.round(s.position.y)} z: ${Math.round(s.position.z)}`,textColor:9738662,backgroundColor:16316922,tooltip:"Position"})),e};function wm(s,e,t=""){s.children.forEach(n=>{if(n.type==="HightlightMesh"||t&&!n.type.includes(t)&&!n.name.includes(t))return;const i=Sm(n);e.children.push(i),wm(n,i,t)})}const Lw=[],lr="tres:inspector",Nw=$m({sceneGraph:null});function Dw(s,e){Rw({id:"dev.esm.tres",label:"TresJS 🪐",logo:"https://raw.githubusercontent.com/Tresjs/tres/main/public/favicon.svg",packageName:"tresjs",homepage:"https://tresjs.org",componentStateTypes:Lw,app:s},t=>{typeof t.now!="function"&&Iw("You seem to be using an outdated version of Vue Devtools. Are you still using the Beta release instead of the stable one? You can find the links at https://devtools.vuejs.org/guide/installation.html."),t.addInspector({id:lr,label:"TresJS 🪐",icon:"account_tree",treeFilterPlaceholder:"Search instances"}),setInterval(()=>{t.sendInspectorTree(lr)},1e3),setInterval(()=>{t.notifyComponentUpdate()},5e3),t.on.getInspectorTree(r=>{if(r.inspectorId===lr){const o=Sm(e.scene.value);wm(e.scene.value,o,r.filter),Nw.sceneGraph=o,r.rootNodes=[o]}});let n=null,i=null;t.on.getInspectorState(r=>{var o;if(r.inspectorId===lr){const[a]=e.scene.value.getObjectsByProperty("uuid",r.nodeId);if(!a)return;if(i&&n&&n.parent&&i.remove(n),a.isMesh){const l=lw(a);a.add(l),n=l,i=a}r.state={object:[{key:"uuid",editable:!0,value:a.uuid},{key:"name",editable:!0,value:a.name},{key:"type",editable:!0,value:a.type},{key:"position",editable:!0,value:a.position},{key:"rotation",editable:!0,value:a.rotation},{key:"scale",editable:!0,value:a.scale},{key:"geometry",value:a.geometry},{key:"material",value:a.material},{key:"color",editable:!0,value:a.color},{key:"intensity",editable:!0,value:a.intensity},{key:"castShadow",editable:!0,value:a.castShadow},{key:"receiveShadow",editable:!0,value:a.receiveShadow},{key:"frustumCulled",editable:!0,value:a.frustumCulled},{key:"matrixAutoUpdate",editable:!0,value:a.matrixAutoUpdate},{key:"matrixWorldNeedsUpdate",editable:!0,value:a.matrixWorldNeedsUpdate},{key:"matrixWorld",value:a.matrixWorld},{key:"visible",editable:!0,value:a.visible}]},a.isScene&&(r.state.info={memory:Vu(a),objects:a.children.length,calls:e.renderer.value.info.render.calls,triangles:e.renderer.value.info.render.triangles,points:e.renderer.value.info.render.points,lines:e.renderer.value.info.render.lines},r.state.programs=((o=e.renderer.value.info.programs)==null?void 0:o.map(l=>({key:l.name,value:{...l,vertexShader:l.vertexShader,attributes:l.getAttributes(),uniforms:l.getUniforms()}})))||[])}}),t.on.editInspectorState(r=>{r.inspectorId===lr&&aw(e.scene.value,r.nodeId,r.path,r.state.value)})})}const Uw=["data-scene","data-tres"],Ow=Be({__name:"TresCanvas",props:{shadows:{type:Boolean,default:void 0},clearColor:{},toneMapping:{},shadowMapType:{},useLegacyLights:{type:Boolean,default:void 0},outputColorSpace:{},toneMappingExposure:{},renderMode:{default:"always"},camera:{},preset:{},windowSize:{type:Boolean,default:void 0},disableRender:{type:Boolean,default:void 0},context:{},precision:{},alpha:{type:Boolean,default:void 0},premultipliedAlpha:{type:Boolean},antialias:{type:Boolean,default:void 0},stencil:{type:Boolean,default:void 0},preserveDrawingBuffer:{type:Boolean,default:void 0},powerPreference:{},depth:{type:Boolean,default:void 0},logarithmicDepthBuffer:{type:Boolean,default:void 0},failIfMajorPerformanceCaveat:{type:Boolean,default:void 0}},emits:["render","click","double-click","context-menu","pointer-move","pointer-up","pointer-down","pointer-enter","pointer-leave","pointer-over","pointer-out","pointer-missed","wheel"],setup(s,{expose:e,emit:t}){var n;const i=s,r=t,o=Xd(),{logWarning:a}=eo(),l=Ge(),c=Rn(new Fa),u=(n=ma())==null?void 0:n.appContext.app;Hc(iS);const h=m=>Be({setup(){var p;const y=(p=ma())==null?void 0:p.appContext;return y&&(y.app=u),vr("useTres",m),vr("extend",Hc),typeof window<"u"&&Dw(y==null?void 0:y.app,m),()=>eh(xt,null,o!=null&&o.default?o.default():[])}}),d=m=>{const p=h(m),{render:y}=Xm(bw());y(eh(p),c.value)},f=(m,p=!1)=>{zu(m.scene.value),p&&(m.renderer.value.dispose(),m.renderer.value.renderLists.dispose(),m.renderer.value.forceContextLoss()),c.value.__tres={root:m},d(m)},g=ke(()=>i.disableRender),v=Rn(null);return e({context:v,dispose:()=>f(v.value,!0)}),Nn(()=>{const m=l;v.value=yw({scene:c.value,canvas:m,windowSize:i.windowSize??!1,disableRender:g.value??!1,rendererOptions:i,emit:r}),Mw(c.value,v.value,r);const{registerCamera:p,camera:y,cameras:_,deregisterCamera:x}=v.value;d(v.value);const A=()=>{const b=new Ut(45,window.innerWidth/window.innerHeight,.1,1e3);b.position.set(3,3,3),b.lookAt(0,0,0),p(b);const E=Ri(()=>{_.value.length>=2&&(b.removeFromParent(),x(b),E==null||E())})};Ct(()=>i.camera,(b,E)=>{b&&p(b),E&&(E.removeFromParent(),x(E))},{immediate:!0}),y.value||(a("No camera found. Creating a default perspective camera. To have full control over a camera, please add one to the scene."),A())}),Wn(()=>{f(v.value)}),(m,p)=>(Y(),fe("canvas",{ref_key:"canvas",ref:l,"data-scene":c.value.uuid,class:yt(m.$attrs.class),"data-tres":`tresjs ${j(XS).version}`,style:Yc({display:"block",width:"100%",height:"100%",position:m.windowSize?"fixed":"relative",top:0,left:0,pointerEvents:"auto",touchAction:"none",...m.$attrs.style})},null,14,Uw))}}),Fw=ln;class Sa extends on{constructor(e){super(e),this.defaultDPI=90,this.defaultUnit="px"}load(e,t,n,i){const r=this,o=new $n(r.manager);o.setPath(r.path),o.setRequestHeader(r.requestHeader),o.setWithCredentials(r.withCredentials),o.load(e,function(a){try{t(r.parse(a))}catch(l){i?i(l):console.error(l),r.manager.itemError(e)}},n,i)}parse(e){const t=this;function n(U,D){if(U.nodeType!==1)return;const R=x(U);let T=!1,ie=null;switch(U.nodeName){case"svg":D=g(U,D);break;case"style":r(U);break;case"g":D=g(U,D);break;case"path":D=g(U,D),U.hasAttribute("d")&&(ie=i(U));break;case"rect":D=g(U,D),ie=l(U);break;case"polygon":D=g(U,D),ie=c(U);break;case"polyline":D=g(U,D),ie=u(U);break;case"circle":D=g(U,D),ie=h(U);break;case"ellipse":D=g(U,D),ie=d(U);break;case"line":D=g(U,D),ie=f(U);break;case"defs":T=!0;break;case"use":D=g(U,D);const L=(U.getAttributeNS("http://www.w3.org/1999/xlink","href")||"").substring(1),X=U.viewportElement.getElementById(L);X?n(X,D):console.warn("SVGLoader: 'use node' references non-existent node id: "+L);break}ie&&(D.fill!==void 0&&D.fill!=="none"&&ie.color.setStyle(D.fill,Fw),b(ie,Ae),V.push(ie),ie.userData={node:U,style:D});const he=U.childNodes;for(let J=0;J0?Ae.copy(q[q.length-1]):Ae.identity())}function i(U){const D=new Si,R=new se,T=new se,ie=new se;let he=!0,J=!1;const L=U.getAttribute("d");if(L===""||L==="none")return null;const X=L.match(/[a-df-z][^a-df-z]*/ig);for(let K=0,H=X.length;K0&&(R.copy(ie),D.currentPath.currentPoint.copy(R),he=!0);break;default:console.warn($)}J=!1}return D}function r(U){if(!(!U.sheet||!U.sheet.cssRules||!U.sheet.cssRules.length))for(let D=0;Die.trim());for(let ie=0;ieJ!==""));G[T[ie]]=Object.assign(G[T[ie]]||{},he)}}}function o(U,D,R,T,ie,he,J,L){if(D==0||R==0){U.lineTo(L.x,L.y);return}T=T*Math.PI/180,D=Math.abs(D),R=Math.abs(R);const X=(J.x-L.x)/2,K=(J.y-L.y)/2,H=Math.cos(T)*X+Math.sin(T)*K,$=-Math.sin(T)*X+Math.cos(T)*K;let te=D*D,le=R*R;const k=H*H,O=$*$,P=k/te+O/le;if(P>1){const xe=Math.sqrt(P);D=xe*D,R=xe*R,te=D*D,le=R*R}const S=te*O+le*k,ee=(te*le-S)/S;let pe=Math.sqrt(Math.max(0,ee));ie===he&&(pe=-pe);const ce=pe*D*$/R,ve=-pe*R*H/D,Ve=Math.cos(T)*ce-Math.sin(T)*ve+(J.x+L.x)/2,Ee=Math.sin(T)*ce+Math.cos(T)*ve+(J.y+L.y)/2,Te=a(1,0,(H-ce)/D,($-ve)/R),Qe=a((H-ce)/D,($-ve)/R,(-H-ce)/D,(-$-ve)/R)%(Math.PI*2);U.currentPath.absellipse(Ve,Ee,D,R,Te,Te+Qe,he===0,T)}function a(U,D,R,T){const ie=U*R+D*T,he=Math.sqrt(U*U+D*D)*Math.sqrt(R*R+T*T);let J=Math.acos(Math.max(-1,Math.min(1,ie/he)));return U*T-D*R<0&&(J=-J),J}function l(U){const D=_(U.getAttribute("x")||0),R=_(U.getAttribute("y")||0),T=_(U.getAttribute("rx")||U.getAttribute("ry")||0),ie=_(U.getAttribute("ry")||U.getAttribute("rx")||0),he=_(U.getAttribute("width")),J=_(U.getAttribute("height")),L=1-.551915024494,X=new Si;return X.moveTo(D+T,R),X.lineTo(D+he-T,R),(T!==0||ie!==0)&&X.bezierCurveTo(D+he-T*L,R,D+he,R+ie*L,D+he,R+ie),X.lineTo(D+he,R+J-ie),(T!==0||ie!==0)&&X.bezierCurveTo(D+he,R+J-ie*L,D+he-T*L,R+J,D+he-T,R+J),X.lineTo(D+T,R+J),(T!==0||ie!==0)&&X.bezierCurveTo(D+T*L,R+J,D,R+J-ie*L,D,R+J-ie),X.lineTo(D,R+ie),(T!==0||ie!==0)&&X.bezierCurveTo(D,R+ie*L,D+T*L,R,D+T,R),X}function c(U){function D(he,J,L){const X=_(J),K=_(L);ie===0?T.moveTo(X,K):T.lineTo(X,K),ie++}const R=/([+-]?\d*\.?\d+(?:e[+-]?\d+)?)(?:,|\s)([+-]?\d*\.?\d+(?:e[+-]?\d+)?)/g,T=new Si;let ie=0;return U.getAttribute("points").replace(R,D),T.currentPath.autoClose=!0,T}function u(U){function D(he,J,L){const X=_(J),K=_(L);ie===0?T.moveTo(X,K):T.lineTo(X,K),ie++}const R=/([+-]?\d*\.?\d+(?:e[+-]?\d+)?)(?:,|\s)([+-]?\d*\.?\d+(?:e[+-]?\d+)?)/g,T=new Si;let ie=0;return U.getAttribute("points").replace(R,D),T.currentPath.autoClose=!1,T}function h(U){const D=_(U.getAttribute("cx")||0),R=_(U.getAttribute("cy")||0),T=_(U.getAttribute("r")||0),ie=new Ti;ie.absarc(D,R,T,0,Math.PI*2);const he=new Si;return he.subPaths.push(ie),he}function d(U){const D=_(U.getAttribute("cx")||0),R=_(U.getAttribute("cy")||0),T=_(U.getAttribute("rx")||0),ie=_(U.getAttribute("ry")||0),he=new Ti;he.absellipse(D,R,T,ie,0,Math.PI*2);const J=new Si;return J.subPaths.push(he),J}function f(U){const D=_(U.getAttribute("x1")||0),R=_(U.getAttribute("y1")||0),T=_(U.getAttribute("x2")||0),ie=_(U.getAttribute("y2")||0),he=new Si;return he.moveTo(D,R),he.lineTo(T,ie),he.currentPath.autoClose=!1,he}function g(U,D){D=Object.assign({},D);let R={};if(U.hasAttribute("class")){const J=U.getAttribute("class").split(/\s/).filter(Boolean).map(L=>L.trim());for(let L=0;L0&&D.premultiply(q[q.length-1]),Ae.copy(D),q.push(D),D}function A(U){const D=new Ze,R=ae;if(U.nodeName==="use"&&(U.hasAttribute("x")||U.hasAttribute("y"))){const T=_(U.getAttribute("x")),ie=_(U.getAttribute("y"));D.translate(T,ie)}if(U.hasAttribute("transform")){const T=U.getAttribute("transform").split(")");for(let ie=T.length-1;ie>=0;ie--){const he=T[ie].trim();if(he==="")continue;const J=he.indexOf("("),L=he.length;if(J>0&&J=1){const H=K[0];let $=0;K.length>=2&&($=K[1]),R.translate(H,$)}break;case"rotate":if(K.length>=1){let H=0,$=0,te=0;H=K[0]*Math.PI/180,K.length>=3&&($=K[1],te=K[2]),Q.makeTranslation(-$,-te),oe.makeRotation(H),B.multiplyMatrices(oe,Q),Q.makeTranslation($,te),R.multiplyMatrices(Q,B)}break;case"scale":if(K.length>=1){const H=K[0];let $=H;K.length>=2&&($=K[1]),R.scale(H,$)}break;case"skewX":K.length===1&&R.set(1,Math.tan(K[0]*Math.PI/180),0,0,1,0,0,0,1);break;case"skewY":K.length===1&&R.set(1,0,0,Math.tan(K[0]*Math.PI/180),1,0,0,0,1);break;case"matrix":K.length===6&&R.set(K[0],K[2],K[4],K[1],K[3],K[5],0,0,1);break}}D.premultiply(R)}}return D}function b(U,D){function R(J){be.set(J.x,J.y,1).applyMatrix3(D),J.set(be.x,be.y)}function T(J){const L=J.xRadius,X=J.yRadius,K=Math.cos(J.aRotation),H=Math.sin(J.aRotation),$=new N(L*K,L*H,0),te=new N(-X*H,X*K,0),le=$.applyMatrix3(D),k=te.applyMatrix3(D),O=ae.set(le.x,k.x,0,le.y,k.y,0,0,0,1),P=Q.copy(O).invert(),pe=oe.copy(P).transpose().multiply(P).elements,ce=F(pe[0],pe[1],pe[4]),ve=Math.sqrt(ce.rt1),Ve=Math.sqrt(ce.rt2);if(J.xRadius=1/ve,J.yRadius=1/Ve,J.aRotation=Math.atan2(ce.sn,ce.cs),!((J.aEndAngle-J.aStartAngle)%(2*Math.PI){const{x:Je,y:Re}=new N(Math.cos(st),Math.sin(st),0).applyMatrix3(xe);return Math.atan2(Re,Je)};J.aStartAngle=Ue(J.aStartAngle),J.aEndAngle=Ue(J.aEndAngle),E(D)&&(J.aClockwise=!J.aClockwise)}}function ie(J){const L=w(D),X=M(D);J.xRadius*=L,J.yRadius*=X;const K=L>Number.EPSILON?Math.atan2(D.elements[1],D.elements[0]):Math.atan2(-D.elements[3],D.elements[4]);J.aRotation+=K,E(D)&&(J.aStartAngle*=-1,J.aEndAngle*=-1,J.aClockwise=!J.aClockwise)}const he=U.subPaths;for(let J=0,L=he.length;JNumber.EPSILON}function w(U){const D=U.elements;return Math.sqrt(D[0]*D[0]+D[1]*D[1])}function M(U){const D=U.elements;return Math.sqrt(D[3]*D[3]+D[4]*D[4])}function F(U,D,R){let T,ie,he,J,L;const X=U+R,K=U-R,H=Math.sqrt(K*K+4*D*D);return X>0?(T=.5*(X+H),L=1/T,ie=U*L*R-D*L*D):X<0?ie=.5*(X-H):(T=.5*H,ie=-.5*H),K>0?he=K+H:he=K-H,Math.abs(he)>2*Math.abs(D)?(L=-2*D/he,J=1/Math.sqrt(1+L*L),he=L*J):Math.abs(D)===0?(he=1,J=0):(L=-.5*he/D,he=1/Math.sqrt(1+L*L),J=L*he),K>0&&(L=he,he=-J,J=L),{rt1:T,rt2:ie,cs:he,sn:J}}const V=[],G={},q=[],ae=new Ze,Q=new Ze,oe=new Ze,B=new Ze,Me=new se,be=new N,Ae=new Ze,ge=new DOMParser().parseFromString(e,"image/svg+xml");return n(ge.documentElement,{fill:"#000",fillOpacity:1,strokeOpacity:1,strokeWidth:1,strokeLineJoin:"miter",strokeLineCap:"butt",strokeMiterLimit:4}),{paths:V,xml:ge.documentElement}}static createShapes(e){const n={ORIGIN:0,DESTINATION:1,BETWEEN:2,LEFT:3,RIGHT:4,BEHIND:5,BEYOND:6},i={loc:n.ORIGIN,t:0};function r(v,m,p,y){const _=v.x,x=m.x,A=p.x,b=y.x,E=v.y,I=m.y,w=p.y,M=y.y,F=(b-A)*(E-w)-(M-w)*(_-A),V=(x-_)*(E-w)-(I-E)*(_-A),G=(M-w)*(x-_)-(b-A)*(I-E),q=F/G,ae=V/G;if(G===0&&F!==0||q<=0||q>=1||ae<0||ae>1)return null;if(F===0&&G===0){for(let Q=0;Q<2;Q++)if(o(Q===0?p:y,v,m),i.loc==n.ORIGIN){const oe=Q===0?p:y;return{x:oe.x,y:oe.y,t:i.t}}else if(i.loc==n.BETWEEN){const oe=+(_+i.t*(x-_)).toPrecision(10),B=+(E+i.t*(I-E)).toPrecision(10);return{x:oe,y:B,t:i.t}}return null}else{for(let B=0;B<2;B++)if(o(B===0?p:y,v,m),i.loc==n.ORIGIN){const Me=B===0?p:y;return{x:Me.x,y:Me.y,t:i.t}}const Q=+(_+q*(x-_)).toPrecision(10),oe=+(E+q*(I-E)).toPrecision(10);return{x:Q,y:oe,t:q}}}function o(v,m,p){const y=p.x-m.x,_=p.y-m.y,x=v.x-m.x,A=v.y-m.y,b=y*A-x*_;if(v.x===m.x&&v.y===m.y){i.loc=n.ORIGIN,i.t=0;return}if(v.x===p.x&&v.y===p.y){i.loc=n.DESTINATION,i.t=1;return}if(b<-Number.EPSILON){i.loc=n.LEFT;return}if(b>Number.EPSILON){i.loc=n.RIGHT;return}if(y*x<0||_*A<0){i.loc=n.BEHIND;return}if(Math.sqrt(y*y+_*_)M.t<=w.t+Number.EPSILON&&M.t>=w.t-Number.EPSILON)===void 0&&(p.push(w),y.push(new se(w.x,w.y)))}}return y}function l(v,m,p){const y=new se;m.getCenter(y);const _=[];return p.forEach(x=>{x.boundingBox.containsPoint(y)&&a(v,x.points).forEach(b=>{_.push({identifier:x.identifier,isCW:x.isCW,point:b})})}),_.sort((x,A)=>x.point.x-A.point.x),_}function c(v,m,p,y,_){(_==null||_==="")&&(_="nonzero");const x=new se;v.boundingBox.getCenter(x);const A=[new se(p,x.y),new se(y,x.y)],b=l(A,v.boundingBox,m);b.sort((V,G)=>V.point.x-G.point.x);const E=[],I=[];b.forEach(V=>{V.identifier===v.identifier?E.push(V):I.push(V)});const w=E[0].point.x,M=[];let F=0;for(;F0&&M[M.length-1]===I[F].identifier?M.pop():M.push(I[F].identifier),F++;if(M.push(v.identifier),_==="evenodd"){const V=M.length%2===0,G=M[M.length-2];return{identifier:v.identifier,isHole:V,for:G}}else if(_==="nonzero"){let V=!0,G=null,q=null;for(let ae=0;ae{const m=v.getPoints();let p=-999999999,y=999999999,_=-999999999,x=999999999;for(let A=0;Ap&&(p=b.y),b.y_&&(_=b.x),b.x=x&&(u=x-1),{curves:v.curves,points:m,isCW:Pn.isClockWise(m),identifier:-1,boundingBox:new pm(new se(x,y),new se(_,p))}});d=d.filter(v=>v.points.length>1);for(let v=0;vc(v,d,u,h,e.userData?e.userData.style.fillRule:void 0)),g=[];return d.forEach(v=>{if(!f[v.identifier].isHole){const p=new Ei;p.curves=v.curves,f.filter(_=>_.isHole&&_.for===v.identifier).forEach(_=>{const x=d[_.identifier],A=new Ti;A.curves=x.curves,p.holes.push(A)}),g.push(p)}}),g}static getStrokeStyle(e,t,n,i,r){return e=e!==void 0?e:1,t=t!==void 0?t:"#000",n=n!==void 0?n:"miter",i=i!==void 0?i:"butt",r=r!==void 0?r:4,{strokeColor:t,strokeWidth:e,strokeLineJoin:n,strokeLineCap:i,strokeMiterLimit:r}}static pointsToStroke(e,t,n,i){const r=[],o=[],a=[];if(Sa.pointsToStrokeWithBuffers(e,t,n,i,r,o,a)===0)return null;const l=new it;return l.setAttribute("position",new Ne(r,3)),l.setAttribute("normal",new Ne(o,3)),l.setAttribute("uv",new Ne(a,2)),l}static pointsToStrokeWithBuffers(e,t,n,i,r,o,a,l){const c=new se,u=new se,h=new se,d=new se,f=new se,g=new se,v=new se,m=new se,p=new se,y=new se,_=new se,x=new se,A=new se,b=new se,E=new se,I=new se,w=new se;n=n!==void 0?n:12,i=i!==void 0?i:.001,l=l!==void 0?l:0,e=K(e);const M=e.length;if(M<2)return 0;const F=e[0].equals(e[M-1]);let V,G=e[0],q;const ae=t.strokeWidth/2,Q=1/(M-1);let oe=0,B,Me,be,Ae,ge=!1,ze=0,U=l*3,D=l*2;R(e[0],e[1],c).multiplyScalar(ae),m.copy(e[0]).sub(c),p.copy(e[0]).add(c),y.copy(m),_.copy(p);for(let H=1;HNumber.EPSILON){const le=ae/te;h.multiplyScalar(-le),d.subVectors(V,G),f.copy(d).setLength(le).add(h),I.copy(f).negate();const k=f.length(),O=d.length();d.divideScalar(O),g.subVectors(q,V);const P=g.length();switch(g.divideScalar(P),d.dot(I)=i&&te.push(H[le]);return te.push(H[H.length-1]),te}}}const kw=`// +// Description : Array and textureless GLSL 2D/3D/4D simplex +// noise functions. +// Author : Ian McEwan, Ashima Arts. +// Maintainer : stegu +// Lastmod : 20201014 (stegu) +// License : Copyright (C) 2011 Ashima Arts. All rights reserved. +// Distributed under the MIT License. See LICENSE file. +// https://github.com/ashima/webgl-noise +// https://github.com/stegu/webgl-noise +// + +vec3 mod289(vec3 x) { + return x - floor(x * (1.0 / 289.0)) * 289.0; +} + +vec4 mod289(vec4 x) { + return x - floor(x * (1.0 / 289.0)) * 289.0; +} + +vec4 permute(vec4 x) { + return mod289(((x*34.0)+10.0)*x); +} + +vec4 taylorInvSqrt(vec4 r) +{ + return 1.79284291400159 - 0.85373472095314 * r; +} + +float snoise(vec3 v) + { + const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; + const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); + +// First corner + vec3 i = floor(v + dot(v, C.yyy) ); + vec3 x0 = v - i + dot(i, C.xxx) ; + +// Other corners + vec3 g = step(x0.yzx, x0.xyz); + vec3 l = 1.0 - g; + vec3 i1 = min( g.xyz, l.zxy ); + vec3 i2 = max( g.xyz, l.zxy ); + + // x0 = x0 - 0.0 + 0.0 * C.xxx; + // x1 = x0 - i1 + 1.0 * C.xxx; + // x2 = x0 - i2 + 2.0 * C.xxx; + // x3 = x0 - 1.0 + 3.0 * C.xxx; + vec3 x1 = x0 - i1 + C.xxx; + vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y + vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y + +// Permutations + i = mod289(i); + vec4 p = permute( permute( permute( + i.z + vec4(0.0, i1.z, i2.z, 1.0 )) + + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); + +// Gradients: 7x7 points over a square, mapped onto an octahedron. +// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) + float n_ = 0.142857142857; // 1.0/7.0 + vec3 ns = n_ * D.wyz - D.xzx; + + vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7) + + vec4 x_ = floor(j * ns.z); + vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N) + + vec4 x = x_ *ns.x + ns.yyyy; + vec4 y = y_ *ns.x + ns.yyyy; + vec4 h = 1.0 - abs(x) - abs(y); + + vec4 b0 = vec4( x.xy, y.xy ); + vec4 b1 = vec4( x.zw, y.zw ); + + //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; + //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; + vec4 s0 = floor(b0)*2.0 + 1.0; + vec4 s1 = floor(b1)*2.0 + 1.0; + vec4 sh = -step(h, vec4(0.0)); + + vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ; + vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ; + + vec3 p0 = vec3(a0.xy,h.x); + vec3 p1 = vec3(a0.zw,h.y); + vec3 p2 = vec3(a1.xy,h.z); + vec3 p3 = vec3(a1.zw,h.w); + +//Normalise gradients + vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; + +// Mix final noise value + vec4 m = max(0.5 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); + m = m * m; + return 105.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), + dot(p2,x2), dot(p3,x3) ) ); + } + +// demo code: +// float color(vec2 xy) { return 0.7 * snoise(vec3(xy, 0.3*iTime)); } +// void mainImage(out vec4 fragColor, in vec2 fragCoord) { +// vec2 p = (fragCoord.xy/iResolution.y) * 2.0 - 1.0; + +// vec3 xyz = vec3(p, 0); + +// vec2 step = vec2(1.3, 1.7); +// float n = color(xyz.xy); +// n += 0.5 * color(xyz.xy * 2.0 - step); +// n += 0.25 * color(xyz.xy * 4.0 - 2.0 * step); +// n += 0.125 * color(xyz.xy * 8.0 - 3.0 * step); +// n += 0.0625 * color(xyz.xy * 16.0 - 4.0 * step); +// n += 0.03125 * color(xyz.xy * 32.0 - 5.0 * step); + +// fragColor.xyz = vec3(0.5 + 0.5 * vec3(n, n, n)); + +// } +`,Bw=` +varying vec2 vUv; + +void main() { + vec4 modelPosition = modelMatrix * vec4(position, 1.0); + vec4 viewPosition = viewMatrix * modelPosition; + gl_Position = projectionMatrix * viewPosition; + vUv = uv; +} +`,zw=Be({__name:"Background",props:{mask:{}},async setup(s){let e,t;const n=s,{renderer:i,sizes:r}=xw(),{paths:o}=([e,t]=qm(()=>pw(Sa,"/circuit-board.svg")),e=await e,t(),e),a=o.map(p=>Sa.createShapes(p)).reduce((p,y)=>[...p,...y]),l=ke(()=>Math.ceil(r.height.value/304)),c=ke(()=>Math.ceil(r.width.value/304)),u=Ge(new se(1/0,1/0));function h(p){const{x:y,y:_,height:x}=i.value.domElement.getBoundingClientRect();u.value=new se(p.screenX-y,x+_+(window.outerHeight-window.innerHeight)-p.screenY),g.value&&g.value.children.forEach(A=>{A.material.uniforms.uMouse.value=u.value})}function d(p){p.relatedTarget||(u.value=new se(1/0,1/0),g.value&&g.value.children.forEach(y=>{y.material.uniforms.uMouse.value=u.value}))}Nn(()=>{window.addEventListener("mousemove",h),window.addEventListener("mouseout",d)}),Wn(()=>{window.removeEventListener("mousemove",h),window.removeEventListener("mouseout",d)});const{onLoop:f}=KS();f(({elapsed:p})=>{g.value&&g.value.children.forEach(y=>{y.material.uniforms.uTime.value=p})});const g=Rn(null),v={uColor:ke(()=>n.mask==null?new N:new N(.23,.26,.32)),uTime:{value:0},uMouse:{value:new se(1/0,1/0)}},m=` +${kw} +precision mediump float; +uniform float uTime; +uniform vec2 uMouse; +uniform vec3 uColor; +varying vec2 vUv; + +void main() { + float dist = distance(gl_FragCoord.xy, uMouse); + float alpha = max(0., 1. - dist / 304.); + alpha += max(0., snoise(vec3(gl_FragCoord.xy / 304., uTime / 4.))); + gl_FragColor = vec4(mix(uColor, vec3(0.), alpha), uColor == vec3(0.) ? alpha : 1.); +} +`;return(p,y)=>{const _=cn("TresShapeGeometry"),x=cn("TresShaderMaterial"),A=cn("TresMesh"),b=cn("TresGroup");return j(i)?(Y(),$e(b,{key:0,ref_key:"groupRef",ref:g,renderOrder:1},{default:ye(()=>[(Y(!0),fe(xt,null,Jt(l.value*c.value,E=>(Y(),$e(A,{position:[(E%c.value-c.value/2)*304,(Math.floor((E-1)/c.value)-l.value/2)*304,1]},{default:ye(()=>[Fe(_,{args:[j(a)]},null,8,["args"]),Fe(x,{vertexShader:Bw,fragmentShader:m,uniforms:v,blending:j(ga),stencilWrite:p.mask!=null,stencilRef:p.mask??0,stencilFunc:j(Zf),stencilFail:j(Bn),stencilZFail:j(Bn),stencilZPass:j(Bn)},null,8,["blending","stencilWrite","stencilRef","stencilFunc","stencilFail","stencilZFail","stencilZPass"])]),_:2},1032,["position"]))),256))]),_:1},512)):De("",!0)}}}),Vw=Be({__name:"VPBadge",props:{text:{},type:{default:"tip"}},setup(s){return(e,t)=>(Y(),fe("span",{class:yt(["VPBadge",e.type])},[ue(e.$slots,"default",{},()=>[Ht(ft(e.text),1)])],2))}}),Hw={key:0,class:"VPBackdrop"},Gw=Be({__name:"VPBackdrop",props:{show:{type:Boolean}},setup(s){return(e,t)=>(Y(),$e(Zc,{name:"fade"},{default:ye(()=>[e.show?(Y(),fe("div",Hw)):De("",!0)]),_:1}))}}),Ww=Ye(Gw,[["__scopeId","data-v-c79a1216"]]),ot=Ym;function $w(s,e){let t,n=!1;return()=>{t&&clearTimeout(t),n?t=setTimeout(s,e):(s(),(n=!0)&&setTimeout(()=>n=!1,e))}}function Wc(s){return/^\//.test(s)?s:`/${s}`}function Hu(s){const{pathname:e,search:t,hash:n,protocol:i}=new URL(s,"http://a.com");if(Zm(s)||s.startsWith("#")||!i.startsWith("http")||!Jm(e))return s;const{site:r}=ot(),o=e.endsWith("/")||e.endsWith(".html")?s:s.replace(/(?:(^\.+)\/)?.*$/,`$1${e.replace(/(\.md)?$/,r.value.cleanUrls?"":".html")}${t}${n}`);return Jc(o)}function to({correspondingLink:s=!1}={}){const{site:e,localeIndex:t,page:n,theme:i,hash:r}=ot(),o=ke(()=>{var l,c;return{label:(l=e.value.locales[t.value])==null?void 0:l.label,link:((c=e.value.locales[t.value])==null?void 0:c.link)||(t.value==="root"?"/":`/${t.value}/`)}});return{localeLinks:ke(()=>Object.entries(e.value.locales).flatMap(([l,c])=>o.value.label===c.label?[]:{text:c.label,link:Xw(c.link||(l==="root"?"/":`/${l}/`),i.value.i18nRouting!==!1&&s,n.value.relativePath.slice(o.value.link.length-1),!e.value.cleanUrls)+r.value})),currentLang:o}}function Xw(s,e,t,n){return e?s.replace(/\/$/,"")+Wc(t.replace(/(^|\/)index\.md$/,"$1").replace(/\.md$/,n?".html":"")):s}const qw=s=>(Wt("data-v-d6be1790"),s=s(),$t(),s),Yw={class:"NotFound"},Zw={class:"code"},Jw={class:"title"},Kw=qw(()=>me("div",{class:"divider"},null,-1)),jw={class:"quote"},Qw={class:"action"},e1=["href","aria-label"],t1=Be({__name:"NotFound",setup(s){const{theme:e}=ot(),{currentLang:t}=to();return(n,i)=>{var r,o,a,l,c;return Y(),fe("div",Yw,[me("p",Zw,ft(((r=j(e).notFound)==null?void 0:r.code)??"404"),1),me("h1",Jw,ft(((o=j(e).notFound)==null?void 0:o.title)??"PAGE NOT FOUND"),1),Kw,me("blockquote",jw,ft(((a=j(e).notFound)==null?void 0:a.quote)??"But if you don't change your direction, and if you keep looking, you may end up where you are heading."),1),me("div",Qw,[me("a",{class:"link",href:j(Jc)(j(t).link),"aria-label":((l=j(e).notFound)==null?void 0:l.linkLabel)??"go to home"},ft(((c=j(e).notFound)==null?void 0:c.linkText)??"Take me home"),9,e1)])])}}}),n1=Ye(t1,[["__scopeId","data-v-d6be1790"]]);function Am(s,e){if(Array.isArray(s))return pa(s);if(s==null)return[];e=Wc(e);const t=Object.keys(s).sort((i,r)=>r.split("/").length-i.split("/").length).find(i=>e.startsWith(Wc(i))),n=t?s[t]:[];return Array.isArray(n)?pa(n):pa(n.items,n.base)}function i1(s){const e=[];let t=0;for(const n in s){const i=s[n];if(i.items){t=e.push(i);continue}e[t]||e.push({items:[]}),e[t].items.push(i)}return e}function s1(s){const e=[];function t(n){for(const i of n)i.text&&i.link&&e.push({text:i.text,link:i.link,docFooterText:i.docFooterText}),i.items&&t(i.items)}return t(s),e}function $c(s,e){return Array.isArray(e)?e.some(t=>$c(s,t)):is(s,e.link)?!0:e.items?$c(s,e.items):!1}function pa(s,e){return[...s].map(t=>{const n={...t},i=n.base||e;return i&&n.link&&(n.link=i+n.link),n.items&&(n.items=pa(n.items,i)),n})}function fi(){const{frontmatter:s,page:e,theme:t}=ot(),n=Kl("(min-width: 960px)"),i=Ge(!1),r=ke(()=>{const v=t.value.sidebar,m=e.value.relativePath;return v?Am(v,m):[]}),o=Ge(r.value);Ct(r,(v,m)=>{JSON.stringify(v)!==JSON.stringify(m)&&(o.value=r.value)});const a=ke(()=>s.value.sidebar!==!1&&o.value.length>0&&s.value.layout!=="home"),l=ke(()=>c?s.value.aside==null?t.value.aside==="left":s.value.aside==="left":!1),c=ke(()=>s.value.layout==="home"?!1:s.value.aside!=null?!!s.value.aside:t.value.aside!==!1),u=ke(()=>a.value&&n.value),h=ke(()=>a.value?i1(o.value):[]);function d(){i.value=!0}function f(){i.value=!1}function g(){i.value?f():d()}return{isOpen:i,sidebar:o,sidebarGroups:h,hasSidebar:a,hasAside:c,leftAside:l,isSidebarEnabled:u,open:d,close:f,toggle:g}}function r1(s,e){let t;Ri(()=>{t=s.value?document.activeElement:void 0}),Nn(()=>{window.addEventListener("keyup",n)}),Wn(()=>{window.removeEventListener("keyup",n)});function n(i){i.key==="Escape"&&s.value&&(e(),t==null||t.focus())}}function o1(s){const{page:e,hash:t}=ot(),n=Ge(!1),i=ke(()=>s.value.collapsed!=null),r=ke(()=>!!s.value.link),o=Ge(!1),a=()=>{o.value=is(e.value.relativePath,s.value.link)};Ct([e,s,t],a),Nn(a);const l=ke(()=>o.value?!0:s.value.items?$c(e.value.relativePath,s.value.items):!1),c=ke(()=>!!(s.value.items&&s.value.items.length));Ri(()=>{n.value=!!(i.value&&s.value.collapsed)}),qd(()=>{(o.value||l.value)&&(n.value=!1)});function u(){i.value&&(n.value=!n.value)}return{collapsed:n,collapsible:i,isLink:r,isActiveLink:o,hasActiveLink:l,hasChildren:c,toggle:u}}function a1(){const{hasSidebar:s}=fi(),e=Kl("(min-width: 960px)"),t=Kl("(min-width: 1280px)");return{isAsideEnabled:ke(()=>!t.value&&!e.value?!1:s.value?t.value:e.value)}}const Xc=[];function Tm(s){return typeof s.outline=="object"&&!Array.isArray(s.outline)&&s.outline.label||s.outlineTitle||"On this page"}function Gu(s){const e=[...document.querySelectorAll(".VPDoc :where(h1,h2,h3,h4,h5,h6)")].filter(t=>t.id&&t.hasChildNodes()).map(t=>{const n=Number(t.tagName[1]);return{element:t,title:l1(t),link:"#"+t.id,level:n}});return c1(e,s)}function l1(s){let e="";for(const t of s.childNodes)if(t.nodeType===1){if(t.classList.contains("VPBadge")||t.classList.contains("header-anchor")||t.classList.contains("ignore-header"))continue;e+=t.textContent}else t.nodeType===3&&(e+=t.textContent);return e.trim()}function c1(s,e){if(e===!1)return[];const t=(typeof e=="object"&&!Array.isArray(e)?e.level:e)||2,[n,i]=typeof t=="number"?[t,t]:t==="deep"?[2,6]:t;s=s.filter(o=>o.level>=n&&o.level<=i),Xc.length=0;for(const{element:o,link:a}of s)Xc.push({element:o,link:a});const r=[];e:for(let o=0;o=0;l--){const c=s[l];if(c.level{requestAnimationFrame(r),window.addEventListener("scroll",n)}),Km(()=>{o(location.hash)}),Wn(()=>{window.removeEventListener("scroll",n)});function r(){if(!t.value)return;const a=window.scrollY,l=window.innerHeight,c=document.body.offsetHeight,u=Math.abs(a+l-c)<1,h=Xc.map(({element:f,link:g})=>({link:g,top:h1(f)})).filter(({top:f})=>!Number.isNaN(f)).sort((f,g)=>f.top-g.top);if(!h.length){o(null);return}if(a<1){o(null);return}if(u){o(h[h.length-1].link);return}let d=null;for(const{link:f,top:g}of h){if(g>a+jm()+4)break;d=f}o(d)}function o(a){i&&i.classList.remove("active"),a==null?i=null:i=s.value.querySelector(`a[href="${decodeURIComponent(a)}"]`);const l=i;l?(l.classList.add("active"),e.value.style.top=l.offsetTop+39+"px",e.value.style.opacity="1"):(e.value.style.top="33px",e.value.style.opacity="0")}}function h1(s){let e=0;for(;s!==document.body;){if(s===null)return NaN;e+=s.offsetTop,s=s.offsetParent}return e}const d1=["href","title"],f1=Be({__name:"VPDocOutlineItem",props:{headers:{},root:{type:Boolean}},setup(s){function e({target:t}){const n=t.href.split("#")[1],i=document.getElementById(decodeURIComponent(n));i==null||i.focus({preventScroll:!0})}return(t,n)=>{const i=cn("VPDocOutlineItem",!0);return Y(),fe("ul",{class:yt(["VPDocOutlineItem",t.root?"root":"nested"])},[(Y(!0),fe(xt,null,Jt(t.headers,({children:r,link:o,title:a})=>(Y(),fe("li",null,[me("a",{class:"outline-link",href:o,onClick:e,title:a},ft(a),9,d1),r!=null&&r.length?(Y(),$e(i,{key:0,headers:r},null,8,["headers"])):De("",!0)]))),256))],2)}}}),Em=Ye(f1,[["__scopeId","data-v-b933a997"]]),p1={class:"content"},m1={"aria-level":"2",class:"outline-title",id:"doc-outline-aria-label",role:"heading"},g1=Be({__name:"VPDocAsideOutline",setup(s){const{frontmatter:e,theme:t}=ot(),n=Rn([]);Aa(()=>{n.value=Gu(e.value.outline??t.value.outline)});const i=Ge(),r=Ge();return u1(i,r),(o,a)=>(Y(),fe("nav",{"aria-labelledby":"doc-outline-aria-label",class:yt(["VPDocAsideOutline",{"has-outline":n.value.length>0}]),ref_key:"container",ref:i},[me("div",p1,[me("div",{class:"outline-marker",ref_key:"marker",ref:r},null,512),me("div",m1,ft(j(Tm)(j(t))),1),Fe(Em,{headers:n.value,root:!0},null,8,["headers"])])],2))}}),v1=Ye(g1,[["__scopeId","data-v-a5bbad30"]]),_1={class:"VPDocAsideCarbonAds"},y1=Be({__name:"VPDocAsideCarbonAds",props:{carbonAds:{}},setup(s){const e=()=>null;return(t,n)=>(Y(),fe("div",_1,[Fe(j(e),{"carbon-ads":t.carbonAds},null,8,["carbon-ads"])]))}}),x1=s=>(Wt("data-v-3f215769"),s=s(),$t(),s),M1={class:"VPDocAside"},b1=x1(()=>me("div",{class:"spacer"},null,-1)),S1=Be({__name:"VPDocAside",setup(s){const{theme:e}=ot();return(t,n)=>(Y(),fe("div",M1,[ue(t.$slots,"aside-top",{},void 0,!0),ue(t.$slots,"aside-outline-before",{},void 0,!0),Fe(v1),ue(t.$slots,"aside-outline-after",{},void 0,!0),b1,ue(t.$slots,"aside-ads-before",{},void 0,!0),j(e).carbonAds?(Y(),$e(y1,{key:0,"carbon-ads":j(e).carbonAds},null,8,["carbon-ads"])):De("",!0),ue(t.$slots,"aside-ads-after",{},void 0,!0),ue(t.$slots,"aside-bottom",{},void 0,!0)]))}}),w1=Ye(S1,[["__scopeId","data-v-3f215769"]]);function A1(){const{theme:s,page:e}=ot();return ke(()=>{const{text:t="Edit this page",pattern:n=""}=s.value.editLink||{};let i;return typeof n=="function"?i=n(e.value):i=n.replace(/:path/g,e.value.filePath),{url:i,text:t}})}function T1(){const{page:s,theme:e,frontmatter:t}=ot();return ke(()=>{var c,u,h,d,f,g,v,m;const n=Am(e.value.sidebar,s.value.relativePath),i=s1(n),r=E1(i,p=>p.link.replace(/[?#].*$/,"")),o=r.findIndex(p=>is(s.value.relativePath,p.link)),a=((c=e.value.docFooter)==null?void 0:c.prev)===!1&&!t.value.prev||t.value.prev===!1,l=((u=e.value.docFooter)==null?void 0:u.next)===!1&&!t.value.next||t.value.next===!1;return{prev:a?void 0:{text:(typeof t.value.prev=="string"?t.value.prev:typeof t.value.prev=="object"?t.value.prev.text:void 0)??((h=r[o-1])==null?void 0:h.docFooterText)??((d=r[o-1])==null?void 0:d.text),link:(typeof t.value.prev=="object"?t.value.prev.link:void 0)??((f=r[o-1])==null?void 0:f.link)},next:l?void 0:{text:(typeof t.value.next=="string"?t.value.next:typeof t.value.next=="object"?t.value.next.text:void 0)??((g=r[o+1])==null?void 0:g.docFooterText)??((v=r[o+1])==null?void 0:v.text),link:(typeof t.value.next=="object"?t.value.next.link:void 0)??((m=r[o+1])==null?void 0:m.link)}}})}function E1(s,e){const t=new Set;return s.filter(n=>{const i=e(n);return t.has(i)?!1:t.add(i)})}const Gn=Be({__name:"VPLink",props:{tag:{},href:{},noIcon:{type:Boolean},target:{},rel:{}},setup(s){const e=s,t=ke(()=>e.tag??(e.href?"a":"span")),n=ke(()=>e.href&&Yd.test(e.href)||e.target==="_blank");return(i,r)=>(Y(),$e(Bs(t.value),{class:yt(["VPLink",{link:i.href,"vp-external-link-icon":n.value,"no-icon":i.noIcon}]),href:i.href?j(Hu)(i.href):void 0,target:i.target??(n.value?"_blank":void 0),rel:i.rel??(n.value?"noreferrer":void 0)},{default:ye(()=>[ue(i.$slots,"default")]),_:3},8,["class","href","target","rel"]))}}),C1={class:"VPLastUpdated"},P1=["datetime"],R1=Be({__name:"VPDocFooterLastUpdated",setup(s){const{theme:e,page:t,frontmatter:n,lang:i}=ot(),r=ke(()=>new Date(n.value.lastUpdated??t.value.lastUpdated)),o=ke(()=>r.value.toISOString()),a=Ge("");return Nn(()=>{Ri(()=>{var l,c,u;a.value=new Intl.DateTimeFormat((c=(l=e.value.lastUpdated)==null?void 0:l.formatOptions)!=null&&c.forceLocale?i.value:void 0,((u=e.value.lastUpdated)==null?void 0:u.formatOptions)??{dateStyle:"short",timeStyle:"short"}).format(r.value)})}),(l,c)=>{var u;return Y(),fe("p",C1,[Ht(ft(((u=j(e).lastUpdated)==null?void 0:u.text)||j(e).lastUpdatedText||"Last updated")+": ",1),me("time",{datetime:o.value},ft(a.value),9,P1)])}}}),I1=Ye(R1,[["__scopeId","data-v-7e05ebdb"]]),Cm=s=>(Wt("data-v-d4a0bba5"),s=s(),$t(),s),L1={key:0,class:"VPDocFooter"},N1={key:0,class:"edit-info"},D1={key:0,class:"edit-link"},U1=Cm(()=>me("span",{class:"vpi-square-pen edit-link-icon"},null,-1)),O1={key:1,class:"last-updated"},F1={key:1,class:"prev-next","aria-labelledby":"doc-footer-aria-label"},k1=Cm(()=>me("span",{class:"visually-hidden",id:"doc-footer-aria-label"},"Pager",-1)),B1={class:"pager"},z1=["innerHTML"],V1=["innerHTML"],H1={class:"pager"},G1=["innerHTML"],W1=["innerHTML"],$1=Be({__name:"VPDocFooter",setup(s){const{theme:e,page:t,frontmatter:n}=ot(),i=A1(),r=T1(),o=ke(()=>e.value.editLink&&n.value.editLink!==!1),a=ke(()=>t.value.lastUpdated&&n.value.lastUpdated!==!1),l=ke(()=>o.value||a.value||r.value.prev||r.value.next);return(c,u)=>{var h,d,f,g;return l.value?(Y(),fe("footer",L1,[ue(c.$slots,"doc-footer-before",{},void 0,!0),o.value||a.value?(Y(),fe("div",N1,[o.value?(Y(),fe("div",D1,[Fe(Gn,{class:"edit-link-button",href:j(i).url,"no-icon":!0},{default:ye(()=>[U1,Ht(" "+ft(j(i).text),1)]),_:1},8,["href"])])):De("",!0),a.value?(Y(),fe("div",O1,[Fe(I1)])):De("",!0)])):De("",!0),(h=j(r).prev)!=null&&h.link||(d=j(r).next)!=null&&d.link?(Y(),fe("nav",F1,[k1,me("div",B1,[(f=j(r).prev)!=null&&f.link?(Y(),$e(Gn,{key:0,class:"pager-link prev",href:j(r).prev.link},{default:ye(()=>{var v;return[me("span",{class:"desc",innerHTML:((v=j(e).docFooter)==null?void 0:v.prev)||"Previous page"},null,8,z1),me("span",{class:"title",innerHTML:j(r).prev.text},null,8,V1)]}),_:1},8,["href"])):De("",!0)]),me("div",H1,[(g=j(r).next)!=null&&g.link?(Y(),$e(Gn,{key:0,class:"pager-link next",href:j(r).next.link},{default:ye(()=>{var v;return[me("span",{class:"desc",innerHTML:((v=j(e).docFooter)==null?void 0:v.next)||"Next page"},null,8,G1),me("span",{class:"title",innerHTML:j(r).next.text},null,8,W1)]}),_:1},8,["href"])):De("",!0)])])):De("",!0)])):De("",!0)}}}),X1=Ye($1,[["__scopeId","data-v-d4a0bba5"]]),q1=s=>(Wt("data-v-39a288b8"),s=s(),$t(),s),Y1={class:"container"},Z1=q1(()=>me("div",{class:"aside-curtain"},null,-1)),J1={class:"aside-container"},K1={class:"aside-content"},j1={class:"content"},Q1={class:"content-container"},eA={class:"main"},tA=Be({__name:"VPDoc",setup(s){const{theme:e}=ot(),t=Vr(),{hasSidebar:n,hasAside:i,leftAside:r}=fi(),o=ke(()=>t.path.replace(/[./]+/g,"_").replace(/_html$/,""));return(a,l)=>{const c=cn("Content");return Y(),fe("div",{class:yt(["VPDoc",{"has-sidebar":j(n),"has-aside":j(i)}])},[ue(a.$slots,"doc-top",{},void 0,!0),me("div",Y1,[j(i)?(Y(),fe("div",{key:0,class:yt(["aside",{"left-aside":j(r)}])},[Z1,me("div",J1,[me("div",K1,[Fe(w1,null,{"aside-top":ye(()=>[ue(a.$slots,"aside-top",{},void 0,!0)]),"aside-bottom":ye(()=>[ue(a.$slots,"aside-bottom",{},void 0,!0)]),"aside-outline-before":ye(()=>[ue(a.$slots,"aside-outline-before",{},void 0,!0)]),"aside-outline-after":ye(()=>[ue(a.$slots,"aside-outline-after",{},void 0,!0)]),"aside-ads-before":ye(()=>[ue(a.$slots,"aside-ads-before",{},void 0,!0)]),"aside-ads-after":ye(()=>[ue(a.$slots,"aside-ads-after",{},void 0,!0)]),_:3})])])],2)):De("",!0),me("div",j1,[me("div",Q1,[ue(a.$slots,"doc-before",{},void 0,!0),me("main",eA,[Fe(c,{class:yt(["vp-doc",[o.value,j(e).externalLinkIcon&&"external-link-icon-enabled"]])},null,8,["class"])]),Fe(X1,null,{"doc-footer-before":ye(()=>[ue(a.$slots,"doc-footer-before",{},void 0,!0)]),_:3}),ue(a.$slots,"doc-after",{},void 0,!0)])])]),ue(a.$slots,"doc-bottom",{},void 0,!0)],2)}}}),nA=Ye(tA,[["__scopeId","data-v-39a288b8"]]),iA=Be({__name:"VPButton",props:{tag:{},size:{default:"medium"},theme:{default:"brand"},text:{},href:{},target:{},rel:{}},setup(s){const e=s,t=ke(()=>e.href&&Yd.test(e.href)),n=ke(()=>e.tag||e.href?"a":"button");return(i,r)=>(Y(),$e(Bs(n.value),{class:yt(["VPButton",[i.size,i.theme]]),href:i.href?j(Hu)(i.href):void 0,target:e.target??(t.value?"_blank":void 0),rel:e.rel??(t.value?"noreferrer":void 0)},{default:ye(()=>[Ht(ft(i.text),1)]),_:1},8,["class","href","target","rel"]))}}),sA=Ye(iA,[["__scopeId","data-v-cad61b99"]]),rA=["src","alt"],oA=Be({inheritAttrs:!1,__name:"VPImage",props:{image:{},alt:{}},setup(s){return(e,t)=>{const n=cn("VPImage",!0);return e.image?(Y(),fe(xt,{key:0},[typeof e.image=="string"||"src"in e.image?(Y(),fe("img",ia({key:0,class:"VPImage"},typeof e.image=="string"?e.$attrs:{...e.image,...e.$attrs},{src:j(Jc)(typeof e.image=="string"?e.image:e.image.src),alt:e.alt??(typeof e.image=="string"?"":e.image.alt||"")}),null,16,rA)):(Y(),fe(xt,{key:1},[Fe(n,ia({class:"dark",image:e.image.dark,alt:e.image.alt},e.$attrs),null,16,["image","alt"]),Fe(n,ia({class:"light",image:e.image.light,alt:e.image.alt},e.$attrs),null,16,["image","alt"])],64))],64)):De("",!0)}}}),wa=Ye(oA,[["__scopeId","data-v-8426fc1a"]]),aA=s=>(Wt("data-v-303bb580"),s=s(),$t(),s),lA={class:"container"},cA={class:"main"},uA={key:0,class:"name"},hA=["innerHTML"],dA=["innerHTML"],fA=["innerHTML"],pA={key:0,class:"actions"},mA={key:0,class:"image"},gA={class:"image-container"},vA=aA(()=>me("div",{class:"image-bg"},null,-1)),_A=Be({__name:"VPHero",props:{name:{},text:{},tagline:{},image:{},actions:{}},setup(s){const e=zr("hero-image-slot-exists");return(t,n)=>(Y(),fe("div",{class:yt(["VPHero",{"has-image":t.image||j(e)}])},[me("div",lA,[me("div",cA,[ue(t.$slots,"home-hero-info-before",{},void 0,!0),ue(t.$slots,"home-hero-info",{},()=>[t.name?(Y(),fe("h1",uA,[me("span",{innerHTML:t.name,class:"clip"},null,8,hA)])):De("",!0),t.text?(Y(),fe("p",{key:1,innerHTML:t.text,class:"text"},null,8,dA)):De("",!0),t.tagline?(Y(),fe("p",{key:2,innerHTML:t.tagline,class:"tagline"},null,8,fA)):De("",!0)],!0),ue(t.$slots,"home-hero-info-after",{},void 0,!0),t.actions?(Y(),fe("div",pA,[(Y(!0),fe(xt,null,Jt(t.actions,i=>(Y(),fe("div",{key:i.link,class:"action"},[Fe(sA,{tag:"a",size:"medium",theme:i.theme,text:i.text,href:i.link,target:i.target,rel:i.rel},null,8,["theme","text","href","target","rel"])]))),128))])):De("",!0),ue(t.$slots,"home-hero-actions-after",{},void 0,!0)]),t.image||j(e)?(Y(),fe("div",mA,[me("div",gA,[vA,ue(t.$slots,"home-hero-image",{},()=>[t.image?(Y(),$e(wa,{key:0,class:"image-src",image:t.image},null,8,["image"])):De("",!0)],!0)])])):De("",!0)])],2))}}),yA=Ye(_A,[["__scopeId","data-v-303bb580"]]),xA=Be({__name:"VPHomeHero",setup(s){const{frontmatter:e}=ot();return(t,n)=>j(e).hero?(Y(),$e(yA,{key:0,class:"VPHomeHero",name:j(e).hero.name,text:j(e).hero.text,tagline:j(e).hero.tagline,image:j(e).hero.image,actions:j(e).hero.actions},{"home-hero-info-before":ye(()=>[ue(t.$slots,"home-hero-info-before")]),"home-hero-info":ye(()=>[ue(t.$slots,"home-hero-info")]),"home-hero-info-after":ye(()=>[ue(t.$slots,"home-hero-info-after")]),"home-hero-actions-after":ye(()=>[ue(t.$slots,"home-hero-actions-after")]),"home-hero-image":ye(()=>[ue(t.$slots,"home-hero-image")]),_:3},8,["name","text","tagline","image","actions"])):De("",!0)}}),MA=s=>(Wt("data-v-a3976bdc"),s=s(),$t(),s),bA={class:"box"},SA={key:0,class:"icon"},wA=["innerHTML"],AA=["innerHTML"],TA=["innerHTML"],EA={key:4,class:"link-text"},CA={class:"link-text-value"},PA=MA(()=>me("span",{class:"vpi-arrow-right link-text-icon"},null,-1)),RA=Be({__name:"VPFeature",props:{icon:{},title:{},details:{},link:{},linkText:{},rel:{},target:{}},setup(s){return(e,t)=>(Y(),$e(Gn,{class:"VPFeature",href:e.link,rel:e.rel,target:e.target,"no-icon":!0,tag:e.link?"a":"div"},{default:ye(()=>[me("article",bA,[typeof e.icon=="object"&&e.icon.wrap?(Y(),fe("div",SA,[Fe(wa,{image:e.icon,alt:e.icon.alt,height:e.icon.height||48,width:e.icon.width||48},null,8,["image","alt","height","width"])])):typeof e.icon=="object"?(Y(),$e(wa,{key:1,image:e.icon,alt:e.icon.alt,height:e.icon.height||48,width:e.icon.width||48},null,8,["image","alt","height","width"])):e.icon?(Y(),fe("div",{key:2,class:"icon",innerHTML:e.icon},null,8,wA)):De("",!0),me("h2",{class:"title",innerHTML:e.title},null,8,AA),e.details?(Y(),fe("p",{key:3,class:"details",innerHTML:e.details},null,8,TA)):De("",!0),e.linkText?(Y(),fe("div",EA,[me("p",CA,[Ht(ft(e.linkText)+" ",1),PA])])):De("",!0)])]),_:1},8,["href","rel","target","tag"]))}}),IA=Ye(RA,[["__scopeId","data-v-a3976bdc"]]),LA={key:0,class:"VPFeatures"},NA={class:"container"},DA={class:"items"},UA=Be({__name:"VPFeatures",props:{features:{}},setup(s){const e=s,t=ke(()=>{const n=e.features.length;if(n){if(n===2)return"grid-2";if(n===3)return"grid-3";if(n%3===0)return"grid-6";if(n>3)return"grid-4"}else return});return(n,i)=>n.features?(Y(),fe("div",LA,[me("div",NA,[me("div",DA,[(Y(!0),fe(xt,null,Jt(n.features,r=>(Y(),fe("div",{key:r.title,class:yt(["item",[t.value]])},[Fe(IA,{icon:r.icon,title:r.title,details:r.details,link:r.link,"link-text":r.linkText,rel:r.rel,target:r.target},null,8,["icon","title","details","link","link-text","rel","target"])],2))),128))])])])):De("",!0)}}),OA=Ye(UA,[["__scopeId","data-v-a6181336"]]),FA=Be({__name:"VPHomeFeatures",setup(s){const{frontmatter:e}=ot();return(t,n)=>j(e).features?(Y(),$e(OA,{key:0,class:"VPHomeFeatures",features:j(e).features},null,8,["features"])):De("",!0)}}),kA=Be({__name:"VPHomeContent",setup(s){const{width:e}=Qm({initialWidth:0,includeScrollbar:!1});return(t,n)=>(Y(),fe("div",{class:"vp-doc container",style:Yc(j(e)?{"--vp-offset":`calc(50% - ${j(e)/2}px)`}:{})},[ue(t.$slots,"default",{},void 0,!0)],4))}}),BA=Ye(kA,[["__scopeId","data-v-8e2d4988"]]),zA={class:"VPHome"},VA=Be({__name:"VPHome",setup(s){const{frontmatter:e}=ot();return(t,n)=>{const i=cn("Content");return Y(),fe("div",zA,[ue(t.$slots,"home-hero-before",{},void 0,!0),Fe(xA,null,{"home-hero-info-before":ye(()=>[ue(t.$slots,"home-hero-info-before",{},void 0,!0)]),"home-hero-info":ye(()=>[ue(t.$slots,"home-hero-info",{},void 0,!0)]),"home-hero-info-after":ye(()=>[ue(t.$slots,"home-hero-info-after",{},void 0,!0)]),"home-hero-actions-after":ye(()=>[ue(t.$slots,"home-hero-actions-after",{},void 0,!0)]),"home-hero-image":ye(()=>[ue(t.$slots,"home-hero-image",{},void 0,!0)]),_:3}),ue(t.$slots,"home-hero-after",{},void 0,!0),ue(t.$slots,"home-features-before",{},void 0,!0),Fe(FA),ue(t.$slots,"home-features-after",{},void 0,!0),j(e).markdownStyles!==!1?(Y(),$e(BA,{key:0},{default:ye(()=>[Fe(i)]),_:1})):(Y(),$e(i,{key:1}))])}}}),HA=Ye(VA,[["__scopeId","data-v-686f80a6"]]),GA={},WA={class:"VPPage"};function $A(s,e){const t=cn("Content");return Y(),fe("div",WA,[ue(s.$slots,"page-top"),Fe(t),ue(s.$slots,"page-bottom")])}const XA=Ye(GA,[["render",$A]]),qA=Be({__name:"VPContent",setup(s){const{page:e,frontmatter:t}=ot(),{hasSidebar:n}=fi();return(i,r)=>(Y(),fe("div",{class:yt(["VPContent",{"has-sidebar":j(n),"is-home":j(t).layout==="home"}]),id:"VPContent"},[j(e).isNotFound?ue(i.$slots,"not-found",{key:0},()=>[Fe(n1)],!0):j(t).layout==="page"?(Y(),$e(XA,{key:1},{"page-top":ye(()=>[ue(i.$slots,"page-top",{},void 0,!0)]),"page-bottom":ye(()=>[ue(i.$slots,"page-bottom",{},void 0,!0)]),_:3})):j(t).layout==="home"?(Y(),$e(HA,{key:2},{"home-hero-before":ye(()=>[ue(i.$slots,"home-hero-before",{},void 0,!0)]),"home-hero-info-before":ye(()=>[ue(i.$slots,"home-hero-info-before",{},void 0,!0)]),"home-hero-info":ye(()=>[ue(i.$slots,"home-hero-info",{},void 0,!0)]),"home-hero-info-after":ye(()=>[ue(i.$slots,"home-hero-info-after",{},void 0,!0)]),"home-hero-actions-after":ye(()=>[ue(i.$slots,"home-hero-actions-after",{},void 0,!0)]),"home-hero-image":ye(()=>[ue(i.$slots,"home-hero-image",{},void 0,!0)]),"home-hero-after":ye(()=>[ue(i.$slots,"home-hero-after",{},void 0,!0)]),"home-features-before":ye(()=>[ue(i.$slots,"home-features-before",{},void 0,!0)]),"home-features-after":ye(()=>[ue(i.$slots,"home-features-after",{},void 0,!0)]),_:3})):j(t).layout&&j(t).layout!=="doc"?(Y(),$e(Bs(j(t).layout),{key:3})):(Y(),$e(nA,{key:4},{"doc-top":ye(()=>[ue(i.$slots,"doc-top",{},void 0,!0)]),"doc-bottom":ye(()=>[ue(i.$slots,"doc-bottom",{},void 0,!0)]),"doc-footer-before":ye(()=>[ue(i.$slots,"doc-footer-before",{},void 0,!0)]),"doc-before":ye(()=>[ue(i.$slots,"doc-before",{},void 0,!0)]),"doc-after":ye(()=>[ue(i.$slots,"doc-after",{},void 0,!0)]),"aside-top":ye(()=>[ue(i.$slots,"aside-top",{},void 0,!0)]),"aside-outline-before":ye(()=>[ue(i.$slots,"aside-outline-before",{},void 0,!0)]),"aside-outline-after":ye(()=>[ue(i.$slots,"aside-outline-after",{},void 0,!0)]),"aside-ads-before":ye(()=>[ue(i.$slots,"aside-ads-before",{},void 0,!0)]),"aside-ads-after":ye(()=>[ue(i.$slots,"aside-ads-after",{},void 0,!0)]),"aside-bottom":ye(()=>[ue(i.$slots,"aside-bottom",{},void 0,!0)]),_:3}))],2))}}),YA=Ye(qA,[["__scopeId","data-v-1428d186"]]),ZA={class:"container"},JA=["innerHTML"],KA=["innerHTML"],jA=Be({__name:"VPFooter",setup(s){const{theme:e,frontmatter:t}=ot(),{hasSidebar:n}=fi();return(i,r)=>j(e).footer&&j(t).footer!==!1?(Y(),fe("footer",{key:0,class:yt(["VPFooter",{"has-sidebar":j(n)}])},[me("div",ZA,[j(e).footer.message?(Y(),fe("p",{key:0,class:"message",innerHTML:j(e).footer.message},null,8,JA)):De("",!0),j(e).footer.copyright?(Y(),fe("p",{key:1,class:"copyright",innerHTML:j(e).footer.copyright},null,8,KA)):De("",!0)])],2)):De("",!0)}}),QA=Ye(jA,[["__scopeId","data-v-e315a0ad"]]);function eT(){const{theme:s,frontmatter:e}=ot(),t=Rn([]),n=ke(()=>t.value.length>0);return Aa(()=>{t.value=Gu(e.value.outline??s.value.outline)}),{headers:t,hasLocalNav:n}}const tT=s=>(Wt("data-v-17a5e62e"),s=s(),$t(),s),nT={class:"menu-text"},iT=tT(()=>me("span",{class:"vpi-chevron-right icon"},null,-1)),sT={class:"header"},rT={class:"outline"},oT=Be({__name:"VPLocalNavOutlineDropdown",props:{headers:{},navHeight:{}},setup(s){const e=s,{theme:t}=ot(),n=Ge(!1),i=Ge(0),r=Ge(),o=Ge();function a(h){var d;(d=r.value)!=null&&d.contains(h.target)||(n.value=!1)}Ct(n,h=>{if(h){document.addEventListener("click",a);return}document.removeEventListener("click",a)}),jl("Escape",()=>{n.value=!1}),Aa(()=>{n.value=!1});function l(){n.value=!n.value,i.value=window.innerHeight+Math.min(window.scrollY-e.navHeight,0)}function c(h){h.target.classList.contains("outline-link")&&(o.value&&(o.value.style.transition="none"),qc(()=>{n.value=!1}))}function u(){n.value=!1,window.scrollTo({top:0,left:0,behavior:"smooth"})}return(h,d)=>(Y(),fe("div",{class:"VPLocalNavOutlineDropdown",style:Yc({"--vp-vh":i.value+"px"}),ref_key:"main",ref:r},[h.headers.length>0?(Y(),fe("button",{key:0,onClick:l,class:yt({open:n.value})},[me("span",nT,ft(j(Tm)(j(t))),1),iT],2)):(Y(),fe("button",{key:1,onClick:u},ft(j(t).returnToTopLabel||"Return to top"),1)),Fe(Zc,{name:"flyout"},{default:ye(()=>[n.value?(Y(),fe("div",{key:0,ref_key:"items",ref:o,class:"items",onClick:c},[me("div",sT,[me("a",{class:"top-link",href:"#",onClick:u},ft(j(t).returnToTopLabel||"Return to top"),1)]),me("div",rT,[Fe(Em,{headers:h.headers},null,8,["headers"])])],512)):De("",!0)]),_:1})],4))}}),aT=Ye(oT,[["__scopeId","data-v-17a5e62e"]]),lT=s=>(Wt("data-v-a6f0e41e"),s=s(),$t(),s),cT={class:"container"},uT=["aria-expanded"],hT=lT(()=>me("span",{class:"vpi-align-left menu-icon"},null,-1)),dT={class:"menu-text"},fT=Be({__name:"VPLocalNav",props:{open:{type:Boolean}},emits:["open-menu"],setup(s){const{theme:e,frontmatter:t}=ot(),{hasSidebar:n}=fi(),{headers:i}=eT(),{y:r}=Zd(),o=Ge(0);Nn(()=>{o.value=parseInt(getComputedStyle(document.documentElement).getPropertyValue("--vp-nav-height"))}),Aa(()=>{i.value=Gu(t.value.outline??e.value.outline)});const a=ke(()=>i.value.length===0),l=ke(()=>a.value&&!n.value),c=ke(()=>({VPLocalNav:!0,"has-sidebar":n.value,empty:a.value,fixed:l.value}));return(u,h)=>j(t).layout!=="home"&&(!l.value||j(r)>=o.value)?(Y(),fe("div",{key:0,class:yt(c.value)},[me("div",cT,[j(n)?(Y(),fe("button",{key:0,class:"menu","aria-expanded":u.open,"aria-controls":"VPSidebarNav",onClick:h[0]||(h[0]=d=>u.$emit("open-menu"))},[hT,me("span",dT,ft(j(e).sidebarMenuLabel||"Menu"),1)],8,uT)):De("",!0),Fe(aT,{headers:j(i),navHeight:o.value},null,8,["headers","navHeight"])])],2)):De("",!0)}}),pT=Ye(fT,[["__scopeId","data-v-a6f0e41e"]]);function mT(){const s=Ge(!1);function e(){s.value=!0,window.addEventListener("resize",i)}function t(){s.value=!1,window.removeEventListener("resize",i)}function n(){s.value?t():e()}function i(){window.outerWidth>=768&&t()}const r=Vr();return Ct(()=>r.path,t),{isScreenOpen:s,openScreen:e,closeScreen:t,toggleScreen:n}}const gT={},vT={class:"VPSwitch",type:"button",role:"switch"},_T={class:"check"},yT={key:0,class:"icon"};function xT(s,e){return Y(),fe("button",vT,[me("span",_T,[s.$slots.default?(Y(),fe("span",yT,[ue(s.$slots,"default",{},void 0,!0)])):De("",!0)])])}const MT=Ye(gT,[["render",xT],["__scopeId","data-v-1d5665e3"]]),Pm=s=>(Wt("data-v-d1f28634"),s=s(),$t(),s),bT=Pm(()=>me("span",{class:"vpi-sun sun"},null,-1)),ST=Pm(()=>me("span",{class:"vpi-moon moon"},null,-1)),wT=Be({__name:"VPSwitchAppearance",setup(s){const{isDark:e,theme:t}=ot(),n=zr("toggle-appearance",()=>{e.value=!e.value}),i=ke(()=>e.value?t.value.lightModeSwitchTitle||"Switch to light theme":t.value.darkModeSwitchTitle||"Switch to dark theme");return(r,o)=>(Y(),$e(MT,{title:i.value,class:"VPSwitchAppearance","aria-checked":j(e),onClick:j(n)},{default:ye(()=>[bT,ST]),_:1},8,["title","aria-checked","onClick"]))}}),Wu=Ye(wT,[["__scopeId","data-v-d1f28634"]]),AT={key:0,class:"VPNavBarAppearance"},TT=Be({__name:"VPNavBarAppearance",setup(s){const{site:e}=ot();return(t,n)=>j(e).appearance&&j(e).appearance!=="force-dark"?(Y(),fe("div",AT,[Fe(Wu)])):De("",!0)}}),ET=Ye(TT,[["__scopeId","data-v-e6aabb21"]]),$u=Ge();let Rm=!1,Jl=0;function CT(s){const e=Ge(!1);if(Ta){!Rm&&PT(),Jl++;const t=Ct($u,n=>{var i,r,o;n===s.el.value||(i=s.el.value)!=null&&i.contains(n)?(e.value=!0,(r=s.onFocus)==null||r.call(s)):(e.value=!1,(o=s.onBlur)==null||o.call(s))});Wn(()=>{t(),Jl--,Jl||RT()})}return gr(e)}function PT(){document.addEventListener("focusin",Im),Rm=!0,$u.value=document.activeElement}function RT(){document.removeEventListener("focusin",Im)}function Im(){$u.value=document.activeElement}const IT={class:"VPMenuLink"},LT=Be({__name:"VPMenuLink",props:{item:{}},setup(s){const{page:e}=ot();return(t,n)=>(Y(),fe("div",IT,[Fe(Gn,{class:yt({active:j(is)(j(e).relativePath,t.item.activeMatch||t.item.link,!!t.item.activeMatch)}),href:t.item.link,target:t.item.target,rel:t.item.rel},{default:ye(()=>[Ht(ft(t.item.text),1)]),_:1},8,["class","href","target","rel"])]))}}),sl=Ye(LT,[["__scopeId","data-v-43f1e123"]]),NT={class:"VPMenuGroup"},DT={key:0,class:"title"},UT=Be({__name:"VPMenuGroup",props:{text:{},items:{}},setup(s){return(e,t)=>(Y(),fe("div",NT,[e.text?(Y(),fe("p",DT,ft(e.text),1)):De("",!0),(Y(!0),fe(xt,null,Jt(e.items,n=>(Y(),fe(xt,null,["link"in n?(Y(),$e(sl,{key:0,item:n},null,8,["item"])):De("",!0)],64))),256))]))}}),OT=Ye(UT,[["__scopeId","data-v-69e747b5"]]),FT={class:"VPMenu"},kT={key:0,class:"items"},BT=Be({__name:"VPMenu",props:{items:{}},setup(s){return(e,t)=>(Y(),fe("div",FT,[e.items?(Y(),fe("div",kT,[(Y(!0),fe(xt,null,Jt(e.items,n=>(Y(),fe(xt,{key:n.text},["link"in n?(Y(),$e(sl,{key:0,item:n},null,8,["item"])):(Y(),$e(OT,{key:1,text:n.text,items:n.items},null,8,["text","items"]))],64))),128))])):De("",!0),ue(e.$slots,"default",{},void 0,!0)]))}}),zT=Ye(BT,[["__scopeId","data-v-e7ea1737"]]),VT=s=>(Wt("data-v-b6c34ac9"),s=s(),$t(),s),HT=["aria-expanded","aria-label"],GT={key:0,class:"text"},WT=["innerHTML"],$T=VT(()=>me("span",{class:"vpi-chevron-down text-icon"},null,-1)),XT={key:1,class:"vpi-more-horizontal icon"},qT={class:"menu"},YT=Be({__name:"VPFlyout",props:{icon:{},button:{},label:{},items:{}},setup(s){const e=Ge(!1),t=Ge();CT({el:t,onBlur:n});function n(){e.value=!1}return(i,r)=>(Y(),fe("div",{class:"VPFlyout",ref_key:"el",ref:t,onMouseenter:r[1]||(r[1]=o=>e.value=!0),onMouseleave:r[2]||(r[2]=o=>e.value=!1)},[me("button",{type:"button",class:"button","aria-haspopup":"true","aria-expanded":e.value,"aria-label":i.label,onClick:r[0]||(r[0]=o=>e.value=!e.value)},[i.button||i.icon?(Y(),fe("span",GT,[i.icon?(Y(),fe("span",{key:0,class:yt([i.icon,"option-icon"])},null,2)):De("",!0),i.button?(Y(),fe("span",{key:1,innerHTML:i.button},null,8,WT)):De("",!0),$T])):(Y(),fe("span",XT))],8,HT),me("div",qT,[Fe(zT,{items:i.items},{default:ye(()=>[ue(i.$slots,"default",{},void 0,!0)]),_:3},8,["items"])])],544))}}),Xu=Ye(YT,[["__scopeId","data-v-b6c34ac9"]]),ZT=["href","aria-label","innerHTML"],JT=Be({__name:"VPSocialLink",props:{icon:{},link:{},ariaLabel:{}},setup(s){const e=s,t=ke(()=>typeof e.icon=="object"?e.icon.svg:``);return(n,i)=>(Y(),fe("a",{class:"VPSocialLink no-icon",href:n.link,"aria-label":n.ariaLabel??(typeof n.icon=="string"?n.icon:""),target:"_blank",rel:"noopener",innerHTML:t.value},null,8,ZT))}}),KT=Ye(JT,[["__scopeId","data-v-eee4e7cb"]]),jT={class:"VPSocialLinks"},QT=Be({__name:"VPSocialLinks",props:{links:{}},setup(s){return(e,t)=>(Y(),fe("div",jT,[(Y(!0),fe(xt,null,Jt(e.links,({link:n,icon:i,ariaLabel:r})=>(Y(),$e(KT,{key:n,icon:i,link:n,ariaLabel:r},null,8,["icon","link","ariaLabel"]))),128))]))}}),qu=Ye(QT,[["__scopeId","data-v-7bc22406"]]),eE={key:0,class:"group translations"},tE={class:"trans-title"},nE={key:1,class:"group"},iE={class:"item appearance"},sE={class:"label"},rE={class:"appearance-action"},oE={key:2,class:"group"},aE={class:"item social-links"},lE=Be({__name:"VPNavBarExtra",setup(s){const{site:e,theme:t}=ot(),{localeLinks:n,currentLang:i}=to({correspondingLink:!0}),r=ke(()=>n.value.length&&i.value.label||e.value.appearance||t.value.socialLinks);return(o,a)=>r.value?(Y(),$e(Xu,{key:0,class:"VPNavBarExtra",label:"extra navigation"},{default:ye(()=>[j(n).length&&j(i).label?(Y(),fe("div",eE,[me("p",tE,ft(j(i).label),1),(Y(!0),fe(xt,null,Jt(j(n),l=>(Y(),$e(sl,{key:l.link,item:l},null,8,["item"]))),128))])):De("",!0),j(e).appearance&&j(e).appearance!=="force-dark"?(Y(),fe("div",nE,[me("div",iE,[me("p",sE,ft(j(t).darkModeSwitchLabel||"Appearance"),1),me("div",rE,[Fe(Wu)])])])):De("",!0),j(t).socialLinks?(Y(),fe("div",oE,[me("div",aE,[Fe(qu,{class:"social-links-list",links:j(t).socialLinks},null,8,["links"])])])):De("",!0)]),_:1})):De("",!0)}}),cE=Ye(lE,[["__scopeId","data-v-d0bd9dde"]]),uE=s=>(Wt("data-v-e5dd9c1c"),s=s(),$t(),s),hE=["aria-expanded"],dE=uE(()=>me("span",{class:"container"},[me("span",{class:"top"}),me("span",{class:"middle"}),me("span",{class:"bottom"})],-1)),fE=[dE],pE=Be({__name:"VPNavBarHamburger",props:{active:{type:Boolean}},emits:["click"],setup(s){return(e,t)=>(Y(),fe("button",{type:"button",class:yt(["VPNavBarHamburger",{active:e.active}]),"aria-label":"mobile navigation","aria-expanded":e.active,"aria-controls":"VPNavScreen",onClick:t[0]||(t[0]=n=>e.$emit("click"))},fE,10,hE))}}),mE=Ye(pE,[["__scopeId","data-v-e5dd9c1c"]]),gE=["innerHTML"],vE=Be({__name:"VPNavBarMenuLink",props:{item:{}},setup(s){const{page:e}=ot();return(t,n)=>(Y(),$e(Gn,{class:yt({VPNavBarMenuLink:!0,active:j(is)(j(e).relativePath,t.item.activeMatch||t.item.link,!!t.item.activeMatch)}),href:t.item.link,noIcon:t.item.noIcon,target:t.item.target,rel:t.item.rel,tabindex:"0"},{default:ye(()=>[me("span",{innerHTML:t.item.text},null,8,gE)]),_:1},8,["class","href","noIcon","target","rel"]))}}),_E=Ye(vE,[["__scopeId","data-v-9c663999"]]),yE=Be({__name:"VPNavBarMenuGroup",props:{item:{}},setup(s){const e=s,{page:t}=ot(),n=r=>"link"in r?is(t.value.relativePath,r.link,!!e.item.activeMatch):r.items.some(n),i=ke(()=>n(e.item));return(r,o)=>(Y(),$e(Xu,{class:yt({VPNavBarMenuGroup:!0,active:j(is)(j(t).relativePath,r.item.activeMatch,!!r.item.activeMatch)||i.value}),button:r.item.text,items:r.item.items},null,8,["class","button","items"]))}}),xE=s=>(Wt("data-v-7f418b0f"),s=s(),$t(),s),ME={key:0,"aria-labelledby":"main-nav-aria-label",class:"VPNavBarMenu"},bE=xE(()=>me("span",{id:"main-nav-aria-label",class:"visually-hidden"},"Main Navigation",-1)),SE=Be({__name:"VPNavBarMenu",setup(s){const{theme:e}=ot();return(t,n)=>j(e).nav?(Y(),fe("nav",ME,[bE,(Y(!0),fe(xt,null,Jt(j(e).nav,i=>(Y(),fe(xt,{key:i.text},["link"in i?(Y(),$e(_E,{key:0,item:i},null,8,["item"])):(Y(),$e(yE,{key:1,item:i},null,8,["item"]))],64))),128))])):De("",!0)}}),wE=Ye(SE,[["__scopeId","data-v-7f418b0f"]]);function AE(s){const{localeIndex:e,theme:t}=ot();function n(i){var g,v,m;const r=i.split("."),o=(g=t.value.search)==null?void 0:g.options,a=o&&typeof o=="object",l=a&&((m=(v=o.locales)==null?void 0:v[e.value])==null?void 0:m.translations)||null,c=a&&o.translations||null;let u=l,h=c,d=s;const f=r.pop();for(const p of r){let y=null;const _=d==null?void 0:d[p];_&&(y=d=_);const x=h==null?void 0:h[p];x&&(y=h=x);const A=u==null?void 0:u[p];A&&(y=u=A),_||(d=y),x||(h=y),A||(u=y)}return(u==null?void 0:u[f])??(h==null?void 0:h[f])??(d==null?void 0:d[f])??""}return n}const TE=["aria-label"],EE={class:"DocSearch-Button-Container"},CE=me("span",{class:"vp-icon DocSearch-Search-Icon"},null,-1),PE={class:"DocSearch-Button-Placeholder"},RE=me("span",{class:"DocSearch-Button-Keys"},[me("kbd",{class:"DocSearch-Button-Key"}),me("kbd",{class:"DocSearch-Button-Key"},"K")],-1),Wd=Be({__name:"VPNavBarSearchButton",setup(s){const t=AE({button:{buttonText:"Search",buttonAriaLabel:"Search"}});return(n,i)=>(Y(),fe("button",{type:"button",class:"DocSearch DocSearch-Button","aria-label":j(t)("button.buttonAriaLabel")},[me("span",EE,[CE,me("span",PE,ft(j(t)("button.buttonText")),1)]),RE],8,TE))}}),IE={class:"VPNavBarSearch"},LE={id:"local-search"},NE={key:1,id:"docsearch"},DE=Be({__name:"VPNavBarSearch",setup(s){const e=eg(()=>tg(()=>import("./VPLocalSearchBox.hF612Jrh.js"),__vite__mapDeps([0,1]))),t=()=>null,{theme:n}=ot(),i=Ge(!1),r=Ge(!1);Nn(()=>{});function o(){i.value||(i.value=!0,setTimeout(a,16))}function a(){const h=new Event("keydown");h.key="k",h.metaKey=!0,window.dispatchEvent(h),setTimeout(()=>{document.querySelector(".DocSearch-Modal")||a()},16)}function l(h){const d=h.target,f=d.tagName;return d.isContentEditable||f==="INPUT"||f==="SELECT"||f==="TEXTAREA"}const c=Ge(!1);jl("k",h=>{(h.ctrlKey||h.metaKey)&&(h.preventDefault(),c.value=!0)}),jl("/",h=>{l(h)||(h.preventDefault(),c.value=!0)});const u="local";return(h,d)=>{var f;return Y(),fe("div",IE,[j(u)==="local"?(Y(),fe(xt,{key:0},[c.value?(Y(),$e(j(e),{key:0,onClose:d[0]||(d[0]=g=>c.value=!1)})):De("",!0),me("div",LE,[Fe(Wd,{onClick:d[1]||(d[1]=g=>c.value=!0)})])],64)):j(u)==="algolia"?(Y(),fe(xt,{key:1},[i.value?(Y(),$e(j(t),{key:0,algolia:((f=j(n).search)==null?void 0:f.options)??j(n).algolia,onVnodeBeforeMount:d[2]||(d[2]=g=>r.value=!0)},null,8,["algolia"])):De("",!0),r.value?De("",!0):(Y(),fe("div",NE,[Fe(Wd,{onClick:o})]))],64)):De("",!0)])}}}),UE=Be({__name:"VPNavBarSocialLinks",setup(s){const{theme:e}=ot();return(t,n)=>j(e).socialLinks?(Y(),$e(qu,{key:0,class:"VPNavBarSocialLinks",links:j(e).socialLinks},null,8,["links"])):De("",!0)}}),OE=Ye(UE,[["__scopeId","data-v-0394ad82"]]),FE=["href","rel","target"],kE={key:1},BE={key:2},zE=Be({__name:"VPNavBarTitle",setup(s){const{site:e,theme:t}=ot(),{hasSidebar:n}=fi(),{currentLang:i}=to(),r=ke(()=>{var l;return typeof t.value.logoLink=="string"?t.value.logoLink:(l=t.value.logoLink)==null?void 0:l.link}),o=ke(()=>{var l;return typeof t.value.logoLink=="string"||(l=t.value.logoLink)==null?void 0:l.rel}),a=ke(()=>{var l;return typeof t.value.logoLink=="string"||(l=t.value.logoLink)==null?void 0:l.target});return(l,c)=>(Y(),fe("div",{class:yt(["VPNavBarTitle",{"has-sidebar":j(n)}])},[me("a",{class:"title",href:r.value??j(Hu)(j(i).link),rel:o.value,target:a.value},[ue(l.$slots,"nav-bar-title-before",{},void 0,!0),j(t).logo?(Y(),$e(wa,{key:0,class:"logo",image:j(t).logo},null,8,["image"])):De("",!0),j(t).siteTitle?(Y(),fe("span",kE,ft(j(t).siteTitle),1)):j(t).siteTitle===void 0?(Y(),fe("span",BE,ft(j(e).title),1)):De("",!0),ue(l.$slots,"nav-bar-title-after",{},void 0,!0)],8,FE)],2))}}),VE=Ye(zE,[["__scopeId","data-v-ab179fa1"]]),HE={class:"items"},GE={class:"title"},WE=Be({__name:"VPNavBarTranslations",setup(s){const{theme:e}=ot(),{localeLinks:t,currentLang:n}=to({correspondingLink:!0});return(i,r)=>j(t).length&&j(n).label?(Y(),$e(Xu,{key:0,class:"VPNavBarTranslations",icon:"vpi-languages",label:j(e).langMenuLabel||"Change language"},{default:ye(()=>[me("div",HE,[me("p",GE,ft(j(n).label),1),(Y(!0),fe(xt,null,Jt(j(t),o=>(Y(),$e(sl,{key:o.link,item:o},null,8,["item"]))),128))])]),_:1},8,["label"])):De("",!0)}}),$E=Ye(WE,[["__scopeId","data-v-88af2de4"]]),XE=s=>(Wt("data-v-ccf7ddec"),s=s(),$t(),s),qE={class:"wrapper"},YE={class:"container"},ZE={class:"title"},JE={class:"content"},KE={class:"content-body"},jE=XE(()=>me("div",{class:"divider"},[me("div",{class:"divider-line"})],-1)),QE=Be({__name:"VPNavBar",props:{isScreenOpen:{type:Boolean}},emits:["toggle-screen"],setup(s){const{y:e}=Zd(),{hasSidebar:t}=fi(),{frontmatter:n}=ot(),i=Ge({});return qd(()=>{i.value={"has-sidebar":t.value,home:n.value.layout==="home",top:e.value===0}}),(r,o)=>(Y(),fe("div",{class:yt(["VPNavBar",i.value])},[me("div",qE,[me("div",YE,[me("div",ZE,[Fe(VE,null,{"nav-bar-title-before":ye(()=>[ue(r.$slots,"nav-bar-title-before",{},void 0,!0)]),"nav-bar-title-after":ye(()=>[ue(r.$slots,"nav-bar-title-after",{},void 0,!0)]),_:3})]),me("div",JE,[me("div",KE,[ue(r.$slots,"nav-bar-content-before",{},void 0,!0),Fe(DE,{class:"search"}),Fe(wE,{class:"menu"}),Fe($E,{class:"translations"}),Fe(ET,{class:"appearance"}),Fe(OE,{class:"social-links"}),Fe(cE,{class:"extra"}),ue(r.$slots,"nav-bar-content-after",{},void 0,!0),Fe(mE,{class:"hamburger",active:r.isScreenOpen,onClick:o[0]||(o[0]=a=>r.$emit("toggle-screen"))},null,8,["active"])])])])]),jE],2))}}),eC=Ye(QE,[["__scopeId","data-v-ccf7ddec"]]),tC={key:0,class:"VPNavScreenAppearance"},nC={class:"text"},iC=Be({__name:"VPNavScreenAppearance",setup(s){const{site:e,theme:t}=ot();return(n,i)=>j(e).appearance&&j(e).appearance!=="force-dark"?(Y(),fe("div",tC,[me("p",nC,ft(j(t).darkModeSwitchLabel||"Appearance"),1),Fe(Wu)])):De("",!0)}}),sC=Ye(iC,[["__scopeId","data-v-2d7af913"]]),rC=Be({__name:"VPNavScreenMenuLink",props:{item:{}},setup(s){const e=zr("close-screen");return(t,n)=>(Y(),$e(Gn,{class:"VPNavScreenMenuLink",href:t.item.link,target:t.item.target,rel:t.item.rel,onClick:j(e),innerHTML:t.item.text},null,8,["href","target","rel","onClick","innerHTML"]))}}),oC=Ye(rC,[["__scopeId","data-v-7f31e1f6"]]),aC=Be({__name:"VPNavScreenMenuGroupLink",props:{item:{}},setup(s){const e=zr("close-screen");return(t,n)=>(Y(),$e(Gn,{class:"VPNavScreenMenuGroupLink",href:t.item.link,target:t.item.target,rel:t.item.rel,onClick:j(e)},{default:ye(()=>[Ht(ft(t.item.text),1)]),_:1},8,["href","target","rel","onClick"]))}}),Lm=Ye(aC,[["__scopeId","data-v-19976ae1"]]),lC={class:"VPNavScreenMenuGroupSection"},cC={key:0,class:"title"},uC=Be({__name:"VPNavScreenMenuGroupSection",props:{text:{},items:{}},setup(s){return(e,t)=>(Y(),fe("div",lC,[e.text?(Y(),fe("p",cC,ft(e.text),1)):De("",!0),(Y(!0),fe(xt,null,Jt(e.items,n=>(Y(),$e(Lm,{key:n.text,item:n},null,8,["item"]))),128))]))}}),hC=Ye(uC,[["__scopeId","data-v-8133b170"]]),dC=s=>(Wt("data-v-ff6087d4"),s=s(),$t(),s),fC=["aria-controls","aria-expanded"],pC=["innerHTML"],mC=dC(()=>me("span",{class:"vpi-plus button-icon"},null,-1)),gC=["id"],vC={key:1,class:"group"},_C=Be({__name:"VPNavScreenMenuGroup",props:{text:{},items:{}},setup(s){const e=s,t=Ge(!1),n=ke(()=>`NavScreenGroup-${e.text.replace(" ","-").toLowerCase()}`);function i(){t.value=!t.value}return(r,o)=>(Y(),fe("div",{class:yt(["VPNavScreenMenuGroup",{open:t.value}])},[me("button",{class:"button","aria-controls":n.value,"aria-expanded":t.value,onClick:i},[me("span",{class:"button-text",innerHTML:r.text},null,8,pC),mC],8,fC),me("div",{id:n.value,class:"items"},[(Y(!0),fe(xt,null,Jt(r.items,a=>(Y(),fe(xt,{key:a.text},["link"in a?(Y(),fe("div",{key:a.text,class:"item"},[Fe(Lm,{item:a},null,8,["item"])])):(Y(),fe("div",vC,[Fe(hC,{text:a.text,items:a.items},null,8,["text","items"])]))],64))),128))],8,gC)],2))}}),yC=Ye(_C,[["__scopeId","data-v-ff6087d4"]]),xC={key:0,class:"VPNavScreenMenu"},MC=Be({__name:"VPNavScreenMenu",setup(s){const{theme:e}=ot();return(t,n)=>j(e).nav?(Y(),fe("nav",xC,[(Y(!0),fe(xt,null,Jt(j(e).nav,i=>(Y(),fe(xt,{key:i.text},["link"in i?(Y(),$e(oC,{key:0,item:i},null,8,["item"])):(Y(),$e(yC,{key:1,text:i.text||"",items:i.items},null,8,["text","items"]))],64))),128))])):De("",!0)}}),bC=Be({__name:"VPNavScreenSocialLinks",setup(s){const{theme:e}=ot();return(t,n)=>j(e).socialLinks?(Y(),$e(qu,{key:0,class:"VPNavScreenSocialLinks",links:j(e).socialLinks},null,8,["links"])):De("",!0)}}),Nm=s=>(Wt("data-v-858fe1a4"),s=s(),$t(),s),SC=Nm(()=>me("span",{class:"vpi-languages icon lang"},null,-1)),wC=Nm(()=>me("span",{class:"vpi-chevron-down icon chevron"},null,-1)),AC={class:"list"},TC=Be({__name:"VPNavScreenTranslations",setup(s){const{localeLinks:e,currentLang:t}=to({correspondingLink:!0}),n=Ge(!1);function i(){n.value=!n.value}return(r,o)=>j(e).length&&j(t).label?(Y(),fe("div",{key:0,class:yt(["VPNavScreenTranslations",{open:n.value}])},[me("button",{class:"title",onClick:i},[SC,Ht(" "+ft(j(t).label)+" ",1),wC]),me("ul",AC,[(Y(!0),fe(xt,null,Jt(j(e),a=>(Y(),fe("li",{key:a.link,class:"item"},[Fe(Gn,{class:"link",href:a.link},{default:ye(()=>[Ht(ft(a.text),1)]),_:2},1032,["href"])]))),128))])],2)):De("",!0)}}),EC=Ye(TC,[["__scopeId","data-v-858fe1a4"]]),CC={class:"container"},PC=Be({__name:"VPNavScreen",props:{open:{type:Boolean}},setup(s){const e=Ge(null),t=Jd(Ta?document.body:null);return(n,i)=>(Y(),$e(Zc,{name:"fade",onEnter:i[0]||(i[0]=r=>t.value=!0),onAfterLeave:i[1]||(i[1]=r=>t.value=!1)},{default:ye(()=>[n.open?(Y(),fe("div",{key:0,class:"VPNavScreen",ref_key:"screen",ref:e,id:"VPNavScreen"},[me("div",CC,[ue(n.$slots,"nav-screen-content-before",{},void 0,!0),Fe(MC,{class:"menu"}),Fe(EC,{class:"translations"}),Fe(sC,{class:"appearance"}),Fe(bC,{class:"social-links"}),ue(n.$slots,"nav-screen-content-after",{},void 0,!0)])],512)):De("",!0)]),_:3}))}}),RC=Ye(PC,[["__scopeId","data-v-cc5739dd"]]),IC={key:0,class:"VPNav"},LC=Be({__name:"VPNav",setup(s){const{isScreenOpen:e,closeScreen:t,toggleScreen:n}=mT(),{frontmatter:i}=ot(),r=ke(()=>i.value.navbar!==!1);return vr("close-screen",t),Ri(()=>{Ta&&document.documentElement.classList.toggle("hide-nav",!r.value)}),(o,a)=>r.value?(Y(),fe("header",IC,[Fe(eC,{"is-screen-open":j(e),onToggleScreen:j(n)},{"nav-bar-title-before":ye(()=>[ue(o.$slots,"nav-bar-title-before",{},void 0,!0)]),"nav-bar-title-after":ye(()=>[ue(o.$slots,"nav-bar-title-after",{},void 0,!0)]),"nav-bar-content-before":ye(()=>[ue(o.$slots,"nav-bar-content-before",{},void 0,!0)]),"nav-bar-content-after":ye(()=>[ue(o.$slots,"nav-bar-content-after",{},void 0,!0)]),_:3},8,["is-screen-open","onToggleScreen"]),Fe(RC,{open:j(e)},{"nav-screen-content-before":ye(()=>[ue(o.$slots,"nav-screen-content-before",{},void 0,!0)]),"nav-screen-content-after":ye(()=>[ue(o.$slots,"nav-screen-content-after",{},void 0,!0)]),_:3},8,["open"])])):De("",!0)}}),NC=Ye(LC,[["__scopeId","data-v-ae24b3ad"]]),Dm=s=>(Wt("data-v-b8d55f3b"),s=s(),$t(),s),DC=["role","tabindex"],UC=Dm(()=>me("div",{class:"indicator"},null,-1)),OC=["onKeydown"],FC=Dm(()=>me("span",{class:"vpi-chevron-right caret-icon"},null,-1)),kC=[FC],BC={key:1,class:"items"},zC=Be({__name:"VPSidebarItem",props:{item:{},depth:{}},setup(s){const e=s,{collapsed:t,collapsible:n,isLink:i,isActiveLink:r,hasActiveLink:o,hasChildren:a,toggle:l}=o1(ke(()=>e.item)),c=ke(()=>a.value?"section":"div"),u=ke(()=>i.value?"a":"div"),h=ke(()=>a.value?e.depth+2===7?"p":`h${e.depth+2}`:"p"),d=ke(()=>i.value?void 0:"button"),f=ke(()=>[[`level-${e.depth}`],{collapsible:n.value},{collapsed:t.value},{"is-link":i.value},{"is-active":r.value},{"has-active":o.value}]);function g(m){"key"in m&&m.key!=="Enter"||!e.item.link&&l()}function v(){e.item.link&&l()}return(m,p)=>{const y=cn("VPSidebarItem",!0);return Y(),$e(Bs(c.value),{class:yt(["VPSidebarItem",f.value])},{default:ye(()=>[m.item.text?(Y(),fe("div",ia({key:0,class:"item",role:d.value},ng(m.item.items?{click:g,keydown:g}:{},!0),{tabindex:m.item.items&&0}),[UC,m.item.link?(Y(),$e(Gn,{key:0,tag:u.value,class:"link",href:m.item.link,rel:m.item.rel,target:m.item.target},{default:ye(()=>[(Y(),$e(Bs(h.value),{class:"text",innerHTML:m.item.text},null,8,["innerHTML"]))]),_:1},8,["tag","href","rel","target"])):(Y(),$e(Bs(h.value),{key:1,class:"text",innerHTML:m.item.text},null,8,["innerHTML"])),m.item.collapsed!=null&&m.item.items&&m.item.items.length?(Y(),fe("div",{key:2,class:"caret",role:"button","aria-label":"toggle section",onClick:v,onKeydown:ig(v,["enter"]),tabindex:"0"},kC,40,OC)):De("",!0)],16,DC)):De("",!0),m.item.items&&m.item.items.length?(Y(),fe("div",BC,[m.depth<5?(Y(!0),fe(xt,{key:0},Jt(m.item.items,_=>(Y(),$e(y,{key:_.text,item:_,depth:m.depth+1},null,8,["item","depth"]))),128)):De("",!0)])):De("",!0)]),_:1},8,["class"])}}}),VC=Ye(zC,[["__scopeId","data-v-b8d55f3b"]]),Um=s=>(Wt("data-v-575e6a36"),s=s(),$t(),s),HC=Um(()=>me("div",{class:"curtain"},null,-1)),GC={class:"nav",id:"VPSidebarNav","aria-labelledby":"sidebar-aria-label",tabindex:"-1"},WC=Um(()=>me("span",{class:"visually-hidden",id:"sidebar-aria-label"}," Sidebar Navigation ",-1)),$C=Be({__name:"VPSidebar",props:{open:{type:Boolean}},setup(s){const e=s,{sidebarGroups:t,hasSidebar:n}=fi(),i=Ge(null),r=Jd(Ta?document.body:null);return Ct([e,i],()=>{var o;e.open?(r.value=!0,(o=i.value)==null||o.focus()):r.value=!1},{immediate:!0,flush:"post"}),(o,a)=>j(n)?(Y(),fe("aside",{key:0,class:yt(["VPSidebar",{open:o.open}]),ref_key:"navEl",ref:i,onClick:a[0]||(a[0]=sg(()=>{},["stop"]))},[HC,me("nav",GC,[WC,ue(o.$slots,"sidebar-nav-before",{},void 0,!0),(Y(!0),fe(xt,null,Jt(j(t),l=>(Y(),fe("div",{key:l.text,class:"group"},[Fe(VC,{item:l,depth:0},null,8,["item"])]))),128)),ue(o.$slots,"sidebar-nav-after",{},void 0,!0)])],2)):De("",!0)}}),XC=Ye($C,[["__scopeId","data-v-575e6a36"]]),qC=Be({__name:"VPSkipLink",setup(s){const e=Vr(),t=Ge();Ct(()=>e.path,()=>t.value.focus());function n({target:i}){const r=document.getElementById(decodeURIComponent(i.hash).slice(1));if(r){const o=()=>{r.removeAttribute("tabindex"),r.removeEventListener("blur",o)};r.setAttribute("tabindex","-1"),r.addEventListener("blur",o),r.focus(),window.scrollTo(0,0)}}return(i,r)=>(Y(),fe(xt,null,[me("span",{ref_key:"backToTop",ref:t,tabindex:"-1"},null,512),me("a",{href:"#VPContent",class:"VPSkipLink visually-hidden",onClick:n}," Skip to content ")],64))}}),YC=Ye(qC,[["__scopeId","data-v-0f60ec36"]]),ZC=Be({__name:"Layout",setup(s){const{isOpen:e,open:t,close:n}=fi(),i=Vr();Ct(()=>i.path,n),r1(e,n);const{frontmatter:r}=ot(),o=Xd(),a=ke(()=>!!o["home-hero-image"]);return vr("hero-image-slot-exists",a),(l,c)=>{const u=cn("Content");return j(r).layout!==!1?(Y(),fe("div",{key:0,class:yt(["Layout",j(r).pageClass])},[ue(l.$slots,"layout-top",{},void 0,!0),Fe(YC),Fe(Ww,{class:"backdrop",show:j(e),onClick:j(n)},null,8,["show","onClick"]),Fe(NC,null,{"nav-bar-title-before":ye(()=>[ue(l.$slots,"nav-bar-title-before",{},void 0,!0)]),"nav-bar-title-after":ye(()=>[ue(l.$slots,"nav-bar-title-after",{},void 0,!0)]),"nav-bar-content-before":ye(()=>[ue(l.$slots,"nav-bar-content-before",{},void 0,!0)]),"nav-bar-content-after":ye(()=>[ue(l.$slots,"nav-bar-content-after",{},void 0,!0)]),"nav-screen-content-before":ye(()=>[ue(l.$slots,"nav-screen-content-before",{},void 0,!0)]),"nav-screen-content-after":ye(()=>[ue(l.$slots,"nav-screen-content-after",{},void 0,!0)]),_:3}),Fe(pT,{open:j(e),onOpenMenu:j(t)},null,8,["open","onOpenMenu"]),Fe(XC,{open:j(e)},{"sidebar-nav-before":ye(()=>[ue(l.$slots,"sidebar-nav-before",{},void 0,!0)]),"sidebar-nav-after":ye(()=>[ue(l.$slots,"sidebar-nav-after",{},void 0,!0)]),_:3},8,["open"]),Fe(YA,null,{"page-top":ye(()=>[ue(l.$slots,"page-top",{},void 0,!0)]),"page-bottom":ye(()=>[ue(l.$slots,"page-bottom",{},void 0,!0)]),"not-found":ye(()=>[ue(l.$slots,"not-found",{},void 0,!0)]),"home-hero-before":ye(()=>[ue(l.$slots,"home-hero-before",{},void 0,!0)]),"home-hero-info-before":ye(()=>[ue(l.$slots,"home-hero-info-before",{},void 0,!0)]),"home-hero-info":ye(()=>[ue(l.$slots,"home-hero-info",{},void 0,!0)]),"home-hero-info-after":ye(()=>[ue(l.$slots,"home-hero-info-after",{},void 0,!0)]),"home-hero-actions-after":ye(()=>[ue(l.$slots,"home-hero-actions-after",{},void 0,!0)]),"home-hero-image":ye(()=>[ue(l.$slots,"home-hero-image",{},void 0,!0)]),"home-hero-after":ye(()=>[ue(l.$slots,"home-hero-after",{},void 0,!0)]),"home-features-before":ye(()=>[ue(l.$slots,"home-features-before",{},void 0,!0)]),"home-features-after":ye(()=>[ue(l.$slots,"home-features-after",{},void 0,!0)]),"doc-footer-before":ye(()=>[ue(l.$slots,"doc-footer-before",{},void 0,!0)]),"doc-before":ye(()=>[ue(l.$slots,"doc-before",{},void 0,!0)]),"doc-after":ye(()=>[ue(l.$slots,"doc-after",{},void 0,!0)]),"doc-top":ye(()=>[ue(l.$slots,"doc-top",{},void 0,!0)]),"doc-bottom":ye(()=>[ue(l.$slots,"doc-bottom",{},void 0,!0)]),"aside-top":ye(()=>[ue(l.$slots,"aside-top",{},void 0,!0)]),"aside-bottom":ye(()=>[ue(l.$slots,"aside-bottom",{},void 0,!0)]),"aside-outline-before":ye(()=>[ue(l.$slots,"aside-outline-before",{},void 0,!0)]),"aside-outline-after":ye(()=>[ue(l.$slots,"aside-outline-after",{},void 0,!0)]),"aside-ads-before":ye(()=>[ue(l.$slots,"aside-ads-before",{},void 0,!0)]),"aside-ads-after":ye(()=>[ue(l.$slots,"aside-ads-after",{},void 0,!0)]),_:3}),Fe(QA),ue(l.$slots,"layout-bottom",{},void 0,!0)],2)):(Y(),$e(u,{key:1}))}}}),JC=Ye(ZC,[["__scopeId","data-v-5d98c3a5"]]),Om={Layout:JC,enhanceApp:({app:s})=>{s.component("Badge",Vw)}},KC=Be({__name:"HighlightTargetedHeading",setup(s){function e(){if(!window||!window.location||!window.location.hash)return;const n=decodeURIComponent(window.location.hash);if(!n)return;let i;try{i=document.querySelector(n)}catch(r){console.error(r);return}i&&(i.classList.contains("VPNolebaseHighlightTargetedHeading")||i.classList.add("VPNolebaseHighlightTargetedHeading"),i.classList.remove("VPNolebaseHighlightTargetedHeadingAnimated"),setTimeout(()=>{i&&i.classList.add("VPNolebaseHighlightTargetedHeadingAnimated")},10))}const t=Vr();return Nn(e),Ct(t,async()=>{await qc(),e()}),rg("hashchange",e),(n,i)=>ue(n.$slots,"default")}}),no=s=>(Wt("data-v-d5ead69d"),s=s(),$t(),s),jC={class:"background"},QC={class:"vp-doc"},eP=no(()=>me("a",{class:"h-card",rel:"me",href:"/about"},[me("img",{src:ag,alt:""}),Ht("The Paper Pilot")],-1)),tP=no(()=>me("a",{rel:"license",href:"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"CC BY-NC-SA 4.0",-1)),nP=no(()=>me("div",null,"Any and all opinions listed here are my own and not representative of my employers; future, past and present.",-1)),iP=no(()=>me("div",null,[me("a",{href:"https://resume.incremental.social/thepaperpilot/thepaperpilot"},"Resume"),Ht(" (not actively seeking new opportunities).")],-1)),sP=no(()=>me("div",null,[Ht("Site built from "),me("a",{href:"https://code.incremental.social/thepaperpilot/pages/commit/e8e6e124509bfd4a86462c298d470021181676fb"},"this commit"),Ht(" on "),me("time",null,"Thursday, June 27, 2024 at 23:14:26"),Ht(". "),me("a",{href:"https://www.thepaperpilot.org/licenses.txt"},"Legal disclaimers"),Ht(".")],-1)),rP=Be({__name:"Layout",setup(s){return(e,t)=>{const n=cn("TresOrthographicCamera"),i=cn("TresAmbientLight"),r=cn("ClientOnly");return Y(),$e(j(Om).Layout,null,{"layout-top":ye(()=>[Fe(j(KC)),Fe(r,null,{default:ye(()=>[me("div",jC,[Fe(j(Ow),null,{default:ye(()=>[Fe(n,{position:[0,0,10]}),Fe(i,{intensity:1}),(Y(),$e(og,null,{default:ye(()=>[Fe(zw)]),_:1}))]),_:1})])]),_:1})]),"layout-bottom":ye(()=>[me("footer",QC,[me("div",null,[Ht("CC "+ft(new Date().getFullYear())+" ",1),eP,Ht(". "),tP,Ht(".")]),nP,iP,sP])]),_:1})}}}),oP=Ye(rP,[["__scopeId","data-v-d5ead69d"]]),lP={...Om,Layout:oP};export{Pc as A,Bn as K,es as N,xg as R,N as V,zw as _,lP as a,AE as c,kw as n,xw as r,Ow as t,ot as u}; diff --git a/assets/chunks/theme.Bc6XxFSB.js b/assets/chunks/theme.Bc6XxFSB.js deleted file mode 100644 index 2fa785d2..00000000 --- a/assets/chunks/theme.Bc6XxFSB.js +++ /dev/null @@ -1,3946 +0,0 @@ -const __vite__fileDeps=["assets/chunks/VPLocalSearchBox.DMasLpNF.js","assets/chunks/framework.VBE0TPts.js"],__vite__mapDeps=i=>i.map(i=>__vite__fileDeps[i]); -import{d as Ue,o as Y,c as fe,r as ue,n as yt,a as Ht,t as ft,b as $e,w as ye,e as De,T as qc,_ as Ye,u as Vm,i as Hm,f as Gm,g as Yc,h as ze,j as me,k as ee,p as Wt,l as $t,m as is,q as Kl,s as Ge,v as wt,x as Pi,y as Nn,z as Gn,A as $d,B as Wm,C as $m,D as cn,F as xt,E as Jt,G as Rn,H as Aa,I as ke,J as Bs,K as Xd,L as zr,M as ia,N as Vr,O as Xm,P as Zc,Q as jl,R as Jc,S as qd,U as Ta,V as gr,W as qm,X as Ym,Y as Yd,Z as vr,$ as Zm,a0 as Jm,a1 as Km,a2 as Zd,a3 as jm,a4 as Jd,a5 as Qm,a6 as eg,a7 as tg,a8 as ng,a9 as ma,aa as ig,ab as sg,ac as eh,ad as rg,ae as og,af as ag}from"./framework.VBE0TPts.js";const lg=Ue({__name:"VPBadge",props:{text:{},type:{default:"tip"}},setup(s){return(e,t)=>(Y(),fe("span",{class:yt(["VPBadge",e.type])},[ue(e.$slots,"default",{},()=>[Ht(ft(e.text),1)])],2))}}),cg={key:0,class:"VPBackdrop"},ug=Ue({__name:"VPBackdrop",props:{show:{type:Boolean}},setup(s){return(e,t)=>(Y(),$e(qc,{name:"fade"},{default:ye(()=>[e.show?(Y(),fe("div",cg)):De("",!0)]),_:1}))}}),hg=Ye(ug,[["__scopeId","data-v-c79a1216"]]),ot=Vm;function dg(s,e){let t,n=!1;return()=>{t&&clearTimeout(t),n?t=setTimeout(s,e):(s(),(n=!0)&&setTimeout(()=>n=!1,e))}}function Ql(s){return/^\//.test(s)?s:`/${s}`}function Kc(s){const{pathname:e,search:t,hash:n,protocol:i}=new URL(s,"http://a.com");if(Hm(s)||s.startsWith("#")||!i.startsWith("http")||!Gm(e))return s;const{site:r}=ot(),o=e.endsWith("/")||e.endsWith(".html")?s:s.replace(/(?:(^\.+)\/)?.*$/,`$1${e.replace(/(\.md)?$/,r.value.cleanUrls?"":".html")}${t}${n}`);return Yc(o)}function Hr({correspondingLink:s=!1}={}){const{site:e,localeIndex:t,page:n,theme:i,hash:r}=ot(),o=ze(()=>{var l,c;return{label:(l=e.value.locales[t.value])==null?void 0:l.label,link:((c=e.value.locales[t.value])==null?void 0:c.link)||(t.value==="root"?"/":`/${t.value}/`)}});return{localeLinks:ze(()=>Object.entries(e.value.locales).flatMap(([l,c])=>o.value.label===c.label?[]:{text:c.label,link:fg(c.link||(l==="root"?"/":`/${l}/`),i.value.i18nRouting!==!1&&s,n.value.relativePath.slice(o.value.link.length-1),!e.value.cleanUrls)+r.value})),currentLang:o}}function fg(s,e,t,n){return e?s.replace(/\/$/,"")+Ql(t.replace(/(^|\/)index\.md$/,"$1").replace(/\.md$/,n?".html":"")):s}const pg=s=>(Wt("data-v-d6be1790"),s=s(),$t(),s),mg={class:"NotFound"},gg={class:"code"},vg={class:"title"},_g=pg(()=>me("div",{class:"divider"},null,-1)),yg={class:"quote"},xg={class:"action"},Mg=["href","aria-label"],bg=Ue({__name:"NotFound",setup(s){const{theme:e}=ot(),{currentLang:t}=Hr();return(n,i)=>{var r,o,a,l,c;return Y(),fe("div",mg,[me("p",gg,ft(((r=ee(e).notFound)==null?void 0:r.code)??"404"),1),me("h1",vg,ft(((o=ee(e).notFound)==null?void 0:o.title)??"PAGE NOT FOUND"),1),_g,me("blockquote",yg,ft(((a=ee(e).notFound)==null?void 0:a.quote)??"But if you don't change your direction, and if you keep looking, you may end up where you are heading."),1),me("div",xg,[me("a",{class:"link",href:ee(Yc)(ee(t).link),"aria-label":((l=ee(e).notFound)==null?void 0:l.linkLabel)??"go to home"},ft(((c=ee(e).notFound)==null?void 0:c.linkText)??"Take me home"),9,Mg)])])}}}),Sg=Ye(bg,[["__scopeId","data-v-d6be1790"]]);function Kd(s,e){if(Array.isArray(s))return sa(s);if(s==null)return[];e=Ql(e);const t=Object.keys(s).sort((i,r)=>r.split("/").length-i.split("/").length).find(i=>e.startsWith(Ql(i))),n=t?s[t]:[];return Array.isArray(n)?sa(n):sa(n.items,n.base)}function wg(s){const e=[];let t=0;for(const n in s){const i=s[n];if(i.items){t=e.push(i);continue}e[t]||e.push({items:[]}),e[t].items.push(i)}return e}function Ag(s){const e=[];function t(n){for(const i of n)i.text&&i.link&&e.push({text:i.text,link:i.link,docFooterText:i.docFooterText}),i.items&&t(i.items)}return t(s),e}function ec(s,e){return Array.isArray(e)?e.some(t=>ec(s,t)):is(s,e.link)?!0:e.items?ec(s,e.items):!1}function sa(s,e){return[...s].map(t=>{const n={...t},i=n.base||e;return i&&n.link&&(n.link=i+n.link),n.items&&(n.items=sa(n.items,i)),n})}function li(){const{frontmatter:s,page:e,theme:t}=ot(),n=Kl("(min-width: 960px)"),i=Ge(!1),r=ze(()=>{const v=t.value.sidebar,p=e.value.relativePath;return v?Kd(v,p):[]}),o=Ge(r.value);wt(r,(v,p)=>{JSON.stringify(v)!==JSON.stringify(p)&&(o.value=r.value)});const a=ze(()=>s.value.sidebar!==!1&&o.value.length>0&&s.value.layout!=="home"),l=ze(()=>c?s.value.aside==null?t.value.aside==="left":s.value.aside==="left":!1),c=ze(()=>s.value.layout==="home"?!1:s.value.aside!=null?!!s.value.aside:t.value.aside!==!1),u=ze(()=>a.value&&n.value),h=ze(()=>a.value?wg(o.value):[]);function d(){i.value=!0}function f(){i.value=!1}function g(){i.value?f():d()}return{isOpen:i,sidebar:o,sidebarGroups:h,hasSidebar:a,hasAside:c,leftAside:l,isSidebarEnabled:u,open:d,close:f,toggle:g}}function Tg(s,e){let t;Pi(()=>{t=s.value?document.activeElement:void 0}),Nn(()=>{window.addEventListener("keyup",n)}),Gn(()=>{window.removeEventListener("keyup",n)});function n(i){i.key==="Escape"&&s.value&&(e(),t==null||t.focus())}}function Eg(s){const{page:e,hash:t}=ot(),n=Ge(!1),i=ze(()=>s.value.collapsed!=null),r=ze(()=>!!s.value.link),o=Ge(!1),a=()=>{o.value=is(e.value.relativePath,s.value.link)};wt([e,s,t],a),Nn(a);const l=ze(()=>o.value?!0:s.value.items?ec(e.value.relativePath,s.value.items):!1),c=ze(()=>!!(s.value.items&&s.value.items.length));Pi(()=>{n.value=!!(i.value&&s.value.collapsed)}),$d(()=>{(o.value||l.value)&&(n.value=!1)});function u(){i.value&&(n.value=!n.value)}return{collapsed:n,collapsible:i,isLink:r,isActiveLink:o,hasActiveLink:l,hasChildren:c,toggle:u}}function Cg(){const{hasSidebar:s}=li(),e=Kl("(min-width: 960px)"),t=Kl("(min-width: 1280px)");return{isAsideEnabled:ze(()=>!t.value&&!e.value?!1:s.value?t.value:e.value)}}const tc=[];function jd(s){return typeof s.outline=="object"&&!Array.isArray(s.outline)&&s.outline.label||s.outlineTitle||"On this page"}function jc(s){const e=[...document.querySelectorAll(".VPDoc :where(h1,h2,h3,h4,h5,h6)")].filter(t=>t.id&&t.hasChildNodes()).map(t=>{const n=Number(t.tagName[1]);return{element:t,title:Pg(t),link:"#"+t.id,level:n}});return Rg(e,s)}function Pg(s){let e="";for(const t of s.childNodes)if(t.nodeType===1){if(t.classList.contains("VPBadge")||t.classList.contains("header-anchor")||t.classList.contains("ignore-header"))continue;e+=t.textContent}else t.nodeType===3&&(e+=t.textContent);return e.trim()}function Rg(s,e){if(e===!1)return[];const t=(typeof e=="object"&&!Array.isArray(e)?e.level:e)||2,[n,i]=typeof t=="number"?[t,t]:t==="deep"?[2,6]:t;s=s.filter(o=>o.level>=n&&o.level<=i),tc.length=0;for(const{element:o,link:a}of s)tc.push({element:o,link:a});const r=[];e:for(let o=0;o=0;l--){const c=s[l];if(c.level{requestAnimationFrame(r),window.addEventListener("scroll",n)}),Wm(()=>{o(location.hash)}),Gn(()=>{window.removeEventListener("scroll",n)});function r(){if(!t.value)return;const a=window.scrollY,l=window.innerHeight,c=document.body.offsetHeight,u=Math.abs(a+l-c)<1,h=tc.map(({element:f,link:g})=>({link:g,top:Lg(f)})).filter(({top:f})=>!Number.isNaN(f)).sort((f,g)=>f.top-g.top);if(!h.length){o(null);return}if(a<1){o(null);return}if(u){o(h[h.length-1].link);return}let d=null;for(const{link:f,top:g}of h){if(g>a+$m()+4)break;d=f}o(d)}function o(a){i&&i.classList.remove("active"),a==null?i=null:i=s.value.querySelector(`a[href="${decodeURIComponent(a)}"]`);const l=i;l?(l.classList.add("active"),e.value.style.top=l.offsetTop+39+"px",e.value.style.opacity="1"):(e.value.style.top="33px",e.value.style.opacity="0")}}function Lg(s){let e=0;for(;s!==document.body;){if(s===null)return NaN;e+=s.offsetTop,s=s.offsetParent}return e}const Ng=["href","title"],Dg=Ue({__name:"VPDocOutlineItem",props:{headers:{},root:{type:Boolean}},setup(s){function e({target:t}){const n=t.href.split("#")[1],i=document.getElementById(decodeURIComponent(n));i==null||i.focus({preventScroll:!0})}return(t,n)=>{const i=cn("VPDocOutlineItem",!0);return Y(),fe("ul",{class:yt(["VPDocOutlineItem",t.root?"root":"nested"])},[(Y(!0),fe(xt,null,Jt(t.headers,({children:r,link:o,title:a})=>(Y(),fe("li",null,[me("a",{class:"outline-link",href:o,onClick:e,title:a},ft(a),9,Ng),r!=null&&r.length?(Y(),$e(i,{key:0,headers:r},null,8,["headers"])):De("",!0)]))),256))],2)}}}),Qd=Ye(Dg,[["__scopeId","data-v-b933a997"]]),Ug={class:"content"},Og={"aria-level":"2",class:"outline-title",id:"doc-outline-aria-label",role:"heading"},Fg=Ue({__name:"VPDocAsideOutline",setup(s){const{frontmatter:e,theme:t}=ot(),n=Rn([]);Aa(()=>{n.value=jc(e.value.outline??t.value.outline)});const i=Ge(),r=Ge();return Ig(i,r),(o,a)=>(Y(),fe("nav",{"aria-labelledby":"doc-outline-aria-label",class:yt(["VPDocAsideOutline",{"has-outline":n.value.length>0}]),ref_key:"container",ref:i},[me("div",Ug,[me("div",{class:"outline-marker",ref_key:"marker",ref:r},null,512),me("div",Og,ft(ee(jd)(ee(t))),1),ke(Qd,{headers:n.value,root:!0},null,8,["headers"])])],2))}}),kg=Ye(Fg,[["__scopeId","data-v-a5bbad30"]]),Bg={class:"VPDocAsideCarbonAds"},zg=Ue({__name:"VPDocAsideCarbonAds",props:{carbonAds:{}},setup(s){const e=()=>null;return(t,n)=>(Y(),fe("div",Bg,[ke(ee(e),{"carbon-ads":t.carbonAds},null,8,["carbon-ads"])]))}}),Vg=s=>(Wt("data-v-3f215769"),s=s(),$t(),s),Hg={class:"VPDocAside"},Gg=Vg(()=>me("div",{class:"spacer"},null,-1)),Wg=Ue({__name:"VPDocAside",setup(s){const{theme:e}=ot();return(t,n)=>(Y(),fe("div",Hg,[ue(t.$slots,"aside-top",{},void 0,!0),ue(t.$slots,"aside-outline-before",{},void 0,!0),ke(kg),ue(t.$slots,"aside-outline-after",{},void 0,!0),Gg,ue(t.$slots,"aside-ads-before",{},void 0,!0),ee(e).carbonAds?(Y(),$e(zg,{key:0,"carbon-ads":ee(e).carbonAds},null,8,["carbon-ads"])):De("",!0),ue(t.$slots,"aside-ads-after",{},void 0,!0),ue(t.$slots,"aside-bottom",{},void 0,!0)]))}}),$g=Ye(Wg,[["__scopeId","data-v-3f215769"]]);function Xg(){const{theme:s,page:e}=ot();return ze(()=>{const{text:t="Edit this page",pattern:n=""}=s.value.editLink||{};let i;return typeof n=="function"?i=n(e.value):i=n.replace(/:path/g,e.value.filePath),{url:i,text:t}})}function qg(){const{page:s,theme:e,frontmatter:t}=ot();return ze(()=>{var c,u,h,d,f,g,v,p;const n=Kd(e.value.sidebar,s.value.relativePath),i=Ag(n),r=Yg(i,m=>m.link.replace(/[?#].*$/,"")),o=r.findIndex(m=>is(s.value.relativePath,m.link)),a=((c=e.value.docFooter)==null?void 0:c.prev)===!1&&!t.value.prev||t.value.prev===!1,l=((u=e.value.docFooter)==null?void 0:u.next)===!1&&!t.value.next||t.value.next===!1;return{prev:a?void 0:{text:(typeof t.value.prev=="string"?t.value.prev:typeof t.value.prev=="object"?t.value.prev.text:void 0)??((h=r[o-1])==null?void 0:h.docFooterText)??((d=r[o-1])==null?void 0:d.text),link:(typeof t.value.prev=="object"?t.value.prev.link:void 0)??((f=r[o-1])==null?void 0:f.link)},next:l?void 0:{text:(typeof t.value.next=="string"?t.value.next:typeof t.value.next=="object"?t.value.next.text:void 0)??((g=r[o+1])==null?void 0:g.docFooterText)??((v=r[o+1])==null?void 0:v.text),link:(typeof t.value.next=="object"?t.value.next.link:void 0)??((p=r[o+1])==null?void 0:p.link)}}})}function Yg(s,e){const t=new Set;return s.filter(n=>{const i=e(n);return t.has(i)?!1:t.add(i)})}const Vn=Ue({__name:"VPLink",props:{tag:{},href:{},noIcon:{type:Boolean},target:{},rel:{}},setup(s){const e=s,t=ze(()=>e.tag??(e.href?"a":"span")),n=ze(()=>e.href&&Xd.test(e.href)||e.target==="_blank");return(i,r)=>(Y(),$e(Bs(t.value),{class:yt(["VPLink",{link:i.href,"vp-external-link-icon":n.value,"no-icon":i.noIcon}]),href:i.href?ee(Kc)(i.href):void 0,target:i.target??(n.value?"_blank":void 0),rel:i.rel??(n.value?"noreferrer":void 0)},{default:ye(()=>[ue(i.$slots,"default")]),_:3},8,["class","href","target","rel"]))}}),Zg={class:"VPLastUpdated"},Jg=["datetime"],Kg=Ue({__name:"VPDocFooterLastUpdated",setup(s){const{theme:e,page:t,frontmatter:n,lang:i}=ot(),r=ze(()=>new Date(n.value.lastUpdated??t.value.lastUpdated)),o=ze(()=>r.value.toISOString()),a=Ge("");return Nn(()=>{Pi(()=>{var l,c,u;a.value=new Intl.DateTimeFormat((c=(l=e.value.lastUpdated)==null?void 0:l.formatOptions)!=null&&c.forceLocale?i.value:void 0,((u=e.value.lastUpdated)==null?void 0:u.formatOptions)??{dateStyle:"short",timeStyle:"short"}).format(r.value)})}),(l,c)=>{var u;return Y(),fe("p",Zg,[Ht(ft(((u=ee(e).lastUpdated)==null?void 0:u.text)||ee(e).lastUpdatedText||"Last updated")+": ",1),me("time",{datetime:o.value},ft(a.value),9,Jg)])}}}),jg=Ye(Kg,[["__scopeId","data-v-7e05ebdb"]]),ef=s=>(Wt("data-v-d4a0bba5"),s=s(),$t(),s),Qg={key:0,class:"VPDocFooter"},ev={key:0,class:"edit-info"},tv={key:0,class:"edit-link"},nv=ef(()=>me("span",{class:"vpi-square-pen edit-link-icon"},null,-1)),iv={key:1,class:"last-updated"},sv={key:1,class:"prev-next","aria-labelledby":"doc-footer-aria-label"},rv=ef(()=>me("span",{class:"visually-hidden",id:"doc-footer-aria-label"},"Pager",-1)),ov={class:"pager"},av=["innerHTML"],lv=["innerHTML"],cv={class:"pager"},uv=["innerHTML"],hv=["innerHTML"],dv=Ue({__name:"VPDocFooter",setup(s){const{theme:e,page:t,frontmatter:n}=ot(),i=Xg(),r=qg(),o=ze(()=>e.value.editLink&&n.value.editLink!==!1),a=ze(()=>t.value.lastUpdated&&n.value.lastUpdated!==!1),l=ze(()=>o.value||a.value||r.value.prev||r.value.next);return(c,u)=>{var h,d,f,g;return l.value?(Y(),fe("footer",Qg,[ue(c.$slots,"doc-footer-before",{},void 0,!0),o.value||a.value?(Y(),fe("div",ev,[o.value?(Y(),fe("div",tv,[ke(Vn,{class:"edit-link-button",href:ee(i).url,"no-icon":!0},{default:ye(()=>[nv,Ht(" "+ft(ee(i).text),1)]),_:1},8,["href"])])):De("",!0),a.value?(Y(),fe("div",iv,[ke(jg)])):De("",!0)])):De("",!0),(h=ee(r).prev)!=null&&h.link||(d=ee(r).next)!=null&&d.link?(Y(),fe("nav",sv,[rv,me("div",ov,[(f=ee(r).prev)!=null&&f.link?(Y(),$e(Vn,{key:0,class:"pager-link prev",href:ee(r).prev.link},{default:ye(()=>{var v;return[me("span",{class:"desc",innerHTML:((v=ee(e).docFooter)==null?void 0:v.prev)||"Previous page"},null,8,av),me("span",{class:"title",innerHTML:ee(r).prev.text},null,8,lv)]}),_:1},8,["href"])):De("",!0)]),me("div",cv,[(g=ee(r).next)!=null&&g.link?(Y(),$e(Vn,{key:0,class:"pager-link next",href:ee(r).next.link},{default:ye(()=>{var v;return[me("span",{class:"desc",innerHTML:((v=ee(e).docFooter)==null?void 0:v.next)||"Next page"},null,8,uv),me("span",{class:"title",innerHTML:ee(r).next.text},null,8,hv)]}),_:1},8,["href"])):De("",!0)])])):De("",!0)])):De("",!0)}}}),fv=Ye(dv,[["__scopeId","data-v-d4a0bba5"]]),pv=s=>(Wt("data-v-39a288b8"),s=s(),$t(),s),mv={class:"container"},gv=pv(()=>me("div",{class:"aside-curtain"},null,-1)),vv={class:"aside-container"},_v={class:"aside-content"},yv={class:"content"},xv={class:"content-container"},Mv={class:"main"},bv=Ue({__name:"VPDoc",setup(s){const{theme:e}=ot(),t=zr(),{hasSidebar:n,hasAside:i,leftAside:r}=li(),o=ze(()=>t.path.replace(/[./]+/g,"_").replace(/_html$/,""));return(a,l)=>{const c=cn("Content");return Y(),fe("div",{class:yt(["VPDoc",{"has-sidebar":ee(n),"has-aside":ee(i)}])},[ue(a.$slots,"doc-top",{},void 0,!0),me("div",mv,[ee(i)?(Y(),fe("div",{key:0,class:yt(["aside",{"left-aside":ee(r)}])},[gv,me("div",vv,[me("div",_v,[ke($g,null,{"aside-top":ye(()=>[ue(a.$slots,"aside-top",{},void 0,!0)]),"aside-bottom":ye(()=>[ue(a.$slots,"aside-bottom",{},void 0,!0)]),"aside-outline-before":ye(()=>[ue(a.$slots,"aside-outline-before",{},void 0,!0)]),"aside-outline-after":ye(()=>[ue(a.$slots,"aside-outline-after",{},void 0,!0)]),"aside-ads-before":ye(()=>[ue(a.$slots,"aside-ads-before",{},void 0,!0)]),"aside-ads-after":ye(()=>[ue(a.$slots,"aside-ads-after",{},void 0,!0)]),_:3})])])],2)):De("",!0),me("div",yv,[me("div",xv,[ue(a.$slots,"doc-before",{},void 0,!0),me("main",Mv,[ke(c,{class:yt(["vp-doc",[o.value,ee(e).externalLinkIcon&&"external-link-icon-enabled"]])},null,8,["class"])]),ke(fv,null,{"doc-footer-before":ye(()=>[ue(a.$slots,"doc-footer-before",{},void 0,!0)]),_:3}),ue(a.$slots,"doc-after",{},void 0,!0)])])]),ue(a.$slots,"doc-bottom",{},void 0,!0)],2)}}}),Sv=Ye(bv,[["__scopeId","data-v-39a288b8"]]),wv=Ue({__name:"VPButton",props:{tag:{},size:{default:"medium"},theme:{default:"brand"},text:{},href:{},target:{},rel:{}},setup(s){const e=s,t=ze(()=>e.href&&Xd.test(e.href)),n=ze(()=>e.tag||e.href?"a":"button");return(i,r)=>(Y(),$e(Bs(n.value),{class:yt(["VPButton",[i.size,i.theme]]),href:i.href?ee(Kc)(i.href):void 0,target:e.target??(t.value?"_blank":void 0),rel:e.rel??(t.value?"noreferrer":void 0)},{default:ye(()=>[Ht(ft(i.text),1)]),_:1},8,["class","href","target","rel"]))}}),Av=Ye(wv,[["__scopeId","data-v-cad61b99"]]),Tv=["src","alt"],Ev=Ue({inheritAttrs:!1,__name:"VPImage",props:{image:{},alt:{}},setup(s){return(e,t)=>{const n=cn("VPImage",!0);return e.image?(Y(),fe(xt,{key:0},[typeof e.image=="string"||"src"in e.image?(Y(),fe("img",ia({key:0,class:"VPImage"},typeof e.image=="string"?e.$attrs:{...e.image,...e.$attrs},{src:ee(Yc)(typeof e.image=="string"?e.image:e.image.src),alt:e.alt??(typeof e.image=="string"?"":e.image.alt||"")}),null,16,Tv)):(Y(),fe(xt,{key:1},[ke(n,ia({class:"dark",image:e.image.dark,alt:e.image.alt},e.$attrs),null,16,["image","alt"]),ke(n,ia({class:"light",image:e.image.light,alt:e.image.alt},e.$attrs),null,16,["image","alt"])],64))],64)):De("",!0)}}}),ga=Ye(Ev,[["__scopeId","data-v-8426fc1a"]]),Cv=s=>(Wt("data-v-303bb580"),s=s(),$t(),s),Pv={class:"container"},Rv={class:"main"},Iv={key:0,class:"name"},Lv=["innerHTML"],Nv=["innerHTML"],Dv=["innerHTML"],Uv={key:0,class:"actions"},Ov={key:0,class:"image"},Fv={class:"image-container"},kv=Cv(()=>me("div",{class:"image-bg"},null,-1)),Bv=Ue({__name:"VPHero",props:{name:{},text:{},tagline:{},image:{},actions:{}},setup(s){const e=Vr("hero-image-slot-exists");return(t,n)=>(Y(),fe("div",{class:yt(["VPHero",{"has-image":t.image||ee(e)}])},[me("div",Pv,[me("div",Rv,[ue(t.$slots,"home-hero-info-before",{},void 0,!0),ue(t.$slots,"home-hero-info",{},()=>[t.name?(Y(),fe("h1",Iv,[me("span",{innerHTML:t.name,class:"clip"},null,8,Lv)])):De("",!0),t.text?(Y(),fe("p",{key:1,innerHTML:t.text,class:"text"},null,8,Nv)):De("",!0),t.tagline?(Y(),fe("p",{key:2,innerHTML:t.tagline,class:"tagline"},null,8,Dv)):De("",!0)],!0),ue(t.$slots,"home-hero-info-after",{},void 0,!0),t.actions?(Y(),fe("div",Uv,[(Y(!0),fe(xt,null,Jt(t.actions,i=>(Y(),fe("div",{key:i.link,class:"action"},[ke(Av,{tag:"a",size:"medium",theme:i.theme,text:i.text,href:i.link,target:i.target,rel:i.rel},null,8,["theme","text","href","target","rel"])]))),128))])):De("",!0),ue(t.$slots,"home-hero-actions-after",{},void 0,!0)]),t.image||ee(e)?(Y(),fe("div",Ov,[me("div",Fv,[kv,ue(t.$slots,"home-hero-image",{},()=>[t.image?(Y(),$e(ga,{key:0,class:"image-src",image:t.image},null,8,["image"])):De("",!0)],!0)])])):De("",!0)])],2))}}),zv=Ye(Bv,[["__scopeId","data-v-303bb580"]]),Vv=Ue({__name:"VPHomeHero",setup(s){const{frontmatter:e}=ot();return(t,n)=>ee(e).hero?(Y(),$e(zv,{key:0,class:"VPHomeHero",name:ee(e).hero.name,text:ee(e).hero.text,tagline:ee(e).hero.tagline,image:ee(e).hero.image,actions:ee(e).hero.actions},{"home-hero-info-before":ye(()=>[ue(t.$slots,"home-hero-info-before")]),"home-hero-info":ye(()=>[ue(t.$slots,"home-hero-info")]),"home-hero-info-after":ye(()=>[ue(t.$slots,"home-hero-info-after")]),"home-hero-actions-after":ye(()=>[ue(t.$slots,"home-hero-actions-after")]),"home-hero-image":ye(()=>[ue(t.$slots,"home-hero-image")]),_:3},8,["name","text","tagline","image","actions"])):De("",!0)}}),Hv=s=>(Wt("data-v-a3976bdc"),s=s(),$t(),s),Gv={class:"box"},Wv={key:0,class:"icon"},$v=["innerHTML"],Xv=["innerHTML"],qv=["innerHTML"],Yv={key:4,class:"link-text"},Zv={class:"link-text-value"},Jv=Hv(()=>me("span",{class:"vpi-arrow-right link-text-icon"},null,-1)),Kv=Ue({__name:"VPFeature",props:{icon:{},title:{},details:{},link:{},linkText:{},rel:{},target:{}},setup(s){return(e,t)=>(Y(),$e(Vn,{class:"VPFeature",href:e.link,rel:e.rel,target:e.target,"no-icon":!0,tag:e.link?"a":"div"},{default:ye(()=>[me("article",Gv,[typeof e.icon=="object"&&e.icon.wrap?(Y(),fe("div",Wv,[ke(ga,{image:e.icon,alt:e.icon.alt,height:e.icon.height||48,width:e.icon.width||48},null,8,["image","alt","height","width"])])):typeof e.icon=="object"?(Y(),$e(ga,{key:1,image:e.icon,alt:e.icon.alt,height:e.icon.height||48,width:e.icon.width||48},null,8,["image","alt","height","width"])):e.icon?(Y(),fe("div",{key:2,class:"icon",innerHTML:e.icon},null,8,$v)):De("",!0),me("h2",{class:"title",innerHTML:e.title},null,8,Xv),e.details?(Y(),fe("p",{key:3,class:"details",innerHTML:e.details},null,8,qv)):De("",!0),e.linkText?(Y(),fe("div",Yv,[me("p",Zv,[Ht(ft(e.linkText)+" ",1),Jv])])):De("",!0)])]),_:1},8,["href","rel","target","tag"]))}}),jv=Ye(Kv,[["__scopeId","data-v-a3976bdc"]]),Qv={key:0,class:"VPFeatures"},e_={class:"container"},t_={class:"items"},n_=Ue({__name:"VPFeatures",props:{features:{}},setup(s){const e=s,t=ze(()=>{const n=e.features.length;if(n){if(n===2)return"grid-2";if(n===3)return"grid-3";if(n%3===0)return"grid-6";if(n>3)return"grid-4"}else return});return(n,i)=>n.features?(Y(),fe("div",Qv,[me("div",e_,[me("div",t_,[(Y(!0),fe(xt,null,Jt(n.features,r=>(Y(),fe("div",{key:r.title,class:yt(["item",[t.value]])},[ke(jv,{icon:r.icon,title:r.title,details:r.details,link:r.link,"link-text":r.linkText,rel:r.rel,target:r.target},null,8,["icon","title","details","link","link-text","rel","target"])],2))),128))])])])):De("",!0)}}),i_=Ye(n_,[["__scopeId","data-v-a6181336"]]),s_=Ue({__name:"VPHomeFeatures",setup(s){const{frontmatter:e}=ot();return(t,n)=>ee(e).features?(Y(),$e(i_,{key:0,class:"VPHomeFeatures",features:ee(e).features},null,8,["features"])):De("",!0)}}),r_=Ue({__name:"VPHomeContent",setup(s){const{width:e}=Xm({initialWidth:0,includeScrollbar:!1});return(t,n)=>(Y(),fe("div",{class:"vp-doc container",style:Zc(ee(e)?{"--vp-offset":`calc(50% - ${ee(e)/2}px)`}:{})},[ue(t.$slots,"default",{},void 0,!0)],4))}}),o_=Ye(r_,[["__scopeId","data-v-8e2d4988"]]),a_={class:"VPHome"},l_=Ue({__name:"VPHome",setup(s){const{frontmatter:e}=ot();return(t,n)=>{const i=cn("Content");return Y(),fe("div",a_,[ue(t.$slots,"home-hero-before",{},void 0,!0),ke(Vv,null,{"home-hero-info-before":ye(()=>[ue(t.$slots,"home-hero-info-before",{},void 0,!0)]),"home-hero-info":ye(()=>[ue(t.$slots,"home-hero-info",{},void 0,!0)]),"home-hero-info-after":ye(()=>[ue(t.$slots,"home-hero-info-after",{},void 0,!0)]),"home-hero-actions-after":ye(()=>[ue(t.$slots,"home-hero-actions-after",{},void 0,!0)]),"home-hero-image":ye(()=>[ue(t.$slots,"home-hero-image",{},void 0,!0)]),_:3}),ue(t.$slots,"home-hero-after",{},void 0,!0),ue(t.$slots,"home-features-before",{},void 0,!0),ke(s_),ue(t.$slots,"home-features-after",{},void 0,!0),ee(e).markdownStyles!==!1?(Y(),$e(o_,{key:0},{default:ye(()=>[ke(i)]),_:1})):(Y(),$e(i,{key:1}))])}}}),c_=Ye(l_,[["__scopeId","data-v-686f80a6"]]),u_={},h_={class:"VPPage"};function d_(s,e){const t=cn("Content");return Y(),fe("div",h_,[ue(s.$slots,"page-top"),ke(t),ue(s.$slots,"page-bottom")])}const f_=Ye(u_,[["render",d_]]),p_=Ue({__name:"VPContent",setup(s){const{page:e,frontmatter:t}=ot(),{hasSidebar:n}=li();return(i,r)=>(Y(),fe("div",{class:yt(["VPContent",{"has-sidebar":ee(n),"is-home":ee(t).layout==="home"}]),id:"VPContent"},[ee(e).isNotFound?ue(i.$slots,"not-found",{key:0},()=>[ke(Sg)],!0):ee(t).layout==="page"?(Y(),$e(f_,{key:1},{"page-top":ye(()=>[ue(i.$slots,"page-top",{},void 0,!0)]),"page-bottom":ye(()=>[ue(i.$slots,"page-bottom",{},void 0,!0)]),_:3})):ee(t).layout==="home"?(Y(),$e(c_,{key:2},{"home-hero-before":ye(()=>[ue(i.$slots,"home-hero-before",{},void 0,!0)]),"home-hero-info-before":ye(()=>[ue(i.$slots,"home-hero-info-before",{},void 0,!0)]),"home-hero-info":ye(()=>[ue(i.$slots,"home-hero-info",{},void 0,!0)]),"home-hero-info-after":ye(()=>[ue(i.$slots,"home-hero-info-after",{},void 0,!0)]),"home-hero-actions-after":ye(()=>[ue(i.$slots,"home-hero-actions-after",{},void 0,!0)]),"home-hero-image":ye(()=>[ue(i.$slots,"home-hero-image",{},void 0,!0)]),"home-hero-after":ye(()=>[ue(i.$slots,"home-hero-after",{},void 0,!0)]),"home-features-before":ye(()=>[ue(i.$slots,"home-features-before",{},void 0,!0)]),"home-features-after":ye(()=>[ue(i.$slots,"home-features-after",{},void 0,!0)]),_:3})):ee(t).layout&&ee(t).layout!=="doc"?(Y(),$e(Bs(ee(t).layout),{key:3})):(Y(),$e(Sv,{key:4},{"doc-top":ye(()=>[ue(i.$slots,"doc-top",{},void 0,!0)]),"doc-bottom":ye(()=>[ue(i.$slots,"doc-bottom",{},void 0,!0)]),"doc-footer-before":ye(()=>[ue(i.$slots,"doc-footer-before",{},void 0,!0)]),"doc-before":ye(()=>[ue(i.$slots,"doc-before",{},void 0,!0)]),"doc-after":ye(()=>[ue(i.$slots,"doc-after",{},void 0,!0)]),"aside-top":ye(()=>[ue(i.$slots,"aside-top",{},void 0,!0)]),"aside-outline-before":ye(()=>[ue(i.$slots,"aside-outline-before",{},void 0,!0)]),"aside-outline-after":ye(()=>[ue(i.$slots,"aside-outline-after",{},void 0,!0)]),"aside-ads-before":ye(()=>[ue(i.$slots,"aside-ads-before",{},void 0,!0)]),"aside-ads-after":ye(()=>[ue(i.$slots,"aside-ads-after",{},void 0,!0)]),"aside-bottom":ye(()=>[ue(i.$slots,"aside-bottom",{},void 0,!0)]),_:3}))],2))}}),m_=Ye(p_,[["__scopeId","data-v-1428d186"]]),g_={class:"container"},v_=["innerHTML"],__=["innerHTML"],y_=Ue({__name:"VPFooter",setup(s){const{theme:e,frontmatter:t}=ot(),{hasSidebar:n}=li();return(i,r)=>ee(e).footer&&ee(t).footer!==!1?(Y(),fe("footer",{key:0,class:yt(["VPFooter",{"has-sidebar":ee(n)}])},[me("div",g_,[ee(e).footer.message?(Y(),fe("p",{key:0,class:"message",innerHTML:ee(e).footer.message},null,8,v_)):De("",!0),ee(e).footer.copyright?(Y(),fe("p",{key:1,class:"copyright",innerHTML:ee(e).footer.copyright},null,8,__)):De("",!0)])],2)):De("",!0)}}),x_=Ye(y_,[["__scopeId","data-v-e315a0ad"]]);function M_(){const{theme:s,frontmatter:e}=ot(),t=Rn([]),n=ze(()=>t.value.length>0);return Aa(()=>{t.value=jc(e.value.outline??s.value.outline)}),{headers:t,hasLocalNav:n}}const b_=s=>(Wt("data-v-17a5e62e"),s=s(),$t(),s),S_={class:"menu-text"},w_=b_(()=>me("span",{class:"vpi-chevron-right icon"},null,-1)),A_={class:"header"},T_={class:"outline"},E_=Ue({__name:"VPLocalNavOutlineDropdown",props:{headers:{},navHeight:{}},setup(s){const e=s,{theme:t}=ot(),n=Ge(!1),i=Ge(0),r=Ge(),o=Ge();function a(h){var d;(d=r.value)!=null&&d.contains(h.target)||(n.value=!1)}wt(n,h=>{if(h){document.addEventListener("click",a);return}document.removeEventListener("click",a)}),jl("Escape",()=>{n.value=!1}),Aa(()=>{n.value=!1});function l(){n.value=!n.value,i.value=window.innerHeight+Math.min(window.scrollY-e.navHeight,0)}function c(h){h.target.classList.contains("outline-link")&&(o.value&&(o.value.style.transition="none"),Jc(()=>{n.value=!1}))}function u(){n.value=!1,window.scrollTo({top:0,left:0,behavior:"smooth"})}return(h,d)=>(Y(),fe("div",{class:"VPLocalNavOutlineDropdown",style:Zc({"--vp-vh":i.value+"px"}),ref_key:"main",ref:r},[h.headers.length>0?(Y(),fe("button",{key:0,onClick:l,class:yt({open:n.value})},[me("span",S_,ft(ee(jd)(ee(t))),1),w_],2)):(Y(),fe("button",{key:1,onClick:u},ft(ee(t).returnToTopLabel||"Return to top"),1)),ke(qc,{name:"flyout"},{default:ye(()=>[n.value?(Y(),fe("div",{key:0,ref_key:"items",ref:o,class:"items",onClick:c},[me("div",A_,[me("a",{class:"top-link",href:"#",onClick:u},ft(ee(t).returnToTopLabel||"Return to top"),1)]),me("div",T_,[ke(Qd,{headers:h.headers},null,8,["headers"])])],512)):De("",!0)]),_:1})],4))}}),C_=Ye(E_,[["__scopeId","data-v-17a5e62e"]]),P_=s=>(Wt("data-v-a6f0e41e"),s=s(),$t(),s),R_={class:"container"},I_=["aria-expanded"],L_=P_(()=>me("span",{class:"vpi-align-left menu-icon"},null,-1)),N_={class:"menu-text"},D_=Ue({__name:"VPLocalNav",props:{open:{type:Boolean}},emits:["open-menu"],setup(s){const{theme:e,frontmatter:t}=ot(),{hasSidebar:n}=li(),{headers:i}=M_(),{y:r}=qd(),o=Ge(0);Nn(()=>{o.value=parseInt(getComputedStyle(document.documentElement).getPropertyValue("--vp-nav-height"))}),Aa(()=>{i.value=jc(t.value.outline??e.value.outline)});const a=ze(()=>i.value.length===0),l=ze(()=>a.value&&!n.value),c=ze(()=>({VPLocalNav:!0,"has-sidebar":n.value,empty:a.value,fixed:l.value}));return(u,h)=>ee(t).layout!=="home"&&(!l.value||ee(r)>=o.value)?(Y(),fe("div",{key:0,class:yt(c.value)},[me("div",R_,[ee(n)?(Y(),fe("button",{key:0,class:"menu","aria-expanded":u.open,"aria-controls":"VPSidebarNav",onClick:h[0]||(h[0]=d=>u.$emit("open-menu"))},[L_,me("span",N_,ft(ee(e).sidebarMenuLabel||"Menu"),1)],8,I_)):De("",!0),ke(C_,{headers:ee(i),navHeight:o.value},null,8,["headers","navHeight"])])],2)):De("",!0)}}),U_=Ye(D_,[["__scopeId","data-v-a6f0e41e"]]);function O_(){const s=Ge(!1);function e(){s.value=!0,window.addEventListener("resize",i)}function t(){s.value=!1,window.removeEventListener("resize",i)}function n(){s.value?t():e()}function i(){window.outerWidth>=768&&t()}const r=zr();return wt(()=>r.path,t),{isScreenOpen:s,openScreen:e,closeScreen:t,toggleScreen:n}}const F_={},k_={class:"VPSwitch",type:"button",role:"switch"},B_={class:"check"},z_={key:0,class:"icon"};function V_(s,e){return Y(),fe("button",k_,[me("span",B_,[s.$slots.default?(Y(),fe("span",z_,[ue(s.$slots,"default",{},void 0,!0)])):De("",!0)])])}const H_=Ye(F_,[["render",V_],["__scopeId","data-v-1d5665e3"]]),tf=s=>(Wt("data-v-d1f28634"),s=s(),$t(),s),G_=tf(()=>me("span",{class:"vpi-sun sun"},null,-1)),W_=tf(()=>me("span",{class:"vpi-moon moon"},null,-1)),$_=Ue({__name:"VPSwitchAppearance",setup(s){const{isDark:e,theme:t}=ot(),n=Vr("toggle-appearance",()=>{e.value=!e.value}),i=ze(()=>e.value?t.value.lightModeSwitchTitle||"Switch to light theme":t.value.darkModeSwitchTitle||"Switch to dark theme");return(r,o)=>(Y(),$e(H_,{title:i.value,class:"VPSwitchAppearance","aria-checked":ee(e),onClick:ee(n)},{default:ye(()=>[G_,W_]),_:1},8,["title","aria-checked","onClick"]))}}),Qc=Ye($_,[["__scopeId","data-v-d1f28634"]]),X_={key:0,class:"VPNavBarAppearance"},q_=Ue({__name:"VPNavBarAppearance",setup(s){const{site:e}=ot();return(t,n)=>ee(e).appearance&&ee(e).appearance!=="force-dark"?(Y(),fe("div",X_,[ke(Qc)])):De("",!0)}}),Y_=Ye(q_,[["__scopeId","data-v-e6aabb21"]]),eu=Ge();let nf=!1,cl=0;function Z_(s){const e=Ge(!1);if(Ta){!nf&&J_(),cl++;const t=wt(eu,n=>{var i,r,o;n===s.el.value||(i=s.el.value)!=null&&i.contains(n)?(e.value=!0,(r=s.onFocus)==null||r.call(s)):(e.value=!1,(o=s.onBlur)==null||o.call(s))});Gn(()=>{t(),cl--,cl||K_()})}return gr(e)}function J_(){document.addEventListener("focusin",sf),nf=!0,eu.value=document.activeElement}function K_(){document.removeEventListener("focusin",sf)}function sf(){eu.value=document.activeElement}const j_={class:"VPMenuLink"},Q_=Ue({__name:"VPMenuLink",props:{item:{}},setup(s){const{page:e}=ot();return(t,n)=>(Y(),fe("div",j_,[ke(Vn,{class:yt({active:ee(is)(ee(e).relativePath,t.item.activeMatch||t.item.link,!!t.item.activeMatch)}),href:t.item.link,target:t.item.target,rel:t.item.rel},{default:ye(()=>[Ht(ft(t.item.text),1)]),_:1},8,["class","href","target","rel"])]))}}),Ea=Ye(Q_,[["__scopeId","data-v-43f1e123"]]),e0={class:"VPMenuGroup"},t0={key:0,class:"title"},n0=Ue({__name:"VPMenuGroup",props:{text:{},items:{}},setup(s){return(e,t)=>(Y(),fe("div",e0,[e.text?(Y(),fe("p",t0,ft(e.text),1)):De("",!0),(Y(!0),fe(xt,null,Jt(e.items,n=>(Y(),fe(xt,null,["link"in n?(Y(),$e(Ea,{key:0,item:n},null,8,["item"])):De("",!0)],64))),256))]))}}),i0=Ye(n0,[["__scopeId","data-v-69e747b5"]]),s0={class:"VPMenu"},r0={key:0,class:"items"},o0=Ue({__name:"VPMenu",props:{items:{}},setup(s){return(e,t)=>(Y(),fe("div",s0,[e.items?(Y(),fe("div",r0,[(Y(!0),fe(xt,null,Jt(e.items,n=>(Y(),fe(xt,{key:n.text},["link"in n?(Y(),$e(Ea,{key:0,item:n},null,8,["item"])):(Y(),$e(i0,{key:1,text:n.text,items:n.items},null,8,["text","items"]))],64))),128))])):De("",!0),ue(e.$slots,"default",{},void 0,!0)]))}}),a0=Ye(o0,[["__scopeId","data-v-e7ea1737"]]),l0=s=>(Wt("data-v-b6c34ac9"),s=s(),$t(),s),c0=["aria-expanded","aria-label"],u0={key:0,class:"text"},h0=["innerHTML"],d0=l0(()=>me("span",{class:"vpi-chevron-down text-icon"},null,-1)),f0={key:1,class:"vpi-more-horizontal icon"},p0={class:"menu"},m0=Ue({__name:"VPFlyout",props:{icon:{},button:{},label:{},items:{}},setup(s){const e=Ge(!1),t=Ge();Z_({el:t,onBlur:n});function n(){e.value=!1}return(i,r)=>(Y(),fe("div",{class:"VPFlyout",ref_key:"el",ref:t,onMouseenter:r[1]||(r[1]=o=>e.value=!0),onMouseleave:r[2]||(r[2]=o=>e.value=!1)},[me("button",{type:"button",class:"button","aria-haspopup":"true","aria-expanded":e.value,"aria-label":i.label,onClick:r[0]||(r[0]=o=>e.value=!e.value)},[i.button||i.icon?(Y(),fe("span",u0,[i.icon?(Y(),fe("span",{key:0,class:yt([i.icon,"option-icon"])},null,2)):De("",!0),i.button?(Y(),fe("span",{key:1,innerHTML:i.button},null,8,h0)):De("",!0),d0])):(Y(),fe("span",f0))],8,c0),me("div",p0,[ke(a0,{items:i.items},{default:ye(()=>[ue(i.$slots,"default",{},void 0,!0)]),_:3},8,["items"])])],544))}}),tu=Ye(m0,[["__scopeId","data-v-b6c34ac9"]]),g0=["href","aria-label","innerHTML"],v0=Ue({__name:"VPSocialLink",props:{icon:{},link:{},ariaLabel:{}},setup(s){const e=s,t=ze(()=>typeof e.icon=="object"?e.icon.svg:``);return(n,i)=>(Y(),fe("a",{class:"VPSocialLink no-icon",href:n.link,"aria-label":n.ariaLabel??(typeof n.icon=="string"?n.icon:""),target:"_blank",rel:"noopener",innerHTML:t.value},null,8,g0))}}),_0=Ye(v0,[["__scopeId","data-v-eee4e7cb"]]),y0={class:"VPSocialLinks"},x0=Ue({__name:"VPSocialLinks",props:{links:{}},setup(s){return(e,t)=>(Y(),fe("div",y0,[(Y(!0),fe(xt,null,Jt(e.links,({link:n,icon:i,ariaLabel:r})=>(Y(),$e(_0,{key:n,icon:i,link:n,ariaLabel:r},null,8,["icon","link","ariaLabel"]))),128))]))}}),nu=Ye(x0,[["__scopeId","data-v-7bc22406"]]),M0={key:0,class:"group translations"},b0={class:"trans-title"},S0={key:1,class:"group"},w0={class:"item appearance"},A0={class:"label"},T0={class:"appearance-action"},E0={key:2,class:"group"},C0={class:"item social-links"},P0=Ue({__name:"VPNavBarExtra",setup(s){const{site:e,theme:t}=ot(),{localeLinks:n,currentLang:i}=Hr({correspondingLink:!0}),r=ze(()=>n.value.length&&i.value.label||e.value.appearance||t.value.socialLinks);return(o,a)=>r.value?(Y(),$e(tu,{key:0,class:"VPNavBarExtra",label:"extra navigation"},{default:ye(()=>[ee(n).length&&ee(i).label?(Y(),fe("div",M0,[me("p",b0,ft(ee(i).label),1),(Y(!0),fe(xt,null,Jt(ee(n),l=>(Y(),$e(Ea,{key:l.link,item:l},null,8,["item"]))),128))])):De("",!0),ee(e).appearance&&ee(e).appearance!=="force-dark"?(Y(),fe("div",S0,[me("div",w0,[me("p",A0,ft(ee(t).darkModeSwitchLabel||"Appearance"),1),me("div",T0,[ke(Qc)])])])):De("",!0),ee(t).socialLinks?(Y(),fe("div",E0,[me("div",C0,[ke(nu,{class:"social-links-list",links:ee(t).socialLinks},null,8,["links"])])])):De("",!0)]),_:1})):De("",!0)}}),R0=Ye(P0,[["__scopeId","data-v-d0bd9dde"]]),I0=s=>(Wt("data-v-e5dd9c1c"),s=s(),$t(),s),L0=["aria-expanded"],N0=I0(()=>me("span",{class:"container"},[me("span",{class:"top"}),me("span",{class:"middle"}),me("span",{class:"bottom"})],-1)),D0=[N0],U0=Ue({__name:"VPNavBarHamburger",props:{active:{type:Boolean}},emits:["click"],setup(s){return(e,t)=>(Y(),fe("button",{type:"button",class:yt(["VPNavBarHamburger",{active:e.active}]),"aria-label":"mobile navigation","aria-expanded":e.active,"aria-controls":"VPNavScreen",onClick:t[0]||(t[0]=n=>e.$emit("click"))},D0,10,L0))}}),O0=Ye(U0,[["__scopeId","data-v-e5dd9c1c"]]),F0=["innerHTML"],k0=Ue({__name:"VPNavBarMenuLink",props:{item:{}},setup(s){const{page:e}=ot();return(t,n)=>(Y(),$e(Vn,{class:yt({VPNavBarMenuLink:!0,active:ee(is)(ee(e).relativePath,t.item.activeMatch||t.item.link,!!t.item.activeMatch)}),href:t.item.link,noIcon:t.item.noIcon,target:t.item.target,rel:t.item.rel,tabindex:"0"},{default:ye(()=>[me("span",{innerHTML:t.item.text},null,8,F0)]),_:1},8,["class","href","noIcon","target","rel"]))}}),B0=Ye(k0,[["__scopeId","data-v-9c663999"]]),z0=Ue({__name:"VPNavBarMenuGroup",props:{item:{}},setup(s){const e=s,{page:t}=ot(),n=r=>"link"in r?is(t.value.relativePath,r.link,!!e.item.activeMatch):r.items.some(n),i=ze(()=>n(e.item));return(r,o)=>(Y(),$e(tu,{class:yt({VPNavBarMenuGroup:!0,active:ee(is)(ee(t).relativePath,r.item.activeMatch,!!r.item.activeMatch)||i.value}),button:r.item.text,items:r.item.items},null,8,["class","button","items"]))}}),V0=s=>(Wt("data-v-7f418b0f"),s=s(),$t(),s),H0={key:0,"aria-labelledby":"main-nav-aria-label",class:"VPNavBarMenu"},G0=V0(()=>me("span",{id:"main-nav-aria-label",class:"visually-hidden"},"Main Navigation",-1)),W0=Ue({__name:"VPNavBarMenu",setup(s){const{theme:e}=ot();return(t,n)=>ee(e).nav?(Y(),fe("nav",H0,[G0,(Y(!0),fe(xt,null,Jt(ee(e).nav,i=>(Y(),fe(xt,{key:i.text},["link"in i?(Y(),$e(B0,{key:0,item:i},null,8,["item"])):(Y(),$e(z0,{key:1,item:i},null,8,["item"]))],64))),128))])):De("",!0)}}),$0=Ye(W0,[["__scopeId","data-v-7f418b0f"]]);function X0(s){const{localeIndex:e,theme:t}=ot();function n(i){var g,v,p;const r=i.split("."),o=(g=t.value.search)==null?void 0:g.options,a=o&&typeof o=="object",l=a&&((p=(v=o.locales)==null?void 0:v[e.value])==null?void 0:p.translations)||null,c=a&&o.translations||null;let u=l,h=c,d=s;const f=r.pop();for(const m of r){let y=null;const _=d==null?void 0:d[m];_&&(y=d=_);const x=h==null?void 0:h[m];x&&(y=h=x);const A=u==null?void 0:u[m];A&&(y=u=A),_||(d=y),x||(h=y),A||(u=y)}return(u==null?void 0:u[f])??(h==null?void 0:h[f])??(d==null?void 0:d[f])??""}return n}const q0=["aria-label"],Y0={class:"DocSearch-Button-Container"},Z0=me("span",{class:"vp-icon DocSearch-Search-Icon"},null,-1),J0={class:"DocSearch-Button-Placeholder"},K0=me("span",{class:"DocSearch-Button-Keys"},[me("kbd",{class:"DocSearch-Button-Key"}),me("kbd",{class:"DocSearch-Button-Key"},"K")],-1),th=Ue({__name:"VPNavBarSearchButton",setup(s){const t=X0({button:{buttonText:"Search",buttonAriaLabel:"Search"}});return(n,i)=>(Y(),fe("button",{type:"button",class:"DocSearch DocSearch-Button","aria-label":ee(t)("button.buttonAriaLabel")},[me("span",Y0,[Z0,me("span",J0,ft(ee(t)("button.buttonText")),1)]),K0],8,q0))}}),j0={class:"VPNavBarSearch"},Q0={id:"local-search"},ey={key:1,id:"docsearch"},ty=Ue({__name:"VPNavBarSearch",setup(s){const e=qm(()=>Ym(()=>import("./VPLocalSearchBox.DMasLpNF.js"),__vite__mapDeps([0,1]))),t=()=>null,{theme:n}=ot(),i=Ge(!1),r=Ge(!1);Nn(()=>{});function o(){i.value||(i.value=!0,setTimeout(a,16))}function a(){const h=new Event("keydown");h.key="k",h.metaKey=!0,window.dispatchEvent(h),setTimeout(()=>{document.querySelector(".DocSearch-Modal")||a()},16)}function l(h){const d=h.target,f=d.tagName;return d.isContentEditable||f==="INPUT"||f==="SELECT"||f==="TEXTAREA"}const c=Ge(!1);jl("k",h=>{(h.ctrlKey||h.metaKey)&&(h.preventDefault(),c.value=!0)}),jl("/",h=>{l(h)||(h.preventDefault(),c.value=!0)});const u="local";return(h,d)=>{var f;return Y(),fe("div",j0,[ee(u)==="local"?(Y(),fe(xt,{key:0},[c.value?(Y(),$e(ee(e),{key:0,onClose:d[0]||(d[0]=g=>c.value=!1)})):De("",!0),me("div",Q0,[ke(th,{onClick:d[1]||(d[1]=g=>c.value=!0)})])],64)):ee(u)==="algolia"?(Y(),fe(xt,{key:1},[i.value?(Y(),$e(ee(t),{key:0,algolia:((f=ee(n).search)==null?void 0:f.options)??ee(n).algolia,onVnodeBeforeMount:d[2]||(d[2]=g=>r.value=!0)},null,8,["algolia"])):De("",!0),r.value?De("",!0):(Y(),fe("div",ey,[ke(th,{onClick:o})]))],64)):De("",!0)])}}}),ny=Ue({__name:"VPNavBarSocialLinks",setup(s){const{theme:e}=ot();return(t,n)=>ee(e).socialLinks?(Y(),$e(nu,{key:0,class:"VPNavBarSocialLinks",links:ee(e).socialLinks},null,8,["links"])):De("",!0)}}),iy=Ye(ny,[["__scopeId","data-v-0394ad82"]]),sy=["href","rel","target"],ry={key:1},oy={key:2},ay=Ue({__name:"VPNavBarTitle",setup(s){const{site:e,theme:t}=ot(),{hasSidebar:n}=li(),{currentLang:i}=Hr(),r=ze(()=>{var l;return typeof t.value.logoLink=="string"?t.value.logoLink:(l=t.value.logoLink)==null?void 0:l.link}),o=ze(()=>{var l;return typeof t.value.logoLink=="string"||(l=t.value.logoLink)==null?void 0:l.rel}),a=ze(()=>{var l;return typeof t.value.logoLink=="string"||(l=t.value.logoLink)==null?void 0:l.target});return(l,c)=>(Y(),fe("div",{class:yt(["VPNavBarTitle",{"has-sidebar":ee(n)}])},[me("a",{class:"title",href:r.value??ee(Kc)(ee(i).link),rel:o.value,target:a.value},[ue(l.$slots,"nav-bar-title-before",{},void 0,!0),ee(t).logo?(Y(),$e(ga,{key:0,class:"logo",image:ee(t).logo},null,8,["image"])):De("",!0),ee(t).siteTitle?(Y(),fe("span",ry,ft(ee(t).siteTitle),1)):ee(t).siteTitle===void 0?(Y(),fe("span",oy,ft(ee(e).title),1)):De("",!0),ue(l.$slots,"nav-bar-title-after",{},void 0,!0)],8,sy)],2))}}),ly=Ye(ay,[["__scopeId","data-v-ab179fa1"]]),cy={class:"items"},uy={class:"title"},hy=Ue({__name:"VPNavBarTranslations",setup(s){const{theme:e}=ot(),{localeLinks:t,currentLang:n}=Hr({correspondingLink:!0});return(i,r)=>ee(t).length&&ee(n).label?(Y(),$e(tu,{key:0,class:"VPNavBarTranslations",icon:"vpi-languages",label:ee(e).langMenuLabel||"Change language"},{default:ye(()=>[me("div",cy,[me("p",uy,ft(ee(n).label),1),(Y(!0),fe(xt,null,Jt(ee(t),o=>(Y(),$e(Ea,{key:o.link,item:o},null,8,["item"]))),128))])]),_:1},8,["label"])):De("",!0)}}),dy=Ye(hy,[["__scopeId","data-v-88af2de4"]]),fy=s=>(Wt("data-v-ccf7ddec"),s=s(),$t(),s),py={class:"wrapper"},my={class:"container"},gy={class:"title"},vy={class:"content"},_y={class:"content-body"},yy=fy(()=>me("div",{class:"divider"},[me("div",{class:"divider-line"})],-1)),xy=Ue({__name:"VPNavBar",props:{isScreenOpen:{type:Boolean}},emits:["toggle-screen"],setup(s){const{y:e}=qd(),{hasSidebar:t}=li(),{frontmatter:n}=ot(),i=Ge({});return $d(()=>{i.value={"has-sidebar":t.value,home:n.value.layout==="home",top:e.value===0}}),(r,o)=>(Y(),fe("div",{class:yt(["VPNavBar",i.value])},[me("div",py,[me("div",my,[me("div",gy,[ke(ly,null,{"nav-bar-title-before":ye(()=>[ue(r.$slots,"nav-bar-title-before",{},void 0,!0)]),"nav-bar-title-after":ye(()=>[ue(r.$slots,"nav-bar-title-after",{},void 0,!0)]),_:3})]),me("div",vy,[me("div",_y,[ue(r.$slots,"nav-bar-content-before",{},void 0,!0),ke(ty,{class:"search"}),ke($0,{class:"menu"}),ke(dy,{class:"translations"}),ke(Y_,{class:"appearance"}),ke(iy,{class:"social-links"}),ke(R0,{class:"extra"}),ue(r.$slots,"nav-bar-content-after",{},void 0,!0),ke(O0,{class:"hamburger",active:r.isScreenOpen,onClick:o[0]||(o[0]=a=>r.$emit("toggle-screen"))},null,8,["active"])])])])]),yy],2))}}),My=Ye(xy,[["__scopeId","data-v-ccf7ddec"]]),by={key:0,class:"VPNavScreenAppearance"},Sy={class:"text"},wy=Ue({__name:"VPNavScreenAppearance",setup(s){const{site:e,theme:t}=ot();return(n,i)=>ee(e).appearance&&ee(e).appearance!=="force-dark"?(Y(),fe("div",by,[me("p",Sy,ft(ee(t).darkModeSwitchLabel||"Appearance"),1),ke(Qc)])):De("",!0)}}),Ay=Ye(wy,[["__scopeId","data-v-2d7af913"]]),Ty=Ue({__name:"VPNavScreenMenuLink",props:{item:{}},setup(s){const e=Vr("close-screen");return(t,n)=>(Y(),$e(Vn,{class:"VPNavScreenMenuLink",href:t.item.link,target:t.item.target,rel:t.item.rel,onClick:ee(e),innerHTML:t.item.text},null,8,["href","target","rel","onClick","innerHTML"]))}}),Ey=Ye(Ty,[["__scopeId","data-v-7f31e1f6"]]),Cy=Ue({__name:"VPNavScreenMenuGroupLink",props:{item:{}},setup(s){const e=Vr("close-screen");return(t,n)=>(Y(),$e(Vn,{class:"VPNavScreenMenuGroupLink",href:t.item.link,target:t.item.target,rel:t.item.rel,onClick:ee(e)},{default:ye(()=>[Ht(ft(t.item.text),1)]),_:1},8,["href","target","rel","onClick"]))}}),rf=Ye(Cy,[["__scopeId","data-v-19976ae1"]]),Py={class:"VPNavScreenMenuGroupSection"},Ry={key:0,class:"title"},Iy=Ue({__name:"VPNavScreenMenuGroupSection",props:{text:{},items:{}},setup(s){return(e,t)=>(Y(),fe("div",Py,[e.text?(Y(),fe("p",Ry,ft(e.text),1)):De("",!0),(Y(!0),fe(xt,null,Jt(e.items,n=>(Y(),$e(rf,{key:n.text,item:n},null,8,["item"]))),128))]))}}),Ly=Ye(Iy,[["__scopeId","data-v-8133b170"]]),Ny=s=>(Wt("data-v-ff6087d4"),s=s(),$t(),s),Dy=["aria-controls","aria-expanded"],Uy=["innerHTML"],Oy=Ny(()=>me("span",{class:"vpi-plus button-icon"},null,-1)),Fy=["id"],ky={key:1,class:"group"},By=Ue({__name:"VPNavScreenMenuGroup",props:{text:{},items:{}},setup(s){const e=s,t=Ge(!1),n=ze(()=>`NavScreenGroup-${e.text.replace(" ","-").toLowerCase()}`);function i(){t.value=!t.value}return(r,o)=>(Y(),fe("div",{class:yt(["VPNavScreenMenuGroup",{open:t.value}])},[me("button",{class:"button","aria-controls":n.value,"aria-expanded":t.value,onClick:i},[me("span",{class:"button-text",innerHTML:r.text},null,8,Uy),Oy],8,Dy),me("div",{id:n.value,class:"items"},[(Y(!0),fe(xt,null,Jt(r.items,a=>(Y(),fe(xt,{key:a.text},["link"in a?(Y(),fe("div",{key:a.text,class:"item"},[ke(rf,{item:a},null,8,["item"])])):(Y(),fe("div",ky,[ke(Ly,{text:a.text,items:a.items},null,8,["text","items"])]))],64))),128))],8,Fy)],2))}}),zy=Ye(By,[["__scopeId","data-v-ff6087d4"]]),Vy={key:0,class:"VPNavScreenMenu"},Hy=Ue({__name:"VPNavScreenMenu",setup(s){const{theme:e}=ot();return(t,n)=>ee(e).nav?(Y(),fe("nav",Vy,[(Y(!0),fe(xt,null,Jt(ee(e).nav,i=>(Y(),fe(xt,{key:i.text},["link"in i?(Y(),$e(Ey,{key:0,item:i},null,8,["item"])):(Y(),$e(zy,{key:1,text:i.text||"",items:i.items},null,8,["text","items"]))],64))),128))])):De("",!0)}}),Gy=Ue({__name:"VPNavScreenSocialLinks",setup(s){const{theme:e}=ot();return(t,n)=>ee(e).socialLinks?(Y(),$e(nu,{key:0,class:"VPNavScreenSocialLinks",links:ee(e).socialLinks},null,8,["links"])):De("",!0)}}),of=s=>(Wt("data-v-858fe1a4"),s=s(),$t(),s),Wy=of(()=>me("span",{class:"vpi-languages icon lang"},null,-1)),$y=of(()=>me("span",{class:"vpi-chevron-down icon chevron"},null,-1)),Xy={class:"list"},qy=Ue({__name:"VPNavScreenTranslations",setup(s){const{localeLinks:e,currentLang:t}=Hr({correspondingLink:!0}),n=Ge(!1);function i(){n.value=!n.value}return(r,o)=>ee(e).length&&ee(t).label?(Y(),fe("div",{key:0,class:yt(["VPNavScreenTranslations",{open:n.value}])},[me("button",{class:"title",onClick:i},[Wy,Ht(" "+ft(ee(t).label)+" ",1),$y]),me("ul",Xy,[(Y(!0),fe(xt,null,Jt(ee(e),a=>(Y(),fe("li",{key:a.link,class:"item"},[ke(Vn,{class:"link",href:a.link},{default:ye(()=>[Ht(ft(a.text),1)]),_:2},1032,["href"])]))),128))])],2)):De("",!0)}}),Yy=Ye(qy,[["__scopeId","data-v-858fe1a4"]]),Zy={class:"container"},Jy=Ue({__name:"VPNavScreen",props:{open:{type:Boolean}},setup(s){const e=Ge(null),t=Yd(Ta?document.body:null);return(n,i)=>(Y(),$e(qc,{name:"fade",onEnter:i[0]||(i[0]=r=>t.value=!0),onAfterLeave:i[1]||(i[1]=r=>t.value=!1)},{default:ye(()=>[n.open?(Y(),fe("div",{key:0,class:"VPNavScreen",ref_key:"screen",ref:e,id:"VPNavScreen"},[me("div",Zy,[ue(n.$slots,"nav-screen-content-before",{},void 0,!0),ke(Hy,{class:"menu"}),ke(Yy,{class:"translations"}),ke(Ay,{class:"appearance"}),ke(Gy,{class:"social-links"}),ue(n.$slots,"nav-screen-content-after",{},void 0,!0)])],512)):De("",!0)]),_:3}))}}),Ky=Ye(Jy,[["__scopeId","data-v-cc5739dd"]]),jy={key:0,class:"VPNav"},Qy=Ue({__name:"VPNav",setup(s){const{isScreenOpen:e,closeScreen:t,toggleScreen:n}=O_(),{frontmatter:i}=ot(),r=ze(()=>i.value.navbar!==!1);return vr("close-screen",t),Pi(()=>{Ta&&document.documentElement.classList.toggle("hide-nav",!r.value)}),(o,a)=>r.value?(Y(),fe("header",jy,[ke(My,{"is-screen-open":ee(e),onToggleScreen:ee(n)},{"nav-bar-title-before":ye(()=>[ue(o.$slots,"nav-bar-title-before",{},void 0,!0)]),"nav-bar-title-after":ye(()=>[ue(o.$slots,"nav-bar-title-after",{},void 0,!0)]),"nav-bar-content-before":ye(()=>[ue(o.$slots,"nav-bar-content-before",{},void 0,!0)]),"nav-bar-content-after":ye(()=>[ue(o.$slots,"nav-bar-content-after",{},void 0,!0)]),_:3},8,["is-screen-open","onToggleScreen"]),ke(Ky,{open:ee(e)},{"nav-screen-content-before":ye(()=>[ue(o.$slots,"nav-screen-content-before",{},void 0,!0)]),"nav-screen-content-after":ye(()=>[ue(o.$slots,"nav-screen-content-after",{},void 0,!0)]),_:3},8,["open"])])):De("",!0)}}),ex=Ye(Qy,[["__scopeId","data-v-ae24b3ad"]]),af=s=>(Wt("data-v-b8d55f3b"),s=s(),$t(),s),tx=["role","tabindex"],nx=af(()=>me("div",{class:"indicator"},null,-1)),ix=["onKeydown"],sx=af(()=>me("span",{class:"vpi-chevron-right caret-icon"},null,-1)),rx=[sx],ox={key:1,class:"items"},ax=Ue({__name:"VPSidebarItem",props:{item:{},depth:{}},setup(s){const e=s,{collapsed:t,collapsible:n,isLink:i,isActiveLink:r,hasActiveLink:o,hasChildren:a,toggle:l}=Eg(ze(()=>e.item)),c=ze(()=>a.value?"section":"div"),u=ze(()=>i.value?"a":"div"),h=ze(()=>a.value?e.depth+2===7?"p":`h${e.depth+2}`:"p"),d=ze(()=>i.value?void 0:"button"),f=ze(()=>[[`level-${e.depth}`],{collapsible:n.value},{collapsed:t.value},{"is-link":i.value},{"is-active":r.value},{"has-active":o.value}]);function g(p){"key"in p&&p.key!=="Enter"||!e.item.link&&l()}function v(){e.item.link&&l()}return(p,m)=>{const y=cn("VPSidebarItem",!0);return Y(),$e(Bs(c.value),{class:yt(["VPSidebarItem",f.value])},{default:ye(()=>[p.item.text?(Y(),fe("div",ia({key:0,class:"item",role:d.value},Jm(p.item.items?{click:g,keydown:g}:{},!0),{tabindex:p.item.items&&0}),[nx,p.item.link?(Y(),$e(Vn,{key:0,tag:u.value,class:"link",href:p.item.link,rel:p.item.rel,target:p.item.target},{default:ye(()=>[(Y(),$e(Bs(h.value),{class:"text",innerHTML:p.item.text},null,8,["innerHTML"]))]),_:1},8,["tag","href","rel","target"])):(Y(),$e(Bs(h.value),{key:1,class:"text",innerHTML:p.item.text},null,8,["innerHTML"])),p.item.collapsed!=null&&p.item.items&&p.item.items.length?(Y(),fe("div",{key:2,class:"caret",role:"button","aria-label":"toggle section",onClick:v,onKeydown:Zm(v,["enter"]),tabindex:"0"},rx,40,ix)):De("",!0)],16,tx)):De("",!0),p.item.items&&p.item.items.length?(Y(),fe("div",ox,[p.depth<5?(Y(!0),fe(xt,{key:0},Jt(p.item.items,_=>(Y(),$e(y,{key:_.text,item:_,depth:p.depth+1},null,8,["item","depth"]))),128)):De("",!0)])):De("",!0)]),_:1},8,["class"])}}}),lx=Ye(ax,[["__scopeId","data-v-b8d55f3b"]]),lf=s=>(Wt("data-v-575e6a36"),s=s(),$t(),s),cx=lf(()=>me("div",{class:"curtain"},null,-1)),ux={class:"nav",id:"VPSidebarNav","aria-labelledby":"sidebar-aria-label",tabindex:"-1"},hx=lf(()=>me("span",{class:"visually-hidden",id:"sidebar-aria-label"}," Sidebar Navigation ",-1)),dx=Ue({__name:"VPSidebar",props:{open:{type:Boolean}},setup(s){const e=s,{sidebarGroups:t,hasSidebar:n}=li(),i=Ge(null),r=Yd(Ta?document.body:null);return wt([e,i],()=>{var o;e.open?(r.value=!0,(o=i.value)==null||o.focus()):r.value=!1},{immediate:!0,flush:"post"}),(o,a)=>ee(n)?(Y(),fe("aside",{key:0,class:yt(["VPSidebar",{open:o.open}]),ref_key:"navEl",ref:i,onClick:a[0]||(a[0]=Km(()=>{},["stop"]))},[cx,me("nav",ux,[hx,ue(o.$slots,"sidebar-nav-before",{},void 0,!0),(Y(!0),fe(xt,null,Jt(ee(t),l=>(Y(),fe("div",{key:l.text,class:"group"},[ke(lx,{item:l,depth:0},null,8,["item"])]))),128)),ue(o.$slots,"sidebar-nav-after",{},void 0,!0)])],2)):De("",!0)}}),fx=Ye(dx,[["__scopeId","data-v-575e6a36"]]),px=Ue({__name:"VPSkipLink",setup(s){const e=zr(),t=Ge();wt(()=>e.path,()=>t.value.focus());function n({target:i}){const r=document.getElementById(decodeURIComponent(i.hash).slice(1));if(r){const o=()=>{r.removeAttribute("tabindex"),r.removeEventListener("blur",o)};r.setAttribute("tabindex","-1"),r.addEventListener("blur",o),r.focus(),window.scrollTo(0,0)}}return(i,r)=>(Y(),fe(xt,null,[me("span",{ref_key:"backToTop",ref:t,tabindex:"-1"},null,512),me("a",{href:"#VPContent",class:"VPSkipLink visually-hidden",onClick:n}," Skip to content ")],64))}}),mx=Ye(px,[["__scopeId","data-v-0f60ec36"]]),gx=Ue({__name:"Layout",setup(s){const{isOpen:e,open:t,close:n}=li(),i=zr();wt(()=>i.path,n),Tg(e,n);const{frontmatter:r}=ot(),o=Zd(),a=ze(()=>!!o["home-hero-image"]);return vr("hero-image-slot-exists",a),(l,c)=>{const u=cn("Content");return ee(r).layout!==!1?(Y(),fe("div",{key:0,class:yt(["Layout",ee(r).pageClass])},[ue(l.$slots,"layout-top",{},void 0,!0),ke(mx),ke(hg,{class:"backdrop",show:ee(e),onClick:ee(n)},null,8,["show","onClick"]),ke(ex,null,{"nav-bar-title-before":ye(()=>[ue(l.$slots,"nav-bar-title-before",{},void 0,!0)]),"nav-bar-title-after":ye(()=>[ue(l.$slots,"nav-bar-title-after",{},void 0,!0)]),"nav-bar-content-before":ye(()=>[ue(l.$slots,"nav-bar-content-before",{},void 0,!0)]),"nav-bar-content-after":ye(()=>[ue(l.$slots,"nav-bar-content-after",{},void 0,!0)]),"nav-screen-content-before":ye(()=>[ue(l.$slots,"nav-screen-content-before",{},void 0,!0)]),"nav-screen-content-after":ye(()=>[ue(l.$slots,"nav-screen-content-after",{},void 0,!0)]),_:3}),ke(U_,{open:ee(e),onOpenMenu:ee(t)},null,8,["open","onOpenMenu"]),ke(fx,{open:ee(e)},{"sidebar-nav-before":ye(()=>[ue(l.$slots,"sidebar-nav-before",{},void 0,!0)]),"sidebar-nav-after":ye(()=>[ue(l.$slots,"sidebar-nav-after",{},void 0,!0)]),_:3},8,["open"]),ke(m_,null,{"page-top":ye(()=>[ue(l.$slots,"page-top",{},void 0,!0)]),"page-bottom":ye(()=>[ue(l.$slots,"page-bottom",{},void 0,!0)]),"not-found":ye(()=>[ue(l.$slots,"not-found",{},void 0,!0)]),"home-hero-before":ye(()=>[ue(l.$slots,"home-hero-before",{},void 0,!0)]),"home-hero-info-before":ye(()=>[ue(l.$slots,"home-hero-info-before",{},void 0,!0)]),"home-hero-info":ye(()=>[ue(l.$slots,"home-hero-info",{},void 0,!0)]),"home-hero-info-after":ye(()=>[ue(l.$slots,"home-hero-info-after",{},void 0,!0)]),"home-hero-actions-after":ye(()=>[ue(l.$slots,"home-hero-actions-after",{},void 0,!0)]),"home-hero-image":ye(()=>[ue(l.$slots,"home-hero-image",{},void 0,!0)]),"home-hero-after":ye(()=>[ue(l.$slots,"home-hero-after",{},void 0,!0)]),"home-features-before":ye(()=>[ue(l.$slots,"home-features-before",{},void 0,!0)]),"home-features-after":ye(()=>[ue(l.$slots,"home-features-after",{},void 0,!0)]),"doc-footer-before":ye(()=>[ue(l.$slots,"doc-footer-before",{},void 0,!0)]),"doc-before":ye(()=>[ue(l.$slots,"doc-before",{},void 0,!0)]),"doc-after":ye(()=>[ue(l.$slots,"doc-after",{},void 0,!0)]),"doc-top":ye(()=>[ue(l.$slots,"doc-top",{},void 0,!0)]),"doc-bottom":ye(()=>[ue(l.$slots,"doc-bottom",{},void 0,!0)]),"aside-top":ye(()=>[ue(l.$slots,"aside-top",{},void 0,!0)]),"aside-bottom":ye(()=>[ue(l.$slots,"aside-bottom",{},void 0,!0)]),"aside-outline-before":ye(()=>[ue(l.$slots,"aside-outline-before",{},void 0,!0)]),"aside-outline-after":ye(()=>[ue(l.$slots,"aside-outline-after",{},void 0,!0)]),"aside-ads-before":ye(()=>[ue(l.$slots,"aside-ads-before",{},void 0,!0)]),"aside-ads-after":ye(()=>[ue(l.$slots,"aside-ads-after",{},void 0,!0)]),_:3}),ke(x_),ue(l.$slots,"layout-bottom",{},void 0,!0)],2)):(Y(),$e(u,{key:1}))}}}),vx=Ye(gx,[["__scopeId","data-v-5d98c3a5"]]),cf={Layout:vx,enhanceApp:({app:s})=>{s.component("Badge",lg)}},_x=Ue({__name:"HighlightTargetedHeading",setup(s){function e(){if(!window||!window.location||!window.location.hash)return;const n=decodeURIComponent(window.location.hash);if(!n)return;let i;try{i=document.querySelector(n)}catch(r){console.error(r);return}i&&(i.classList.contains("VPNolebaseHighlightTargetedHeading")||i.classList.add("VPNolebaseHighlightTargetedHeading"),i.classList.remove("VPNolebaseHighlightTargetedHeadingAnimated"),setTimeout(()=>{i&&i.classList.add("VPNolebaseHighlightTargetedHeadingAnimated")},10))}const t=zr();return Nn(e),wt(t,async()=>{await Jc(),e()}),jm("hashchange",e),(n,i)=>ue(n.$slots,"default")}});/** - * @license - * Copyright 2010-2024 Three.js Authors - * SPDX-License-Identifier: MIT - */const Gr="165",yx={LEFT:0,MIDDLE:1,RIGHT:2,ROTATE:0,DOLLY:1,PAN:2},xx={ROTATE:0,PAN:1,DOLLY_PAN:2,DOLLY_ROTATE:3},uf=0,nc=1,hf=2,Mx=3,bx=0,iu=1,su=2,kn=3,ri=0,nn=1,En=2,ii=0,es=1,va=2,ic=3,sc=4,df=5,wi=100,ff=101,pf=102,mf=103,gf=104,vf=200,_f=201,yf=202,xf=203,_a=204,ya=205,Mf=206,bf=207,Sf=208,wf=209,Af=210,Tf=211,Ef=212,Cf=213,Pf=214,Rf=0,If=1,Lf=2,_r=3,Nf=4,Df=5,Uf=6,Of=7,Wr=0,Ff=1,kf=2,Hn=0,Bf=1,zf=2,Vf=3,Ca=4,Hf=5,Gf=6,Wf=7,rc="attached",$f="detached",Pa=300,oi=301,Ei=302,yr=303,xr=304,Ws=306,Mr=1e3,Mn=1001,br=1002,Gt=1003,ru=1004,Sx=1004,Ds=1005,wx=1005,Ot=1006,hr=1007,Ax=1007,Bn=1008,Tx=1008,ai=1009,Xf=1010,qf=1011,Sr=1012,ou=1013,ss=1014,gn=1015,$r=1016,au=1017,lu=1018,rs=1020,Yf=35902,Zf=1021,Jf=1022,un=1023,Kf=1024,jf=1025,ts=1026,os=1027,cu=1028,uu=1029,Qf=1030,hu=1031,du=1033,ra=33776,oa=33777,aa=33778,la=33779,oc=35840,ac=35841,lc=35842,cc=35843,uc=36196,hc=37492,dc=37496,fc=37808,pc=37809,mc=37810,gc=37811,vc=37812,_c=37813,yc=37814,xc=37815,Mc=37816,bc=37817,Sc=37818,wc=37819,Ac=37820,Tc=37821,ca=36492,Ec=36494,Cc=36495,ep=36283,Pc=36284,Rc=36285,Ic=36286,tp=2200,np=2201,ip=2202,wr=2300,xa=2301,ua=2302,Ji=2400,Ki=2401,Ar=2402,Ra=2500,fu=2501,Ex=0,Cx=1,Px=2,sp=3200,rp=3201,Ri=0,op=1,ei="",ln="srgb",ci="srgb-linear",Ia="display-p3",Xr="display-p3-linear",Tr="linear",Mt="srgb",Er="rec709",Cr="p3",Rx=0,qi=7680,Ix=7681,Lx=7682,Nx=7683,Dx=34055,Ux=34056,Ox=5386,Fx=512,kx=513,Bx=514,zx=515,Vx=516,Hx=517,Gx=518,Lc=519,ap=512,lp=513,cp=514,pu=515,up=516,hp=517,dp=518,fp=519,Pr=35044,Wx=35048,$x=35040,Xx=35045,qx=35049,Yx=35041,Zx=35046,Jx=35050,Kx=35042,jx="100",Nc="300 es",zn=2e3,Rr=2001;class ui{addEventListener(e,t){this._listeners===void 0&&(this._listeners={});const n=this._listeners;n[e]===void 0&&(n[e]=[]),n[e].indexOf(t)===-1&&n[e].push(t)}hasEventListener(e,t){if(this._listeners===void 0)return!1;const n=this._listeners;return n[e]!==void 0&&n[e].indexOf(t)!==-1}removeEventListener(e,t){if(this._listeners===void 0)return;const i=this._listeners[e];if(i!==void 0){const r=i.indexOf(t);r!==-1&&i.splice(r,1)}}dispatchEvent(e){if(this._listeners===void 0)return;const n=this._listeners[e.type];if(n!==void 0){e.target=this;const i=n.slice(0);for(let r=0,o=i.length;r>8&255]+Xt[s>>16&255]+Xt[s>>24&255]+"-"+Xt[e&255]+Xt[e>>8&255]+"-"+Xt[e>>16&15|64]+Xt[e>>24&255]+"-"+Xt[t&63|128]+Xt[t>>8&255]+"-"+Xt[t>>16&255]+Xt[t>>24&255]+Xt[n&255]+Xt[n>>8&255]+Xt[n>>16&255]+Xt[n>>24&255]).toLowerCase()}function Ct(s,e,t){return Math.max(e,Math.min(t,s))}function mu(s,e){return(s%e+e)%e}function Qx(s,e,t,n,i){return n+(s-e)*(i-n)/(t-e)}function eM(s,e,t){return s!==e?(t-s)/(e-s):0}function dr(s,e,t){return(1-t)*s+t*e}function tM(s,e,t,n){return dr(s,e,1-Math.exp(-t*n))}function nM(s,e=1){return e-Math.abs(mu(s,e*2)-e)}function iM(s,e,t){return s<=e?0:s>=t?1:(s=(s-e)/(t-e),s*s*(3-2*s))}function sM(s,e,t){return s<=e?0:s>=t?1:(s=(s-e)/(t-e),s*s*s*(s*(s*6-15)+10))}function rM(s,e){return s+Math.floor(Math.random()*(e-s+1))}function oM(s,e){return s+Math.random()*(e-s)}function aM(s){return s*(.5-Math.random())}function lM(s){s!==void 0&&(nh=s);let e=nh+=1831565813;return e=Math.imul(e^e>>>15,e|1),e^=e+Math.imul(e^e>>>7,e|61),((e^e>>>14)>>>0)/4294967296}function cM(s){return s*ns}function uM(s){return s*Vs}function hM(s){return(s&s-1)===0&&s!==0}function dM(s){return Math.pow(2,Math.ceil(Math.log(s)/Math.LN2))}function fM(s){return Math.pow(2,Math.floor(Math.log(s)/Math.LN2))}function pM(s,e,t,n,i){const r=Math.cos,o=Math.sin,a=r(t/2),l=o(t/2),c=r((e+n)/2),u=o((e+n)/2),h=r((e-n)/2),d=o((e-n)/2),f=r((n-e)/2),g=o((n-e)/2);switch(i){case"XYX":s.set(a*u,l*h,l*d,a*c);break;case"YZY":s.set(l*d,a*u,l*h,a*c);break;case"ZXZ":s.set(l*h,l*d,a*u,a*c);break;case"XZX":s.set(a*u,l*g,l*f,a*c);break;case"YXY":s.set(l*f,a*u,l*g,a*c);break;case"ZYZ":s.set(l*g,l*f,a*u,a*c);break;default:console.warn("THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: "+i)}}function tn(s,e){switch(e.constructor){case Float32Array:return s;case Uint32Array:return s/4294967295;case Uint16Array:return s/65535;case Uint8Array:return s/255;case Int32Array:return Math.max(s/2147483647,-1);case Int16Array:return Math.max(s/32767,-1);case Int8Array:return Math.max(s/127,-1);default:throw new Error("Invalid component type.")}}function tt(s,e){switch(e.constructor){case Float32Array:return s;case Uint32Array:return Math.round(s*4294967295);case Uint16Array:return Math.round(s*65535);case Uint8Array:return Math.round(s*255);case Int32Array:return Math.round(s*2147483647);case Int16Array:return Math.round(s*32767);case Int8Array:return Math.round(s*127);default:throw new Error("Invalid component type.")}}const pp={DEG2RAD:ns,RAD2DEG:Vs,generateUUID:vn,clamp:Ct,euclideanModulo:mu,mapLinear:Qx,inverseLerp:eM,lerp:dr,damp:tM,pingpong:nM,smoothstep:iM,smootherstep:sM,randInt:rM,randFloat:oM,randFloatSpread:aM,seededRandom:lM,degToRad:cM,radToDeg:uM,isPowerOfTwo:hM,ceilPowerOfTwo:dM,floorPowerOfTwo:fM,setQuaternionFromProperEuler:pM,normalize:tt,denormalize:tn};class se{constructor(e=0,t=0){se.prototype.isVector2=!0,this.x=e,this.y=t}get width(){return this.x}set width(e){this.x=e}get height(){return this.y}set height(e){this.y=e}set(e,t){return this.x=e,this.y=t,this}setScalar(e){return this.x=e,this.y=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y)}copy(e){return this.x=e.x,this.y=e.y,this}add(e){return this.x+=e.x,this.y+=e.y,this}addScalar(e){return this.x+=e,this.y+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this}subScalar(e){return this.x-=e,this.y-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this}multiply(e){return this.x*=e.x,this.y*=e.y,this}multiplyScalar(e){return this.x*=e,this.y*=e,this}divide(e){return this.x/=e.x,this.y/=e.y,this}divideScalar(e){return this.multiplyScalar(1/e)}applyMatrix3(e){const t=this.x,n=this.y,i=e.elements;return this.x=i[0]*t+i[3]*n+i[6],this.y=i[1]*t+i[4]*n+i[7],this}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this}clamp(e,t){return this.x=Math.max(e.x,Math.min(t.x,this.x)),this.y=Math.max(e.y,Math.min(t.y,this.y)),this}clampScalar(e,t){return this.x=Math.max(e,Math.min(t,this.x)),this.y=Math.max(e,Math.min(t,this.y)),this}clampLength(e,t){const n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(e,Math.min(t,n)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this}negate(){return this.x=-this.x,this.y=-this.y,this}dot(e){return this.x*e.x+this.y*e.y}cross(e){return this.x*e.y-this.y*e.x}lengthSq(){return this.x*this.x+this.y*this.y}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)}normalize(){return this.divideScalar(this.length()||1)}angle(){return Math.atan2(-this.y,-this.x)+Math.PI}angleTo(e){const t=Math.sqrt(this.lengthSq()*e.lengthSq());if(t===0)return Math.PI/2;const n=this.dot(e)/t;return Math.acos(Ct(n,-1,1))}distanceTo(e){return Math.sqrt(this.distanceToSquared(e))}distanceToSquared(e){const t=this.x-e.x,n=this.y-e.y;return t*t+n*n}manhattanDistanceTo(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this}lerpVectors(e,t,n){return this.x=e.x+(t.x-e.x)*n,this.y=e.y+(t.y-e.y)*n,this}equals(e){return e.x===this.x&&e.y===this.y}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this}rotateAround(e,t){const n=Math.cos(t),i=Math.sin(t),r=this.x-e.x,o=this.y-e.y;return this.x=r*n-o*i+e.x,this.y=r*i+o*n+e.y,this}random(){return this.x=Math.random(),this.y=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y}}class Ze{constructor(e,t,n,i,r,o,a,l,c){Ze.prototype.isMatrix3=!0,this.elements=[1,0,0,0,1,0,0,0,1],e!==void 0&&this.set(e,t,n,i,r,o,a,l,c)}set(e,t,n,i,r,o,a,l,c){const u=this.elements;return u[0]=e,u[1]=i,u[2]=a,u[3]=t,u[4]=r,u[5]=l,u[6]=n,u[7]=o,u[8]=c,this}identity(){return this.set(1,0,0,0,1,0,0,0,1),this}copy(e){const t=this.elements,n=e.elements;return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],this}extractBasis(e,t,n){return e.setFromMatrix3Column(this,0),t.setFromMatrix3Column(this,1),n.setFromMatrix3Column(this,2),this}setFromMatrix4(e){const t=e.elements;return this.set(t[0],t[4],t[8],t[1],t[5],t[9],t[2],t[6],t[10]),this}multiply(e){return this.multiplyMatrices(this,e)}premultiply(e){return this.multiplyMatrices(e,this)}multiplyMatrices(e,t){const n=e.elements,i=t.elements,r=this.elements,o=n[0],a=n[3],l=n[6],c=n[1],u=n[4],h=n[7],d=n[2],f=n[5],g=n[8],v=i[0],p=i[3],m=i[6],y=i[1],_=i[4],x=i[7],A=i[2],b=i[5],E=i[8];return r[0]=o*v+a*y+l*A,r[3]=o*p+a*_+l*b,r[6]=o*m+a*x+l*E,r[1]=c*v+u*y+h*A,r[4]=c*p+u*_+h*b,r[7]=c*m+u*x+h*E,r[2]=d*v+f*y+g*A,r[5]=d*p+f*_+g*b,r[8]=d*m+f*x+g*E,this}multiplyScalar(e){const t=this.elements;return t[0]*=e,t[3]*=e,t[6]*=e,t[1]*=e,t[4]*=e,t[7]*=e,t[2]*=e,t[5]*=e,t[8]*=e,this}determinant(){const e=this.elements,t=e[0],n=e[1],i=e[2],r=e[3],o=e[4],a=e[5],l=e[6],c=e[7],u=e[8];return t*o*u-t*a*c-n*r*u+n*a*l+i*r*c-i*o*l}invert(){const e=this.elements,t=e[0],n=e[1],i=e[2],r=e[3],o=e[4],a=e[5],l=e[6],c=e[7],u=e[8],h=u*o-a*c,d=a*l-u*r,f=c*r-o*l,g=t*h+n*d+i*f;if(g===0)return this.set(0,0,0,0,0,0,0,0,0);const v=1/g;return e[0]=h*v,e[1]=(i*c-u*n)*v,e[2]=(a*n-i*o)*v,e[3]=d*v,e[4]=(u*t-i*l)*v,e[5]=(i*r-a*t)*v,e[6]=f*v,e[7]=(n*l-c*t)*v,e[8]=(o*t-n*r)*v,this}transpose(){let e;const t=this.elements;return e=t[1],t[1]=t[3],t[3]=e,e=t[2],t[2]=t[6],t[6]=e,e=t[5],t[5]=t[7],t[7]=e,this}getNormalMatrix(e){return this.setFromMatrix4(e).invert().transpose()}transposeIntoArray(e){const t=this.elements;return e[0]=t[0],e[1]=t[3],e[2]=t[6],e[3]=t[1],e[4]=t[4],e[5]=t[7],e[6]=t[2],e[7]=t[5],e[8]=t[8],this}setUvTransform(e,t,n,i,r,o,a){const l=Math.cos(r),c=Math.sin(r);return this.set(n*l,n*c,-n*(l*o+c*a)+o+e,-i*c,i*l,-i*(-c*o+l*a)+a+t,0,0,1),this}scale(e,t){return this.premultiply(ul.makeScale(e,t)),this}rotate(e){return this.premultiply(ul.makeRotation(-e)),this}translate(e,t){return this.premultiply(ul.makeTranslation(e,t)),this}makeTranslation(e,t){return e.isVector2?this.set(1,0,e.x,0,1,e.y,0,0,1):this.set(1,0,e,0,1,t,0,0,1),this}makeRotation(e){const t=Math.cos(e),n=Math.sin(e);return this.set(t,-n,0,n,t,0,0,0,1),this}makeScale(e,t){return this.set(e,0,0,0,t,0,0,0,1),this}equals(e){const t=this.elements,n=e.elements;for(let i=0;i<9;i++)if(t[i]!==n[i])return!1;return!0}fromArray(e,t=0){for(let n=0;n<9;n++)this.elements[n]=e[n+t];return this}toArray(e=[],t=0){const n=this.elements;return e[t]=n[0],e[t+1]=n[1],e[t+2]=n[2],e[t+3]=n[3],e[t+4]=n[4],e[t+5]=n[5],e[t+6]=n[6],e[t+7]=n[7],e[t+8]=n[8],e}clone(){return new this.constructor().fromArray(this.elements)}}const ul=new Ze;function mp(s){for(let e=s.length-1;e>=0;--e)if(s[e]>=65535)return!0;return!1}const mM={Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array};function Us(s,e){return new mM[s](e)}function Ir(s){return document.createElementNS("http://www.w3.org/1999/xhtml",s)}function gp(){const s=Ir("canvas");return s.style.display="block",s}const ih={};function gu(s){s in ih||(ih[s]=!0,console.warn(s))}function gM(s,e,t){return new Promise(function(n,i){function r(){switch(s.clientWaitSync(e,s.SYNC_FLUSH_COMMANDS_BIT,0)){case s.WAIT_FAILED:i();break;case s.TIMEOUT_EXPIRED:setTimeout(r,t);break;default:n()}}setTimeout(r,t)})}const sh=new Ze().set(.8224621,.177538,0,.0331941,.9668058,0,.0170827,.0723974,.9105199),rh=new Ze().set(1.2249401,-.2249404,0,-.0420569,1.0420571,0,-.0196376,-.0786361,1.0982735),oo={[ci]:{transfer:Tr,primaries:Er,toReference:s=>s,fromReference:s=>s},[ln]:{transfer:Mt,primaries:Er,toReference:s=>s.convertSRGBToLinear(),fromReference:s=>s.convertLinearToSRGB()},[Xr]:{transfer:Tr,primaries:Cr,toReference:s=>s.applyMatrix3(rh),fromReference:s=>s.applyMatrix3(sh)},[Ia]:{transfer:Mt,primaries:Cr,toReference:s=>s.convertSRGBToLinear().applyMatrix3(rh),fromReference:s=>s.applyMatrix3(sh).convertLinearToSRGB()}},vM=new Set([ci,Xr]),ht={enabled:!0,_workingColorSpace:ci,get workingColorSpace(){return this._workingColorSpace},set workingColorSpace(s){if(!vM.has(s))throw new Error(`Unsupported working color space, "${s}".`);this._workingColorSpace=s},convert:function(s,e,t){if(this.enabled===!1||e===t||!e||!t)return s;const n=oo[e].toReference,i=oo[t].fromReference;return i(n(s))},fromWorkingColorSpace:function(s,e){return this.convert(s,this._workingColorSpace,e)},toWorkingColorSpace:function(s,e){return this.convert(s,e,this._workingColorSpace)},getPrimaries:function(s){return oo[s].primaries},getTransfer:function(s){return s===ei?Tr:oo[s].transfer}};function zs(s){return s<.04045?s*.0773993808:Math.pow(s*.9478672986+.0521327014,2.4)}function hl(s){return s<.0031308?s*12.92:1.055*Math.pow(s,.41666)-.055}let ds;class vp{static getDataURL(e){if(/^data:/i.test(e.src)||typeof HTMLCanvasElement>"u")return e.src;let t;if(e instanceof HTMLCanvasElement)t=e;else{ds===void 0&&(ds=Ir("canvas")),ds.width=e.width,ds.height=e.height;const n=ds.getContext("2d");e instanceof ImageData?n.putImageData(e,0,0):n.drawImage(e,0,0,e.width,e.height),t=ds}return t.width>2048||t.height>2048?(console.warn("THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons",e),t.toDataURL("image/jpeg",.6)):t.toDataURL("image/png")}static sRGBToLinear(e){if(typeof HTMLImageElement<"u"&&e instanceof HTMLImageElement||typeof HTMLCanvasElement<"u"&&e instanceof HTMLCanvasElement||typeof ImageBitmap<"u"&&e instanceof ImageBitmap){const t=Ir("canvas");t.width=e.width,t.height=e.height;const n=t.getContext("2d");n.drawImage(e,0,0,e.width,e.height);const i=n.getImageData(0,0,e.width,e.height),r=i.data;for(let o=0;o0&&(n.userData=this.userData),t||(e.textures[this.uuid]=n),n}dispose(){this.dispatchEvent({type:"dispose"})}transformUv(e){if(this.mapping!==Pa)return e;if(e.applyMatrix3(this.matrix),e.x<0||e.x>1)switch(this.wrapS){case Mr:e.x=e.x-Math.floor(e.x);break;case Mn:e.x=e.x<0?0:1;break;case br:Math.abs(Math.floor(e.x)%2)===1?e.x=Math.ceil(e.x)-e.x:e.x=e.x-Math.floor(e.x);break}if(e.y<0||e.y>1)switch(this.wrapT){case Mr:e.y=e.y-Math.floor(e.y);break;case Mn:e.y=e.y<0?0:1;break;case br:Math.abs(Math.floor(e.y)%2)===1?e.y=Math.ceil(e.y)-e.y:e.y=e.y-Math.floor(e.y);break}return this.flipY&&(e.y=1-e.y),e}set needsUpdate(e){e===!0&&(this.version++,this.source.needsUpdate=!0)}set needsPMREMUpdate(e){e===!0&&this.pmremVersion++}}Pt.DEFAULT_IMAGE=null;Pt.DEFAULT_MAPPING=Pa;Pt.DEFAULT_ANISOTROPY=1;class gt{constructor(e=0,t=0,n=0,i=1){gt.prototype.isVector4=!0,this.x=e,this.y=t,this.z=n,this.w=i}get width(){return this.z}set width(e){this.z=e}get height(){return this.w}set height(e){this.w=e}set(e,t,n,i){return this.x=e,this.y=t,this.z=n,this.w=i,this}setScalar(e){return this.x=e,this.y=e,this.z=e,this.w=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setZ(e){return this.z=e,this}setW(e){return this.w=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;case 3:this.w=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y,this.z,this.w)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this.w=e.w!==void 0?e.w:1,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this.w+=e.w,this}addScalar(e){return this.x+=e,this.y+=e,this.z+=e,this.w+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this.w=e.w+t.w,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this.w+=e.w*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this.w-=e.w,this}subScalar(e){return this.x-=e,this.y-=e,this.z-=e,this.w-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this.w=e.w-t.w,this}multiply(e){return this.x*=e.x,this.y*=e.y,this.z*=e.z,this.w*=e.w,this}multiplyScalar(e){return this.x*=e,this.y*=e,this.z*=e,this.w*=e,this}applyMatrix4(e){const t=this.x,n=this.y,i=this.z,r=this.w,o=e.elements;return this.x=o[0]*t+o[4]*n+o[8]*i+o[12]*r,this.y=o[1]*t+o[5]*n+o[9]*i+o[13]*r,this.z=o[2]*t+o[6]*n+o[10]*i+o[14]*r,this.w=o[3]*t+o[7]*n+o[11]*i+o[15]*r,this}divideScalar(e){return this.multiplyScalar(1/e)}setAxisAngleFromQuaternion(e){this.w=2*Math.acos(e.w);const t=Math.sqrt(1-e.w*e.w);return t<1e-4?(this.x=1,this.y=0,this.z=0):(this.x=e.x/t,this.y=e.y/t,this.z=e.z/t),this}setAxisAngleFromRotationMatrix(e){let t,n,i,r;const l=e.elements,c=l[0],u=l[4],h=l[8],d=l[1],f=l[5],g=l[9],v=l[2],p=l[6],m=l[10];if(Math.abs(u-d)<.01&&Math.abs(h-v)<.01&&Math.abs(g-p)<.01){if(Math.abs(u+d)<.1&&Math.abs(h+v)<.1&&Math.abs(g+p)<.1&&Math.abs(c+f+m-3)<.1)return this.set(1,0,0,0),this;t=Math.PI;const _=(c+1)/2,x=(f+1)/2,A=(m+1)/2,b=(u+d)/4,E=(h+v)/4,I=(g+p)/4;return _>x&&_>A?_<.01?(n=0,i=.707106781,r=.707106781):(n=Math.sqrt(_),i=b/n,r=E/n):x>A?x<.01?(n=.707106781,i=0,r=.707106781):(i=Math.sqrt(x),n=b/i,r=I/i):A<.01?(n=.707106781,i=.707106781,r=0):(r=Math.sqrt(A),n=E/r,i=I/r),this.set(n,i,r,t),this}let y=Math.sqrt((p-g)*(p-g)+(h-v)*(h-v)+(d-u)*(d-u));return Math.abs(y)<.001&&(y=1),this.x=(p-g)/y,this.y=(h-v)/y,this.z=(d-u)/y,this.w=Math.acos((c+f+m-1)/2),this}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this.z=Math.min(this.z,e.z),this.w=Math.min(this.w,e.w),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this.z=Math.max(this.z,e.z),this.w=Math.max(this.w,e.w),this}clamp(e,t){return this.x=Math.max(e.x,Math.min(t.x,this.x)),this.y=Math.max(e.y,Math.min(t.y,this.y)),this.z=Math.max(e.z,Math.min(t.z,this.z)),this.w=Math.max(e.w,Math.min(t.w,this.w)),this}clampScalar(e,t){return this.x=Math.max(e,Math.min(t,this.x)),this.y=Math.max(e,Math.min(t,this.y)),this.z=Math.max(e,Math.min(t,this.z)),this.w=Math.max(e,Math.min(t,this.w)),this}clampLength(e,t){const n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(e,Math.min(t,n)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this.w=Math.floor(this.w),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this.w=Math.ceil(this.w),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this.w=Math.round(this.w),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this.w=Math.trunc(this.w),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this.w=-this.w,this}dot(e){return this.x*e.x+this.y*e.y+this.z*e.z+this.w*e.w}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)}normalize(){return this.divideScalar(this.length()||1)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this.z+=(e.z-this.z)*t,this.w+=(e.w-this.w)*t,this}lerpVectors(e,t,n){return this.x=e.x+(t.x-e.x)*n,this.y=e.y+(t.y-e.y)*n,this.z=e.z+(t.z-e.z)*n,this.w=e.w+(t.w-e.w)*n,this}equals(e){return e.x===this.x&&e.y===this.y&&e.z===this.z&&e.w===this.w}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this.z=e[t+2],this.w=e[t+3],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e[t+2]=this.z,e[t+3]=this.w,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this.z=e.getZ(t),this.w=e.getW(t),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this.w=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z,yield this.w}}class _p extends ui{constructor(e=1,t=1,n={}){super(),this.isRenderTarget=!0,this.width=e,this.height=t,this.depth=1,this.scissor=new gt(0,0,e,t),this.scissorTest=!1,this.viewport=new gt(0,0,e,t);const i={width:e,height:t,depth:1};n=Object.assign({generateMipmaps:!1,internalFormat:null,minFilter:Ot,depthBuffer:!0,stencilBuffer:!1,resolveDepthBuffer:!0,resolveStencilBuffer:!0,depthTexture:null,samples:0,count:1},n);const r=new Pt(i,n.mapping,n.wrapS,n.wrapT,n.magFilter,n.minFilter,n.format,n.type,n.anisotropy,n.colorSpace);r.flipY=!1,r.generateMipmaps=n.generateMipmaps,r.internalFormat=n.internalFormat,this.textures=[];const o=n.count;for(let a=0;a=0?1:-1,_=1-m*m;if(_>Number.EPSILON){const A=Math.sqrt(_),b=Math.atan2(A,m*y);p=Math.sin(p*b)/A,a=Math.sin(a*b)/A}const x=a*y;if(l=l*p+d*x,c=c*p+f*x,u=u*p+g*x,h=h*p+v*x,p===1-a){const A=1/Math.sqrt(l*l+c*c+u*u+h*h);l*=A,c*=A,u*=A,h*=A}}e[t]=l,e[t+1]=c,e[t+2]=u,e[t+3]=h}static multiplyQuaternionsFlat(e,t,n,i,r,o){const a=n[i],l=n[i+1],c=n[i+2],u=n[i+3],h=r[o],d=r[o+1],f=r[o+2],g=r[o+3];return e[t]=a*g+u*h+l*f-c*d,e[t+1]=l*g+u*d+c*h-a*f,e[t+2]=c*g+u*f+a*d-l*h,e[t+3]=u*g-a*h-l*d-c*f,e}get x(){return this._x}set x(e){this._x=e,this._onChangeCallback()}get y(){return this._y}set y(e){this._y=e,this._onChangeCallback()}get z(){return this._z}set z(e){this._z=e,this._onChangeCallback()}get w(){return this._w}set w(e){this._w=e,this._onChangeCallback()}set(e,t,n,i){return this._x=e,this._y=t,this._z=n,this._w=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._w)}copy(e){return this._x=e.x,this._y=e.y,this._z=e.z,this._w=e.w,this._onChangeCallback(),this}setFromEuler(e,t=!0){const n=e._x,i=e._y,r=e._z,o=e._order,a=Math.cos,l=Math.sin,c=a(n/2),u=a(i/2),h=a(r/2),d=l(n/2),f=l(i/2),g=l(r/2);switch(o){case"XYZ":this._x=d*u*h+c*f*g,this._y=c*f*h-d*u*g,this._z=c*u*g+d*f*h,this._w=c*u*h-d*f*g;break;case"YXZ":this._x=d*u*h+c*f*g,this._y=c*f*h-d*u*g,this._z=c*u*g-d*f*h,this._w=c*u*h+d*f*g;break;case"ZXY":this._x=d*u*h-c*f*g,this._y=c*f*h+d*u*g,this._z=c*u*g+d*f*h,this._w=c*u*h-d*f*g;break;case"ZYX":this._x=d*u*h-c*f*g,this._y=c*f*h+d*u*g,this._z=c*u*g-d*f*h,this._w=c*u*h+d*f*g;break;case"YZX":this._x=d*u*h+c*f*g,this._y=c*f*h+d*u*g,this._z=c*u*g-d*f*h,this._w=c*u*h-d*f*g;break;case"XZY":this._x=d*u*h-c*f*g,this._y=c*f*h-d*u*g,this._z=c*u*g+d*f*h,this._w=c*u*h+d*f*g;break;default:console.warn("THREE.Quaternion: .setFromEuler() encountered an unknown order: "+o)}return t===!0&&this._onChangeCallback(),this}setFromAxisAngle(e,t){const n=t/2,i=Math.sin(n);return this._x=e.x*i,this._y=e.y*i,this._z=e.z*i,this._w=Math.cos(n),this._onChangeCallback(),this}setFromRotationMatrix(e){const t=e.elements,n=t[0],i=t[4],r=t[8],o=t[1],a=t[5],l=t[9],c=t[2],u=t[6],h=t[10],d=n+a+h;if(d>0){const f=.5/Math.sqrt(d+1);this._w=.25/f,this._x=(u-l)*f,this._y=(r-c)*f,this._z=(o-i)*f}else if(n>a&&n>h){const f=2*Math.sqrt(1+n-a-h);this._w=(u-l)/f,this._x=.25*f,this._y=(i+o)/f,this._z=(r+c)/f}else if(a>h){const f=2*Math.sqrt(1+a-n-h);this._w=(r-c)/f,this._x=(i+o)/f,this._y=.25*f,this._z=(l+u)/f}else{const f=2*Math.sqrt(1+h-n-a);this._w=(o-i)/f,this._x=(r+c)/f,this._y=(l+u)/f,this._z=.25*f}return this._onChangeCallback(),this}setFromUnitVectors(e,t){let n=e.dot(t)+1;return nMath.abs(e.z)?(this._x=-e.y,this._y=e.x,this._z=0,this._w=n):(this._x=0,this._y=-e.z,this._z=e.y,this._w=n)):(this._x=e.y*t.z-e.z*t.y,this._y=e.z*t.x-e.x*t.z,this._z=e.x*t.y-e.y*t.x,this._w=n),this.normalize()}angleTo(e){return 2*Math.acos(Math.abs(Ct(this.dot(e),-1,1)))}rotateTowards(e,t){const n=this.angleTo(e);if(n===0)return this;const i=Math.min(1,t/n);return this.slerp(e,i),this}identity(){return this.set(0,0,0,1)}invert(){return this.conjugate()}conjugate(){return this._x*=-1,this._y*=-1,this._z*=-1,this._onChangeCallback(),this}dot(e){return this._x*e._x+this._y*e._y+this._z*e._z+this._w*e._w}lengthSq(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w}length(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)}normalize(){let e=this.length();return e===0?(this._x=0,this._y=0,this._z=0,this._w=1):(e=1/e,this._x=this._x*e,this._y=this._y*e,this._z=this._z*e,this._w=this._w*e),this._onChangeCallback(),this}multiply(e){return this.multiplyQuaternions(this,e)}premultiply(e){return this.multiplyQuaternions(e,this)}multiplyQuaternions(e,t){const n=e._x,i=e._y,r=e._z,o=e._w,a=t._x,l=t._y,c=t._z,u=t._w;return this._x=n*u+o*a+i*c-r*l,this._y=i*u+o*l+r*a-n*c,this._z=r*u+o*c+n*l-i*a,this._w=o*u-n*a-i*l-r*c,this._onChangeCallback(),this}slerp(e,t){if(t===0)return this;if(t===1)return this.copy(e);const n=this._x,i=this._y,r=this._z,o=this._w;let a=o*e._w+n*e._x+i*e._y+r*e._z;if(a<0?(this._w=-e._w,this._x=-e._x,this._y=-e._y,this._z=-e._z,a=-a):this.copy(e),a>=1)return this._w=o,this._x=n,this._y=i,this._z=r,this;const l=1-a*a;if(l<=Number.EPSILON){const f=1-t;return this._w=f*o+t*this._w,this._x=f*n+t*this._x,this._y=f*i+t*this._y,this._z=f*r+t*this._z,this.normalize(),this}const c=Math.sqrt(l),u=Math.atan2(c,a),h=Math.sin((1-t)*u)/c,d=Math.sin(t*u)/c;return this._w=o*h+this._w*d,this._x=n*h+this._x*d,this._y=i*h+this._y*d,this._z=r*h+this._z*d,this._onChangeCallback(),this}slerpQuaternions(e,t,n){return this.copy(e).slerp(t,n)}random(){const e=2*Math.PI*Math.random(),t=2*Math.PI*Math.random(),n=Math.random(),i=Math.sqrt(1-n),r=Math.sqrt(n);return this.set(i*Math.sin(e),i*Math.cos(e),r*Math.sin(t),r*Math.cos(t))}equals(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._w===this._w}fromArray(e,t=0){return this._x=e[t],this._y=e[t+1],this._z=e[t+2],this._w=e[t+3],this._onChangeCallback(),this}toArray(e=[],t=0){return e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._w,e}fromBufferAttribute(e,t){return this._x=e.getX(t),this._y=e.getY(t),this._z=e.getZ(t),this._w=e.getW(t),this._onChangeCallback(),this}toJSON(){return this.toArray()}_onChange(e){return this._onChangeCallback=e,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._w}}class N{constructor(e=0,t=0,n=0){N.prototype.isVector3=!0,this.x=e,this.y=t,this.z=n}set(e,t,n){return n===void 0&&(n=this.z),this.x=e,this.y=t,this.z=n,this}setScalar(e){return this.x=e,this.y=e,this.z=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setZ(e){return this.z=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y,this.z)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this}addScalar(e){return this.x+=e,this.y+=e,this.z+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this}subScalar(e){return this.x-=e,this.y-=e,this.z-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this}multiply(e){return this.x*=e.x,this.y*=e.y,this.z*=e.z,this}multiplyScalar(e){return this.x*=e,this.y*=e,this.z*=e,this}multiplyVectors(e,t){return this.x=e.x*t.x,this.y=e.y*t.y,this.z=e.z*t.z,this}applyEuler(e){return this.applyQuaternion(oh.setFromEuler(e))}applyAxisAngle(e,t){return this.applyQuaternion(oh.setFromAxisAngle(e,t))}applyMatrix3(e){const t=this.x,n=this.y,i=this.z,r=e.elements;return this.x=r[0]*t+r[3]*n+r[6]*i,this.y=r[1]*t+r[4]*n+r[7]*i,this.z=r[2]*t+r[5]*n+r[8]*i,this}applyNormalMatrix(e){return this.applyMatrix3(e).normalize()}applyMatrix4(e){const t=this.x,n=this.y,i=this.z,r=e.elements,o=1/(r[3]*t+r[7]*n+r[11]*i+r[15]);return this.x=(r[0]*t+r[4]*n+r[8]*i+r[12])*o,this.y=(r[1]*t+r[5]*n+r[9]*i+r[13])*o,this.z=(r[2]*t+r[6]*n+r[10]*i+r[14])*o,this}applyQuaternion(e){const t=this.x,n=this.y,i=this.z,r=e.x,o=e.y,a=e.z,l=e.w,c=2*(o*i-a*n),u=2*(a*t-r*i),h=2*(r*n-o*t);return this.x=t+l*c+o*h-a*u,this.y=n+l*u+a*c-r*h,this.z=i+l*h+r*u-o*c,this}project(e){return this.applyMatrix4(e.matrixWorldInverse).applyMatrix4(e.projectionMatrix)}unproject(e){return this.applyMatrix4(e.projectionMatrixInverse).applyMatrix4(e.matrixWorld)}transformDirection(e){const t=this.x,n=this.y,i=this.z,r=e.elements;return this.x=r[0]*t+r[4]*n+r[8]*i,this.y=r[1]*t+r[5]*n+r[9]*i,this.z=r[2]*t+r[6]*n+r[10]*i,this.normalize()}divide(e){return this.x/=e.x,this.y/=e.y,this.z/=e.z,this}divideScalar(e){return this.multiplyScalar(1/e)}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this.z=Math.min(this.z,e.z),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this.z=Math.max(this.z,e.z),this}clamp(e,t){return this.x=Math.max(e.x,Math.min(t.x,this.x)),this.y=Math.max(e.y,Math.min(t.y,this.y)),this.z=Math.max(e.z,Math.min(t.z,this.z)),this}clampScalar(e,t){return this.x=Math.max(e,Math.min(t,this.x)),this.y=Math.max(e,Math.min(t,this.y)),this.z=Math.max(e,Math.min(t,this.z)),this}clampLength(e,t){const n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(e,Math.min(t,n)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this}dot(e){return this.x*e.x+this.y*e.y+this.z*e.z}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)}normalize(){return this.divideScalar(this.length()||1)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this.z+=(e.z-this.z)*t,this}lerpVectors(e,t,n){return this.x=e.x+(t.x-e.x)*n,this.y=e.y+(t.y-e.y)*n,this.z=e.z+(t.z-e.z)*n,this}cross(e){return this.crossVectors(this,e)}crossVectors(e,t){const n=e.x,i=e.y,r=e.z,o=t.x,a=t.y,l=t.z;return this.x=i*l-r*a,this.y=r*o-n*l,this.z=n*a-i*o,this}projectOnVector(e){const t=e.lengthSq();if(t===0)return this.set(0,0,0);const n=e.dot(this)/t;return this.copy(e).multiplyScalar(n)}projectOnPlane(e){return fl.copy(this).projectOnVector(e),this.sub(fl)}reflect(e){return this.sub(fl.copy(e).multiplyScalar(2*this.dot(e)))}angleTo(e){const t=Math.sqrt(this.lengthSq()*e.lengthSq());if(t===0)return Math.PI/2;const n=this.dot(e)/t;return Math.acos(Ct(n,-1,1))}distanceTo(e){return Math.sqrt(this.distanceToSquared(e))}distanceToSquared(e){const t=this.x-e.x,n=this.y-e.y,i=this.z-e.z;return t*t+n*n+i*i}manhattanDistanceTo(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)+Math.abs(this.z-e.z)}setFromSpherical(e){return this.setFromSphericalCoords(e.radius,e.phi,e.theta)}setFromSphericalCoords(e,t,n){const i=Math.sin(t)*e;return this.x=i*Math.sin(n),this.y=Math.cos(t)*e,this.z=i*Math.cos(n),this}setFromCylindrical(e){return this.setFromCylindricalCoords(e.radius,e.theta,e.y)}setFromCylindricalCoords(e,t,n){return this.x=e*Math.sin(t),this.y=n,this.z=e*Math.cos(t),this}setFromMatrixPosition(e){const t=e.elements;return this.x=t[12],this.y=t[13],this.z=t[14],this}setFromMatrixScale(e){const t=this.setFromMatrixColumn(e,0).length(),n=this.setFromMatrixColumn(e,1).length(),i=this.setFromMatrixColumn(e,2).length();return this.x=t,this.y=n,this.z=i,this}setFromMatrixColumn(e,t){return this.fromArray(e.elements,t*4)}setFromMatrix3Column(e,t){return this.fromArray(e.elements,t*3)}setFromEuler(e){return this.x=e._x,this.y=e._y,this.z=e._z,this}setFromColor(e){return this.x=e.r,this.y=e.g,this.z=e.b,this}equals(e){return e.x===this.x&&e.y===this.y&&e.z===this.z}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this.z=e[t+2],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e[t+2]=this.z,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this.z=e.getZ(t),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this}randomDirection(){const e=Math.random()*Math.PI*2,t=Math.random()*2-1,n=Math.sqrt(1-t*t);return this.x=n*Math.cos(e),this.y=t,this.z=n*Math.sin(e),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z}}const fl=new N,oh=new hn;class sn{constructor(e=new N(1/0,1/0,1/0),t=new N(-1/0,-1/0,-1/0)){this.isBox3=!0,this.min=e,this.max=t}set(e,t){return this.min.copy(e),this.max.copy(t),this}setFromArray(e){this.makeEmpty();for(let t=0,n=e.length;tthis.max.x||e.ythis.max.y||e.zthis.max.z)}containsBox(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y&&this.min.z<=e.min.z&&e.max.z<=this.max.z}getParameter(e,t){return t.set((e.x-this.min.x)/(this.max.x-this.min.x),(e.y-this.min.y)/(this.max.y-this.min.y),(e.z-this.min.z)/(this.max.z-this.min.z))}intersectsBox(e){return!(e.max.xthis.max.x||e.max.ythis.max.y||e.max.zthis.max.z)}intersectsSphere(e){return this.clampPoint(e.center,bn),bn.distanceToSquared(e.center)<=e.radius*e.radius}intersectsPlane(e){let t,n;return e.normal.x>0?(t=e.normal.x*this.min.x,n=e.normal.x*this.max.x):(t=e.normal.x*this.max.x,n=e.normal.x*this.min.x),e.normal.y>0?(t+=e.normal.y*this.min.y,n+=e.normal.y*this.max.y):(t+=e.normal.y*this.max.y,n+=e.normal.y*this.min.y),e.normal.z>0?(t+=e.normal.z*this.min.z,n+=e.normal.z*this.max.z):(t+=e.normal.z*this.max.z,n+=e.normal.z*this.min.z),t<=-e.constant&&n>=-e.constant}intersectsTriangle(e){if(this.isEmpty())return!1;this.getCenter(Zs),lo.subVectors(this.max,Zs),fs.subVectors(e.a,Zs),ps.subVectors(e.b,Zs),ms.subVectors(e.c,Zs),pi.subVectors(ps,fs),mi.subVectors(ms,ps),Ui.subVectors(fs,ms);let t=[0,-pi.z,pi.y,0,-mi.z,mi.y,0,-Ui.z,Ui.y,pi.z,0,-pi.x,mi.z,0,-mi.x,Ui.z,0,-Ui.x,-pi.y,pi.x,0,-mi.y,mi.x,0,-Ui.y,Ui.x,0];return!pl(t,fs,ps,ms,lo)||(t=[1,0,0,0,1,0,0,0,1],!pl(t,fs,ps,ms,lo))?!1:(co.crossVectors(pi,mi),t=[co.x,co.y,co.z],pl(t,fs,ps,ms,lo))}clampPoint(e,t){return t.copy(e).clamp(this.min,this.max)}distanceToPoint(e){return this.clampPoint(e,bn).distanceTo(e)}getBoundingSphere(e){return this.isEmpty()?e.makeEmpty():(this.getCenter(e.center),e.radius=this.getSize(bn).length()*.5),e}intersect(e){return this.min.max(e.min),this.max.min(e.max),this.isEmpty()&&this.makeEmpty(),this}union(e){return this.min.min(e.min),this.max.max(e.max),this}applyMatrix4(e){return this.isEmpty()?this:(Yn[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(e),Yn[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(e),Yn[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(e),Yn[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(e),Yn[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(e),Yn[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(e),Yn[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(e),Yn[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(e),this.setFromPoints(Yn),this)}translate(e){return this.min.add(e),this.max.add(e),this}equals(e){return e.min.equals(this.min)&&e.max.equals(this.max)}}const Yn=[new N,new N,new N,new N,new N,new N,new N,new N],bn=new N,ao=new sn,fs=new N,ps=new N,ms=new N,pi=new N,mi=new N,Ui=new N,Zs=new N,lo=new N,co=new N,Oi=new N;function pl(s,e,t,n,i){for(let r=0,o=s.length-3;r<=o;r+=3){Oi.fromArray(s,r);const a=i.x*Math.abs(Oi.x)+i.y*Math.abs(Oi.y)+i.z*Math.abs(Oi.z),l=e.dot(Oi),c=t.dot(Oi),u=n.dot(Oi);if(Math.max(-Math.max(l,c,u),Math.min(l,c,u))>a)return!1}return!0}const bM=new sn,Js=new N,ml=new N;class Zt{constructor(e=new N,t=-1){this.isSphere=!0,this.center=e,this.radius=t}set(e,t){return this.center.copy(e),this.radius=t,this}setFromPoints(e,t){const n=this.center;t!==void 0?n.copy(t):bM.setFromPoints(e).getCenter(n);let i=0;for(let r=0,o=e.length;rthis.radius*this.radius&&(t.sub(this.center).normalize(),t.multiplyScalar(this.radius).add(this.center)),t}getBoundingBox(e){return this.isEmpty()?(e.makeEmpty(),e):(e.set(this.center,this.center),e.expandByScalar(this.radius),e)}applyMatrix4(e){return this.center.applyMatrix4(e),this.radius=this.radius*e.getMaxScaleOnAxis(),this}translate(e){return this.center.add(e),this}expandByPoint(e){if(this.isEmpty())return this.center.copy(e),this.radius=0,this;Js.subVectors(e,this.center);const t=Js.lengthSq();if(t>this.radius*this.radius){const n=Math.sqrt(t),i=(n-this.radius)*.5;this.center.addScaledVector(Js,i/n),this.radius+=i}return this}union(e){return e.isEmpty()?this:this.isEmpty()?(this.copy(e),this):(this.center.equals(e.center)===!0?this.radius=Math.max(this.radius,e.radius):(ml.subVectors(e.center,this.center).setLength(e.radius),this.expandByPoint(Js.copy(e.center).add(ml)),this.expandByPoint(Js.copy(e.center).sub(ml))),this)}equals(e){return e.center.equals(this.center)&&e.radius===this.radius}clone(){return new this.constructor().copy(this)}}const Zn=new N,gl=new N,uo=new N,gi=new N,vl=new N,ho=new N,_l=new N;class $s{constructor(e=new N,t=new N(0,0,-1)){this.origin=e,this.direction=t}set(e,t){return this.origin.copy(e),this.direction.copy(t),this}copy(e){return this.origin.copy(e.origin),this.direction.copy(e.direction),this}at(e,t){return t.copy(this.origin).addScaledVector(this.direction,e)}lookAt(e){return this.direction.copy(e).sub(this.origin).normalize(),this}recast(e){return this.origin.copy(this.at(e,Zn)),this}closestPointToPoint(e,t){t.subVectors(e,this.origin);const n=t.dot(this.direction);return n<0?t.copy(this.origin):t.copy(this.origin).addScaledVector(this.direction,n)}distanceToPoint(e){return Math.sqrt(this.distanceSqToPoint(e))}distanceSqToPoint(e){const t=Zn.subVectors(e,this.origin).dot(this.direction);return t<0?this.origin.distanceToSquared(e):(Zn.copy(this.origin).addScaledVector(this.direction,t),Zn.distanceToSquared(e))}distanceSqToSegment(e,t,n,i){gl.copy(e).add(t).multiplyScalar(.5),uo.copy(t).sub(e).normalize(),gi.copy(this.origin).sub(gl);const r=e.distanceTo(t)*.5,o=-this.direction.dot(uo),a=gi.dot(this.direction),l=-gi.dot(uo),c=gi.lengthSq(),u=Math.abs(1-o*o);let h,d,f,g;if(u>0)if(h=o*l-a,d=o*a-l,g=r*u,h>=0)if(d>=-g)if(d<=g){const v=1/u;h*=v,d*=v,f=h*(h+o*d+2*a)+d*(o*h+d+2*l)+c}else d=r,h=Math.max(0,-(o*d+a)),f=-h*h+d*(d+2*l)+c;else d=-r,h=Math.max(0,-(o*d+a)),f=-h*h+d*(d+2*l)+c;else d<=-g?(h=Math.max(0,-(-o*r+a)),d=h>0?-r:Math.min(Math.max(-r,-l),r),f=-h*h+d*(d+2*l)+c):d<=g?(h=0,d=Math.min(Math.max(-r,-l),r),f=d*(d+2*l)+c):(h=Math.max(0,-(o*r+a)),d=h>0?r:Math.min(Math.max(-r,-l),r),f=-h*h+d*(d+2*l)+c);else d=o>0?-r:r,h=Math.max(0,-(o*d+a)),f=-h*h+d*(d+2*l)+c;return n&&n.copy(this.origin).addScaledVector(this.direction,h),i&&i.copy(gl).addScaledVector(uo,d),f}intersectSphere(e,t){Zn.subVectors(e.center,this.origin);const n=Zn.dot(this.direction),i=Zn.dot(Zn)-n*n,r=e.radius*e.radius;if(i>r)return null;const o=Math.sqrt(r-i),a=n-o,l=n+o;return l<0?null:a<0?this.at(l,t):this.at(a,t)}intersectsSphere(e){return this.distanceSqToPoint(e.center)<=e.radius*e.radius}distanceToPlane(e){const t=e.normal.dot(this.direction);if(t===0)return e.distanceToPoint(this.origin)===0?0:null;const n=-(this.origin.dot(e.normal)+e.constant)/t;return n>=0?n:null}intersectPlane(e,t){const n=this.distanceToPlane(e);return n===null?null:this.at(n,t)}intersectsPlane(e){const t=e.distanceToPoint(this.origin);return t===0||e.normal.dot(this.direction)*t<0}intersectBox(e,t){let n,i,r,o,a,l;const c=1/this.direction.x,u=1/this.direction.y,h=1/this.direction.z,d=this.origin;return c>=0?(n=(e.min.x-d.x)*c,i=(e.max.x-d.x)*c):(n=(e.max.x-d.x)*c,i=(e.min.x-d.x)*c),u>=0?(r=(e.min.y-d.y)*u,o=(e.max.y-d.y)*u):(r=(e.max.y-d.y)*u,o=(e.min.y-d.y)*u),n>o||r>i||((r>n||isNaN(n))&&(n=r),(o=0?(a=(e.min.z-d.z)*h,l=(e.max.z-d.z)*h):(a=(e.max.z-d.z)*h,l=(e.min.z-d.z)*h),n>l||a>i)||((a>n||n!==n)&&(n=a),(l=0?n:i,t)}intersectsBox(e){return this.intersectBox(e,Zn)!==null}intersectTriangle(e,t,n,i,r){vl.subVectors(t,e),ho.subVectors(n,e),_l.crossVectors(vl,ho);let o=this.direction.dot(_l),a;if(o>0){if(i)return null;a=1}else if(o<0)a=-1,o=-o;else return null;gi.subVectors(this.origin,e);const l=a*this.direction.dot(ho.crossVectors(gi,ho));if(l<0)return null;const c=a*this.direction.dot(vl.cross(gi));if(c<0||l+c>o)return null;const u=-a*gi.dot(_l);return u<0?null:this.at(u/o,r)}applyMatrix4(e){return this.origin.applyMatrix4(e),this.direction.transformDirection(e),this}equals(e){return e.origin.equals(this.origin)&&e.direction.equals(this.direction)}clone(){return new this.constructor().copy(this)}}class qe{constructor(e,t,n,i,r,o,a,l,c,u,h,d,f,g,v,p){qe.prototype.isMatrix4=!0,this.elements=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],e!==void 0&&this.set(e,t,n,i,r,o,a,l,c,u,h,d,f,g,v,p)}set(e,t,n,i,r,o,a,l,c,u,h,d,f,g,v,p){const m=this.elements;return m[0]=e,m[4]=t,m[8]=n,m[12]=i,m[1]=r,m[5]=o,m[9]=a,m[13]=l,m[2]=c,m[6]=u,m[10]=h,m[14]=d,m[3]=f,m[7]=g,m[11]=v,m[15]=p,this}identity(){return this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1),this}clone(){return new qe().fromArray(this.elements)}copy(e){const t=this.elements,n=e.elements;return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],this}copyPosition(e){const t=this.elements,n=e.elements;return t[12]=n[12],t[13]=n[13],t[14]=n[14],this}setFromMatrix3(e){const t=e.elements;return this.set(t[0],t[3],t[6],0,t[1],t[4],t[7],0,t[2],t[5],t[8],0,0,0,0,1),this}extractBasis(e,t,n){return e.setFromMatrixColumn(this,0),t.setFromMatrixColumn(this,1),n.setFromMatrixColumn(this,2),this}makeBasis(e,t,n){return this.set(e.x,t.x,n.x,0,e.y,t.y,n.y,0,e.z,t.z,n.z,0,0,0,0,1),this}extractRotation(e){const t=this.elements,n=e.elements,i=1/gs.setFromMatrixColumn(e,0).length(),r=1/gs.setFromMatrixColumn(e,1).length(),o=1/gs.setFromMatrixColumn(e,2).length();return t[0]=n[0]*i,t[1]=n[1]*i,t[2]=n[2]*i,t[3]=0,t[4]=n[4]*r,t[5]=n[5]*r,t[6]=n[6]*r,t[7]=0,t[8]=n[8]*o,t[9]=n[9]*o,t[10]=n[10]*o,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this}makeRotationFromEuler(e){const t=this.elements,n=e.x,i=e.y,r=e.z,o=Math.cos(n),a=Math.sin(n),l=Math.cos(i),c=Math.sin(i),u=Math.cos(r),h=Math.sin(r);if(e.order==="XYZ"){const d=o*u,f=o*h,g=a*u,v=a*h;t[0]=l*u,t[4]=-l*h,t[8]=c,t[1]=f+g*c,t[5]=d-v*c,t[9]=-a*l,t[2]=v-d*c,t[6]=g+f*c,t[10]=o*l}else if(e.order==="YXZ"){const d=l*u,f=l*h,g=c*u,v=c*h;t[0]=d+v*a,t[4]=g*a-f,t[8]=o*c,t[1]=o*h,t[5]=o*u,t[9]=-a,t[2]=f*a-g,t[6]=v+d*a,t[10]=o*l}else if(e.order==="ZXY"){const d=l*u,f=l*h,g=c*u,v=c*h;t[0]=d-v*a,t[4]=-o*h,t[8]=g+f*a,t[1]=f+g*a,t[5]=o*u,t[9]=v-d*a,t[2]=-o*c,t[6]=a,t[10]=o*l}else if(e.order==="ZYX"){const d=o*u,f=o*h,g=a*u,v=a*h;t[0]=l*u,t[4]=g*c-f,t[8]=d*c+v,t[1]=l*h,t[5]=v*c+d,t[9]=f*c-g,t[2]=-c,t[6]=a*l,t[10]=o*l}else if(e.order==="YZX"){const d=o*l,f=o*c,g=a*l,v=a*c;t[0]=l*u,t[4]=v-d*h,t[8]=g*h+f,t[1]=h,t[5]=o*u,t[9]=-a*u,t[2]=-c*u,t[6]=f*h+g,t[10]=d-v*h}else if(e.order==="XZY"){const d=o*l,f=o*c,g=a*l,v=a*c;t[0]=l*u,t[4]=-h,t[8]=c*u,t[1]=d*h+v,t[5]=o*u,t[9]=f*h-g,t[2]=g*h-f,t[6]=a*u,t[10]=v*h+d}return t[3]=0,t[7]=0,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this}makeRotationFromQuaternion(e){return this.compose(SM,e,wM)}lookAt(e,t,n){const i=this.elements;return fn.subVectors(e,t),fn.lengthSq()===0&&(fn.z=1),fn.normalize(),vi.crossVectors(n,fn),vi.lengthSq()===0&&(Math.abs(n.z)===1?fn.x+=1e-4:fn.z+=1e-4,fn.normalize(),vi.crossVectors(n,fn)),vi.normalize(),fo.crossVectors(fn,vi),i[0]=vi.x,i[4]=fo.x,i[8]=fn.x,i[1]=vi.y,i[5]=fo.y,i[9]=fn.y,i[2]=vi.z,i[6]=fo.z,i[10]=fn.z,this}multiply(e){return this.multiplyMatrices(this,e)}premultiply(e){return this.multiplyMatrices(e,this)}multiplyMatrices(e,t){const n=e.elements,i=t.elements,r=this.elements,o=n[0],a=n[4],l=n[8],c=n[12],u=n[1],h=n[5],d=n[9],f=n[13],g=n[2],v=n[6],p=n[10],m=n[14],y=n[3],_=n[7],x=n[11],A=n[15],b=i[0],E=i[4],I=i[8],w=i[12],M=i[1],F=i[5],V=i[9],G=i[13],q=i[2],ae=i[6],j=i[10],oe=i[14],B=i[3],Me=i[7],be=i[11],Ae=i[15];return r[0]=o*b+a*M+l*q+c*B,r[4]=o*E+a*F+l*ae+c*Me,r[8]=o*I+a*V+l*j+c*be,r[12]=o*w+a*G+l*oe+c*Ae,r[1]=u*b+h*M+d*q+f*B,r[5]=u*E+h*F+d*ae+f*Me,r[9]=u*I+h*V+d*j+f*be,r[13]=u*w+h*G+d*oe+f*Ae,r[2]=g*b+v*M+p*q+m*B,r[6]=g*E+v*F+p*ae+m*Me,r[10]=g*I+v*V+p*j+m*be,r[14]=g*w+v*G+p*oe+m*Ae,r[3]=y*b+_*M+x*q+A*B,r[7]=y*E+_*F+x*ae+A*Me,r[11]=y*I+_*V+x*j+A*be,r[15]=y*w+_*G+x*oe+A*Ae,this}multiplyScalar(e){const t=this.elements;return t[0]*=e,t[4]*=e,t[8]*=e,t[12]*=e,t[1]*=e,t[5]*=e,t[9]*=e,t[13]*=e,t[2]*=e,t[6]*=e,t[10]*=e,t[14]*=e,t[3]*=e,t[7]*=e,t[11]*=e,t[15]*=e,this}determinant(){const e=this.elements,t=e[0],n=e[4],i=e[8],r=e[12],o=e[1],a=e[5],l=e[9],c=e[13],u=e[2],h=e[6],d=e[10],f=e[14],g=e[3],v=e[7],p=e[11],m=e[15];return g*(+r*l*h-i*c*h-r*a*d+n*c*d+i*a*f-n*l*f)+v*(+t*l*f-t*c*d+r*o*d-i*o*f+i*c*u-r*l*u)+p*(+t*c*h-t*a*f-r*o*h+n*o*f+r*a*u-n*c*u)+m*(-i*a*u-t*l*h+t*a*d+i*o*h-n*o*d+n*l*u)}transpose(){const e=this.elements;let t;return t=e[1],e[1]=e[4],e[4]=t,t=e[2],e[2]=e[8],e[8]=t,t=e[6],e[6]=e[9],e[9]=t,t=e[3],e[3]=e[12],e[12]=t,t=e[7],e[7]=e[13],e[13]=t,t=e[11],e[11]=e[14],e[14]=t,this}setPosition(e,t,n){const i=this.elements;return e.isVector3?(i[12]=e.x,i[13]=e.y,i[14]=e.z):(i[12]=e,i[13]=t,i[14]=n),this}invert(){const e=this.elements,t=e[0],n=e[1],i=e[2],r=e[3],o=e[4],a=e[5],l=e[6],c=e[7],u=e[8],h=e[9],d=e[10],f=e[11],g=e[12],v=e[13],p=e[14],m=e[15],y=h*p*c-v*d*c+v*l*f-a*p*f-h*l*m+a*d*m,_=g*d*c-u*p*c-g*l*f+o*p*f+u*l*m-o*d*m,x=u*v*c-g*h*c+g*a*f-o*v*f-u*a*m+o*h*m,A=g*h*l-u*v*l-g*a*d+o*v*d+u*a*p-o*h*p,b=t*y+n*_+i*x+r*A;if(b===0)return this.set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);const E=1/b;return e[0]=y*E,e[1]=(v*d*r-h*p*r-v*i*f+n*p*f+h*i*m-n*d*m)*E,e[2]=(a*p*r-v*l*r+v*i*c-n*p*c-a*i*m+n*l*m)*E,e[3]=(h*l*r-a*d*r-h*i*c+n*d*c+a*i*f-n*l*f)*E,e[4]=_*E,e[5]=(u*p*r-g*d*r+g*i*f-t*p*f-u*i*m+t*d*m)*E,e[6]=(g*l*r-o*p*r-g*i*c+t*p*c+o*i*m-t*l*m)*E,e[7]=(o*d*r-u*l*r+u*i*c-t*d*c-o*i*f+t*l*f)*E,e[8]=x*E,e[9]=(g*h*r-u*v*r-g*n*f+t*v*f+u*n*m-t*h*m)*E,e[10]=(o*v*r-g*a*r+g*n*c-t*v*c-o*n*m+t*a*m)*E,e[11]=(u*a*r-o*h*r-u*n*c+t*h*c+o*n*f-t*a*f)*E,e[12]=A*E,e[13]=(u*v*i-g*h*i+g*n*d-t*v*d-u*n*p+t*h*p)*E,e[14]=(g*a*i-o*v*i-g*n*l+t*v*l+o*n*p-t*a*p)*E,e[15]=(o*h*i-u*a*i+u*n*l-t*h*l-o*n*d+t*a*d)*E,this}scale(e){const t=this.elements,n=e.x,i=e.y,r=e.z;return t[0]*=n,t[4]*=i,t[8]*=r,t[1]*=n,t[5]*=i,t[9]*=r,t[2]*=n,t[6]*=i,t[10]*=r,t[3]*=n,t[7]*=i,t[11]*=r,this}getMaxScaleOnAxis(){const e=this.elements,t=e[0]*e[0]+e[1]*e[1]+e[2]*e[2],n=e[4]*e[4]+e[5]*e[5]+e[6]*e[6],i=e[8]*e[8]+e[9]*e[9]+e[10]*e[10];return Math.sqrt(Math.max(t,n,i))}makeTranslation(e,t,n){return e.isVector3?this.set(1,0,0,e.x,0,1,0,e.y,0,0,1,e.z,0,0,0,1):this.set(1,0,0,e,0,1,0,t,0,0,1,n,0,0,0,1),this}makeRotationX(e){const t=Math.cos(e),n=Math.sin(e);return this.set(1,0,0,0,0,t,-n,0,0,n,t,0,0,0,0,1),this}makeRotationY(e){const t=Math.cos(e),n=Math.sin(e);return this.set(t,0,n,0,0,1,0,0,-n,0,t,0,0,0,0,1),this}makeRotationZ(e){const t=Math.cos(e),n=Math.sin(e);return this.set(t,-n,0,0,n,t,0,0,0,0,1,0,0,0,0,1),this}makeRotationAxis(e,t){const n=Math.cos(t),i=Math.sin(t),r=1-n,o=e.x,a=e.y,l=e.z,c=r*o,u=r*a;return this.set(c*o+n,c*a-i*l,c*l+i*a,0,c*a+i*l,u*a+n,u*l-i*o,0,c*l-i*a,u*l+i*o,r*l*l+n,0,0,0,0,1),this}makeScale(e,t,n){return this.set(e,0,0,0,0,t,0,0,0,0,n,0,0,0,0,1),this}makeShear(e,t,n,i,r,o){return this.set(1,n,r,0,e,1,o,0,t,i,1,0,0,0,0,1),this}compose(e,t,n){const i=this.elements,r=t._x,o=t._y,a=t._z,l=t._w,c=r+r,u=o+o,h=a+a,d=r*c,f=r*u,g=r*h,v=o*u,p=o*h,m=a*h,y=l*c,_=l*u,x=l*h,A=n.x,b=n.y,E=n.z;return i[0]=(1-(v+m))*A,i[1]=(f+x)*A,i[2]=(g-_)*A,i[3]=0,i[4]=(f-x)*b,i[5]=(1-(d+m))*b,i[6]=(p+y)*b,i[7]=0,i[8]=(g+_)*E,i[9]=(p-y)*E,i[10]=(1-(d+v))*E,i[11]=0,i[12]=e.x,i[13]=e.y,i[14]=e.z,i[15]=1,this}decompose(e,t,n){const i=this.elements;let r=gs.set(i[0],i[1],i[2]).length();const o=gs.set(i[4],i[5],i[6]).length(),a=gs.set(i[8],i[9],i[10]).length();this.determinant()<0&&(r=-r),e.x=i[12],e.y=i[13],e.z=i[14],Sn.copy(this);const c=1/r,u=1/o,h=1/a;return Sn.elements[0]*=c,Sn.elements[1]*=c,Sn.elements[2]*=c,Sn.elements[4]*=u,Sn.elements[5]*=u,Sn.elements[6]*=u,Sn.elements[8]*=h,Sn.elements[9]*=h,Sn.elements[10]*=h,t.setFromRotationMatrix(Sn),n.x=r,n.y=o,n.z=a,this}makePerspective(e,t,n,i,r,o,a=zn){const l=this.elements,c=2*r/(t-e),u=2*r/(n-i),h=(t+e)/(t-e),d=(n+i)/(n-i);let f,g;if(a===zn)f=-(o+r)/(o-r),g=-2*o*r/(o-r);else if(a===Rr)f=-o/(o-r),g=-o*r/(o-r);else throw new Error("THREE.Matrix4.makePerspective(): Invalid coordinate system: "+a);return l[0]=c,l[4]=0,l[8]=h,l[12]=0,l[1]=0,l[5]=u,l[9]=d,l[13]=0,l[2]=0,l[6]=0,l[10]=f,l[14]=g,l[3]=0,l[7]=0,l[11]=-1,l[15]=0,this}makeOrthographic(e,t,n,i,r,o,a=zn){const l=this.elements,c=1/(t-e),u=1/(n-i),h=1/(o-r),d=(t+e)*c,f=(n+i)*u;let g,v;if(a===zn)g=(o+r)*h,v=-2*h;else if(a===Rr)g=r*h,v=-1*h;else throw new Error("THREE.Matrix4.makeOrthographic(): Invalid coordinate system: "+a);return l[0]=2*c,l[4]=0,l[8]=0,l[12]=-d,l[1]=0,l[5]=2*u,l[9]=0,l[13]=-f,l[2]=0,l[6]=0,l[10]=v,l[14]=-g,l[3]=0,l[7]=0,l[11]=0,l[15]=1,this}equals(e){const t=this.elements,n=e.elements;for(let i=0;i<16;i++)if(t[i]!==n[i])return!1;return!0}fromArray(e,t=0){for(let n=0;n<16;n++)this.elements[n]=e[n+t];return this}toArray(e=[],t=0){const n=this.elements;return e[t]=n[0],e[t+1]=n[1],e[t+2]=n[2],e[t+3]=n[3],e[t+4]=n[4],e[t+5]=n[5],e[t+6]=n[6],e[t+7]=n[7],e[t+8]=n[8],e[t+9]=n[9],e[t+10]=n[10],e[t+11]=n[11],e[t+12]=n[12],e[t+13]=n[13],e[t+14]=n[14],e[t+15]=n[15],e}}const gs=new N,Sn=new qe,SM=new N(0,0,0),wM=new N(1,1,1),vi=new N,fo=new N,fn=new N,ah=new qe,lh=new hn;class _n{constructor(e=0,t=0,n=0,i=_n.DEFAULT_ORDER){this.isEuler=!0,this._x=e,this._y=t,this._z=n,this._order=i}get x(){return this._x}set x(e){this._x=e,this._onChangeCallback()}get y(){return this._y}set y(e){this._y=e,this._onChangeCallback()}get z(){return this._z}set z(e){this._z=e,this._onChangeCallback()}get order(){return this._order}set order(e){this._order=e,this._onChangeCallback()}set(e,t,n,i=this._order){return this._x=e,this._y=t,this._z=n,this._order=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._order)}copy(e){return this._x=e._x,this._y=e._y,this._z=e._z,this._order=e._order,this._onChangeCallback(),this}setFromRotationMatrix(e,t=this._order,n=!0){const i=e.elements,r=i[0],o=i[4],a=i[8],l=i[1],c=i[5],u=i[9],h=i[2],d=i[6],f=i[10];switch(t){case"XYZ":this._y=Math.asin(Ct(a,-1,1)),Math.abs(a)<.9999999?(this._x=Math.atan2(-u,f),this._z=Math.atan2(-o,r)):(this._x=Math.atan2(d,c),this._z=0);break;case"YXZ":this._x=Math.asin(-Ct(u,-1,1)),Math.abs(u)<.9999999?(this._y=Math.atan2(a,f),this._z=Math.atan2(l,c)):(this._y=Math.atan2(-h,r),this._z=0);break;case"ZXY":this._x=Math.asin(Ct(d,-1,1)),Math.abs(d)<.9999999?(this._y=Math.atan2(-h,f),this._z=Math.atan2(-o,c)):(this._y=0,this._z=Math.atan2(l,r));break;case"ZYX":this._y=Math.asin(-Ct(h,-1,1)),Math.abs(h)<.9999999?(this._x=Math.atan2(d,f),this._z=Math.atan2(l,r)):(this._x=0,this._z=Math.atan2(-o,c));break;case"YZX":this._z=Math.asin(Ct(l,-1,1)),Math.abs(l)<.9999999?(this._x=Math.atan2(-u,c),this._y=Math.atan2(-h,r)):(this._x=0,this._y=Math.atan2(a,f));break;case"XZY":this._z=Math.asin(-Ct(o,-1,1)),Math.abs(o)<.9999999?(this._x=Math.atan2(d,c),this._y=Math.atan2(a,r)):(this._x=Math.atan2(-u,f),this._y=0);break;default:console.warn("THREE.Euler: .setFromRotationMatrix() encountered an unknown order: "+t)}return this._order=t,n===!0&&this._onChangeCallback(),this}setFromQuaternion(e,t,n){return ah.makeRotationFromQuaternion(e),this.setFromRotationMatrix(ah,t,n)}setFromVector3(e,t=this._order){return this.set(e.x,e.y,e.z,t)}reorder(e){return lh.setFromEuler(this),this.setFromQuaternion(lh,e)}equals(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._order===this._order}fromArray(e){return this._x=e[0],this._y=e[1],this._z=e[2],e[3]!==void 0&&(this._order=e[3]),this._onChangeCallback(),this}toArray(e=[],t=0){return e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._order,e}_onChange(e){return this._onChangeCallback=e,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._order}}_n.DEFAULT_ORDER="XYZ";class Na{constructor(){this.mask=1}set(e){this.mask=(1<>>0}enable(e){this.mask|=1<1){for(let t=0;t1){for(let n=0;n0&&(i.userData=this.userData),i.layers=this.layers.mask,i.matrix=this.matrix.toArray(),i.up=this.up.toArray(),this.matrixAutoUpdate===!1&&(i.matrixAutoUpdate=!1),this.isInstancedMesh&&(i.type="InstancedMesh",i.count=this.count,i.instanceMatrix=this.instanceMatrix.toJSON(),this.instanceColor!==null&&(i.instanceColor=this.instanceColor.toJSON())),this.isBatchedMesh&&(i.type="BatchedMesh",i.perObjectFrustumCulled=this.perObjectFrustumCulled,i.sortObjects=this.sortObjects,i.drawRanges=this._drawRanges,i.reservedRanges=this._reservedRanges,i.visibility=this._visibility,i.active=this._active,i.bounds=this._bounds.map(a=>({boxInitialized:a.boxInitialized,boxMin:a.box.min.toArray(),boxMax:a.box.max.toArray(),sphereInitialized:a.sphereInitialized,sphereRadius:a.sphere.radius,sphereCenter:a.sphere.center.toArray()})),i.maxGeometryCount=this._maxGeometryCount,i.maxVertexCount=this._maxVertexCount,i.maxIndexCount=this._maxIndexCount,i.geometryInitialized=this._geometryInitialized,i.geometryCount=this._geometryCount,i.matricesTexture=this._matricesTexture.toJSON(e),this._colorsTexture!==null&&(i.colorsTexture=this._colorsTexture.toJSON(e)),this.boundingSphere!==null&&(i.boundingSphere={center:i.boundingSphere.center.toArray(),radius:i.boundingSphere.radius}),this.boundingBox!==null&&(i.boundingBox={min:i.boundingBox.min.toArray(),max:i.boundingBox.max.toArray()}));function r(a,l){return a[l.uuid]===void 0&&(a[l.uuid]=l.toJSON(e)),l.uuid}if(this.isScene)this.background&&(this.background.isColor?i.background=this.background.toJSON():this.background.isTexture&&(i.background=this.background.toJSON(e).uuid)),this.environment&&this.environment.isTexture&&this.environment.isRenderTargetTexture!==!0&&(i.environment=this.environment.toJSON(e).uuid);else if(this.isMesh||this.isLine||this.isPoints){i.geometry=r(e.geometries,this.geometry);const a=this.geometry.parameters;if(a!==void 0&&a.shapes!==void 0){const l=a.shapes;if(Array.isArray(l))for(let c=0,u=l.length;c0){i.children=[];for(let a=0;a0){i.animations=[];for(let a=0;a0&&(n.geometries=a),l.length>0&&(n.materials=l),c.length>0&&(n.textures=c),u.length>0&&(n.images=u),h.length>0&&(n.shapes=h),d.length>0&&(n.skeletons=d),f.length>0&&(n.animations=f),g.length>0&&(n.nodes=g)}return n.object=i,n;function o(a){const l=[];for(const c in a){const u=a[c];delete u.metadata,l.push(u)}return l}}clone(e){return new this.constructor().copy(this,e)}copy(e,t=!0){if(this.name=e.name,this.up.copy(e.up),this.position.copy(e.position),this.rotation.order=e.rotation.order,this.quaternion.copy(e.quaternion),this.scale.copy(e.scale),this.matrix.copy(e.matrix),this.matrixWorld.copy(e.matrixWorld),this.matrixAutoUpdate=e.matrixAutoUpdate,this.matrixWorldAutoUpdate=e.matrixWorldAutoUpdate,this.matrixWorldNeedsUpdate=e.matrixWorldNeedsUpdate,this.layers.mask=e.layers.mask,this.visible=e.visible,this.castShadow=e.castShadow,this.receiveShadow=e.receiveShadow,this.frustumCulled=e.frustumCulled,this.renderOrder=e.renderOrder,this.animations=e.animations.slice(),this.userData=JSON.parse(JSON.stringify(e.userData)),t===!0)for(let n=0;n0?i.multiplyScalar(1/Math.sqrt(r)):i.set(0,0,0)}static getBarycoord(e,t,n,i,r){wn.subVectors(i,t),Kn.subVectors(n,t),xl.subVectors(e,t);const o=wn.dot(wn),a=wn.dot(Kn),l=wn.dot(xl),c=Kn.dot(Kn),u=Kn.dot(xl),h=o*c-a*a;if(h===0)return r.set(0,0,0),null;const d=1/h,f=(c*l-a*u)*d,g=(o*u-a*l)*d;return r.set(1-f-g,g,f)}static containsPoint(e,t,n,i){return this.getBarycoord(e,t,n,i,jn)===null?!1:jn.x>=0&&jn.y>=0&&jn.x+jn.y<=1}static getInterpolation(e,t,n,i,r,o,a,l){return this.getBarycoord(e,t,n,i,jn)===null?(l.x=0,l.y=0,"z"in l&&(l.z=0),"w"in l&&(l.w=0),null):(l.setScalar(0),l.addScaledVector(r,jn.x),l.addScaledVector(o,jn.y),l.addScaledVector(a,jn.z),l)}static isFrontFacing(e,t,n,i){return wn.subVectors(n,t),Kn.subVectors(e,t),wn.cross(Kn).dot(i)<0}set(e,t,n){return this.a.copy(e),this.b.copy(t),this.c.copy(n),this}setFromPointsAndIndices(e,t,n,i){return this.a.copy(e[t]),this.b.copy(e[n]),this.c.copy(e[i]),this}setFromAttributeAndIndices(e,t,n,i){return this.a.fromBufferAttribute(e,t),this.b.fromBufferAttribute(e,n),this.c.fromBufferAttribute(e,i),this}clone(){return new this.constructor().copy(this)}copy(e){return this.a.copy(e.a),this.b.copy(e.b),this.c.copy(e.c),this}getArea(){return wn.subVectors(this.c,this.b),Kn.subVectors(this.a,this.b),wn.cross(Kn).length()*.5}getMidpoint(e){return e.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)}getNormal(e){return mn.getNormal(this.a,this.b,this.c,e)}getPlane(e){return e.setFromCoplanarPoints(this.a,this.b,this.c)}getBarycoord(e,t){return mn.getBarycoord(e,this.a,this.b,this.c,t)}getInterpolation(e,t,n,i,r){return mn.getInterpolation(e,this.a,this.b,this.c,t,n,i,r)}containsPoint(e){return mn.containsPoint(e,this.a,this.b,this.c)}isFrontFacing(e){return mn.isFrontFacing(this.a,this.b,this.c,e)}intersectsBox(e){return e.intersectsTriangle(this)}closestPointToPoint(e,t){const n=this.a,i=this.b,r=this.c;let o,a;ys.subVectors(i,n),xs.subVectors(r,n),Ml.subVectors(e,n);const l=ys.dot(Ml),c=xs.dot(Ml);if(l<=0&&c<=0)return t.copy(n);bl.subVectors(e,i);const u=ys.dot(bl),h=xs.dot(bl);if(u>=0&&h<=u)return t.copy(i);const d=l*h-u*c;if(d<=0&&l>=0&&u<=0)return o=l/(l-u),t.copy(n).addScaledVector(ys,o);Sl.subVectors(e,r);const f=ys.dot(Sl),g=xs.dot(Sl);if(g>=0&&f<=g)return t.copy(r);const v=f*c-l*g;if(v<=0&&c>=0&&g<=0)return a=c/(c-g),t.copy(n).addScaledVector(xs,a);const p=u*g-f*h;if(p<=0&&h-u>=0&&f-g>=0)return ph.subVectors(r,i),a=(h-u)/(h-u+(f-g)),t.copy(i).addScaledVector(ph,a);const m=1/(p+v+d);return o=v*m,a=d*m,t.copy(n).addScaledVector(ys,o).addScaledVector(xs,a)}equals(e){return e.a.equals(this.a)&&e.b.equals(this.b)&&e.c.equals(this.c)}}const yp={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074},_i={h:0,s:0,l:0},mo={h:0,s:0,l:0};function wl(s,e,t){return t<0&&(t+=1),t>1&&(t-=1),t<1/6?s+(e-s)*6*t:t<1/2?e:t<2/3?s+(e-s)*6*(2/3-t):s}class Pe{constructor(e,t,n){return this.isColor=!0,this.r=1,this.g=1,this.b=1,this.set(e,t,n)}set(e,t,n){if(t===void 0&&n===void 0){const i=e;i&&i.isColor?this.copy(i):typeof i=="number"?this.setHex(i):typeof i=="string"&&this.setStyle(i)}else this.setRGB(e,t,n);return this}setScalar(e){return this.r=e,this.g=e,this.b=e,this}setHex(e,t=ln){return e=Math.floor(e),this.r=(e>>16&255)/255,this.g=(e>>8&255)/255,this.b=(e&255)/255,ht.toWorkingColorSpace(this,t),this}setRGB(e,t,n,i=ht.workingColorSpace){return this.r=e,this.g=t,this.b=n,ht.toWorkingColorSpace(this,i),this}setHSL(e,t,n,i=ht.workingColorSpace){if(e=mu(e,1),t=Ct(t,0,1),n=Ct(n,0,1),t===0)this.r=this.g=this.b=n;else{const r=n<=.5?n*(1+t):n+t-n*t,o=2*n-r;this.r=wl(o,r,e+1/3),this.g=wl(o,r,e),this.b=wl(o,r,e-1/3)}return ht.toWorkingColorSpace(this,i),this}setStyle(e,t=ln){function n(r){r!==void 0&&parseFloat(r)<1&&console.warn("THREE.Color: Alpha component of "+e+" will be ignored.")}let i;if(i=/^(\w+)\(([^\)]*)\)/.exec(e)){let r;const o=i[1],a=i[2];switch(o){case"rgb":case"rgba":if(r=/^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(a))return n(r[4]),this.setRGB(Math.min(255,parseInt(r[1],10))/255,Math.min(255,parseInt(r[2],10))/255,Math.min(255,parseInt(r[3],10))/255,t);if(r=/^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(a))return n(r[4]),this.setRGB(Math.min(100,parseInt(r[1],10))/100,Math.min(100,parseInt(r[2],10))/100,Math.min(100,parseInt(r[3],10))/100,t);break;case"hsl":case"hsla":if(r=/^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(a))return n(r[4]),this.setHSL(parseFloat(r[1])/360,parseFloat(r[2])/100,parseFloat(r[3])/100,t);break;default:console.warn("THREE.Color: Unknown color model "+e)}}else if(i=/^\#([A-Fa-f\d]+)$/.exec(e)){const r=i[1],o=r.length;if(o===3)return this.setRGB(parseInt(r.charAt(0),16)/15,parseInt(r.charAt(1),16)/15,parseInt(r.charAt(2),16)/15,t);if(o===6)return this.setHex(parseInt(r,16),t);console.warn("THREE.Color: Invalid hex color "+e)}else if(e&&e.length>0)return this.setColorName(e,t);return this}setColorName(e,t=ln){const n=yp[e.toLowerCase()];return n!==void 0?this.setHex(n,t):console.warn("THREE.Color: Unknown color "+e),this}clone(){return new this.constructor(this.r,this.g,this.b)}copy(e){return this.r=e.r,this.g=e.g,this.b=e.b,this}copySRGBToLinear(e){return this.r=zs(e.r),this.g=zs(e.g),this.b=zs(e.b),this}copyLinearToSRGB(e){return this.r=hl(e.r),this.g=hl(e.g),this.b=hl(e.b),this}convertSRGBToLinear(){return this.copySRGBToLinear(this),this}convertLinearToSRGB(){return this.copyLinearToSRGB(this),this}getHex(e=ln){return ht.fromWorkingColorSpace(qt.copy(this),e),Math.round(Ct(qt.r*255,0,255))*65536+Math.round(Ct(qt.g*255,0,255))*256+Math.round(Ct(qt.b*255,0,255))}getHexString(e=ln){return("000000"+this.getHex(e).toString(16)).slice(-6)}getHSL(e,t=ht.workingColorSpace){ht.fromWorkingColorSpace(qt.copy(this),t);const n=qt.r,i=qt.g,r=qt.b,o=Math.max(n,i,r),a=Math.min(n,i,r);let l,c;const u=(a+o)/2;if(a===o)l=0,c=0;else{const h=o-a;switch(c=u<=.5?h/(o+a):h/(2-o-a),o){case n:l=(i-r)/h+(i0!=e>0&&this.version++,this._alphaTest=e}onBuild(){}onBeforeRender(){}onBeforeCompile(){}customProgramCacheKey(){return this.onBeforeCompile.toString()}setValues(e){if(e!==void 0)for(const t in e){const n=e[t];if(n===void 0){console.warn(`THREE.Material: parameter '${t}' has value of undefined.`);continue}const i=this[t];if(i===void 0){console.warn(`THREE.Material: '${t}' is not a property of THREE.${this.type}.`);continue}i&&i.isColor?i.set(n):i&&i.isVector3&&n&&n.isVector3?i.copy(n):this[t]=n}}toJSON(e){const t=e===void 0||typeof e=="string";t&&(e={textures:{},images:{}});const n={metadata:{version:4.6,type:"Material",generator:"Material.toJSON"}};n.uuid=this.uuid,n.type=this.type,this.name!==""&&(n.name=this.name),this.color&&this.color.isColor&&(n.color=this.color.getHex()),this.roughness!==void 0&&(n.roughness=this.roughness),this.metalness!==void 0&&(n.metalness=this.metalness),this.sheen!==void 0&&(n.sheen=this.sheen),this.sheenColor&&this.sheenColor.isColor&&(n.sheenColor=this.sheenColor.getHex()),this.sheenRoughness!==void 0&&(n.sheenRoughness=this.sheenRoughness),this.emissive&&this.emissive.isColor&&(n.emissive=this.emissive.getHex()),this.emissiveIntensity!==void 0&&this.emissiveIntensity!==1&&(n.emissiveIntensity=this.emissiveIntensity),this.specular&&this.specular.isColor&&(n.specular=this.specular.getHex()),this.specularIntensity!==void 0&&(n.specularIntensity=this.specularIntensity),this.specularColor&&this.specularColor.isColor&&(n.specularColor=this.specularColor.getHex()),this.shininess!==void 0&&(n.shininess=this.shininess),this.clearcoat!==void 0&&(n.clearcoat=this.clearcoat),this.clearcoatRoughness!==void 0&&(n.clearcoatRoughness=this.clearcoatRoughness),this.clearcoatMap&&this.clearcoatMap.isTexture&&(n.clearcoatMap=this.clearcoatMap.toJSON(e).uuid),this.clearcoatRoughnessMap&&this.clearcoatRoughnessMap.isTexture&&(n.clearcoatRoughnessMap=this.clearcoatRoughnessMap.toJSON(e).uuid),this.clearcoatNormalMap&&this.clearcoatNormalMap.isTexture&&(n.clearcoatNormalMap=this.clearcoatNormalMap.toJSON(e).uuid,n.clearcoatNormalScale=this.clearcoatNormalScale.toArray()),this.dispersion!==void 0&&(n.dispersion=this.dispersion),this.iridescence!==void 0&&(n.iridescence=this.iridescence),this.iridescenceIOR!==void 0&&(n.iridescenceIOR=this.iridescenceIOR),this.iridescenceThicknessRange!==void 0&&(n.iridescenceThicknessRange=this.iridescenceThicknessRange),this.iridescenceMap&&this.iridescenceMap.isTexture&&(n.iridescenceMap=this.iridescenceMap.toJSON(e).uuid),this.iridescenceThicknessMap&&this.iridescenceThicknessMap.isTexture&&(n.iridescenceThicknessMap=this.iridescenceThicknessMap.toJSON(e).uuid),this.anisotropy!==void 0&&(n.anisotropy=this.anisotropy),this.anisotropyRotation!==void 0&&(n.anisotropyRotation=this.anisotropyRotation),this.anisotropyMap&&this.anisotropyMap.isTexture&&(n.anisotropyMap=this.anisotropyMap.toJSON(e).uuid),this.map&&this.map.isTexture&&(n.map=this.map.toJSON(e).uuid),this.matcap&&this.matcap.isTexture&&(n.matcap=this.matcap.toJSON(e).uuid),this.alphaMap&&this.alphaMap.isTexture&&(n.alphaMap=this.alphaMap.toJSON(e).uuid),this.lightMap&&this.lightMap.isTexture&&(n.lightMap=this.lightMap.toJSON(e).uuid,n.lightMapIntensity=this.lightMapIntensity),this.aoMap&&this.aoMap.isTexture&&(n.aoMap=this.aoMap.toJSON(e).uuid,n.aoMapIntensity=this.aoMapIntensity),this.bumpMap&&this.bumpMap.isTexture&&(n.bumpMap=this.bumpMap.toJSON(e).uuid,n.bumpScale=this.bumpScale),this.normalMap&&this.normalMap.isTexture&&(n.normalMap=this.normalMap.toJSON(e).uuid,n.normalMapType=this.normalMapType,n.normalScale=this.normalScale.toArray()),this.displacementMap&&this.displacementMap.isTexture&&(n.displacementMap=this.displacementMap.toJSON(e).uuid,n.displacementScale=this.displacementScale,n.displacementBias=this.displacementBias),this.roughnessMap&&this.roughnessMap.isTexture&&(n.roughnessMap=this.roughnessMap.toJSON(e).uuid),this.metalnessMap&&this.metalnessMap.isTexture&&(n.metalnessMap=this.metalnessMap.toJSON(e).uuid),this.emissiveMap&&this.emissiveMap.isTexture&&(n.emissiveMap=this.emissiveMap.toJSON(e).uuid),this.specularMap&&this.specularMap.isTexture&&(n.specularMap=this.specularMap.toJSON(e).uuid),this.specularIntensityMap&&this.specularIntensityMap.isTexture&&(n.specularIntensityMap=this.specularIntensityMap.toJSON(e).uuid),this.specularColorMap&&this.specularColorMap.isTexture&&(n.specularColorMap=this.specularColorMap.toJSON(e).uuid),this.envMap&&this.envMap.isTexture&&(n.envMap=this.envMap.toJSON(e).uuid,this.combine!==void 0&&(n.combine=this.combine)),this.envMapRotation!==void 0&&(n.envMapRotation=this.envMapRotation.toArray()),this.envMapIntensity!==void 0&&(n.envMapIntensity=this.envMapIntensity),this.reflectivity!==void 0&&(n.reflectivity=this.reflectivity),this.refractionRatio!==void 0&&(n.refractionRatio=this.refractionRatio),this.gradientMap&&this.gradientMap.isTexture&&(n.gradientMap=this.gradientMap.toJSON(e).uuid),this.transmission!==void 0&&(n.transmission=this.transmission),this.transmissionMap&&this.transmissionMap.isTexture&&(n.transmissionMap=this.transmissionMap.toJSON(e).uuid),this.thickness!==void 0&&(n.thickness=this.thickness),this.thicknessMap&&this.thicknessMap.isTexture&&(n.thicknessMap=this.thicknessMap.toJSON(e).uuid),this.attenuationDistance!==void 0&&this.attenuationDistance!==1/0&&(n.attenuationDistance=this.attenuationDistance),this.attenuationColor!==void 0&&(n.attenuationColor=this.attenuationColor.getHex()),this.size!==void 0&&(n.size=this.size),this.shadowSide!==null&&(n.shadowSide=this.shadowSide),this.sizeAttenuation!==void 0&&(n.sizeAttenuation=this.sizeAttenuation),this.blending!==es&&(n.blending=this.blending),this.side!==ri&&(n.side=this.side),this.vertexColors===!0&&(n.vertexColors=!0),this.opacity<1&&(n.opacity=this.opacity),this.transparent===!0&&(n.transparent=!0),this.blendSrc!==_a&&(n.blendSrc=this.blendSrc),this.blendDst!==ya&&(n.blendDst=this.blendDst),this.blendEquation!==wi&&(n.blendEquation=this.blendEquation),this.blendSrcAlpha!==null&&(n.blendSrcAlpha=this.blendSrcAlpha),this.blendDstAlpha!==null&&(n.blendDstAlpha=this.blendDstAlpha),this.blendEquationAlpha!==null&&(n.blendEquationAlpha=this.blendEquationAlpha),this.blendColor&&this.blendColor.isColor&&(n.blendColor=this.blendColor.getHex()),this.blendAlpha!==0&&(n.blendAlpha=this.blendAlpha),this.depthFunc!==_r&&(n.depthFunc=this.depthFunc),this.depthTest===!1&&(n.depthTest=this.depthTest),this.depthWrite===!1&&(n.depthWrite=this.depthWrite),this.colorWrite===!1&&(n.colorWrite=this.colorWrite),this.stencilWriteMask!==255&&(n.stencilWriteMask=this.stencilWriteMask),this.stencilFunc!==Lc&&(n.stencilFunc=this.stencilFunc),this.stencilRef!==0&&(n.stencilRef=this.stencilRef),this.stencilFuncMask!==255&&(n.stencilFuncMask=this.stencilFuncMask),this.stencilFail!==qi&&(n.stencilFail=this.stencilFail),this.stencilZFail!==qi&&(n.stencilZFail=this.stencilZFail),this.stencilZPass!==qi&&(n.stencilZPass=this.stencilZPass),this.stencilWrite===!0&&(n.stencilWrite=this.stencilWrite),this.rotation!==void 0&&this.rotation!==0&&(n.rotation=this.rotation),this.polygonOffset===!0&&(n.polygonOffset=!0),this.polygonOffsetFactor!==0&&(n.polygonOffsetFactor=this.polygonOffsetFactor),this.polygonOffsetUnits!==0&&(n.polygonOffsetUnits=this.polygonOffsetUnits),this.linewidth!==void 0&&this.linewidth!==1&&(n.linewidth=this.linewidth),this.dashSize!==void 0&&(n.dashSize=this.dashSize),this.gapSize!==void 0&&(n.gapSize=this.gapSize),this.scale!==void 0&&(n.scale=this.scale),this.dithering===!0&&(n.dithering=!0),this.alphaTest>0&&(n.alphaTest=this.alphaTest),this.alphaHash===!0&&(n.alphaHash=!0),this.alphaToCoverage===!0&&(n.alphaToCoverage=!0),this.premultipliedAlpha===!0&&(n.premultipliedAlpha=!0),this.forceSinglePass===!0&&(n.forceSinglePass=!0),this.wireframe===!0&&(n.wireframe=!0),this.wireframeLinewidth>1&&(n.wireframeLinewidth=this.wireframeLinewidth),this.wireframeLinecap!=="round"&&(n.wireframeLinecap=this.wireframeLinecap),this.wireframeLinejoin!=="round"&&(n.wireframeLinejoin=this.wireframeLinejoin),this.flatShading===!0&&(n.flatShading=!0),this.visible===!1&&(n.visible=!1),this.toneMapped===!1&&(n.toneMapped=!1),this.fog===!1&&(n.fog=!1),Object.keys(this.userData).length>0&&(n.userData=this.userData);function i(r){const o=[];for(const a in r){const l=r[a];delete l.metadata,o.push(l)}return o}if(t){const r=i(e.textures),o=i(e.images);r.length>0&&(n.textures=r),o.length>0&&(n.images=o)}return n}clone(){return new this.constructor().copy(this)}copy(e){this.name=e.name,this.blending=e.blending,this.side=e.side,this.vertexColors=e.vertexColors,this.opacity=e.opacity,this.transparent=e.transparent,this.blendSrc=e.blendSrc,this.blendDst=e.blendDst,this.blendEquation=e.blendEquation,this.blendSrcAlpha=e.blendSrcAlpha,this.blendDstAlpha=e.blendDstAlpha,this.blendEquationAlpha=e.blendEquationAlpha,this.blendColor.copy(e.blendColor),this.blendAlpha=e.blendAlpha,this.depthFunc=e.depthFunc,this.depthTest=e.depthTest,this.depthWrite=e.depthWrite,this.stencilWriteMask=e.stencilWriteMask,this.stencilFunc=e.stencilFunc,this.stencilRef=e.stencilRef,this.stencilFuncMask=e.stencilFuncMask,this.stencilFail=e.stencilFail,this.stencilZFail=e.stencilZFail,this.stencilZPass=e.stencilZPass,this.stencilWrite=e.stencilWrite;const t=e.clippingPlanes;let n=null;if(t!==null){const i=t.length;n=new Array(i);for(let r=0;r!==i;++r)n[r]=t[r].clone()}return this.clippingPlanes=n,this.clipIntersection=e.clipIntersection,this.clipShadows=e.clipShadows,this.shadowSide=e.shadowSide,this.colorWrite=e.colorWrite,this.precision=e.precision,this.polygonOffset=e.polygonOffset,this.polygonOffsetFactor=e.polygonOffsetFactor,this.polygonOffsetUnits=e.polygonOffsetUnits,this.dithering=e.dithering,this.alphaTest=e.alphaTest,this.alphaHash=e.alphaHash,this.alphaToCoverage=e.alphaToCoverage,this.premultipliedAlpha=e.premultipliedAlpha,this.forceSinglePass=e.forceSinglePass,this.visible=e.visible,this.toneMapped=e.toneMapped,this.userData=JSON.parse(JSON.stringify(e.userData)),this}dispose(){this.dispatchEvent({type:"dispose"})}set needsUpdate(e){e===!0&&this.version++}}class hi extends Kt{constructor(e){super(),this.isMeshBasicMaterial=!0,this.type="MeshBasicMaterial",this.color=new Pe(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new _n,this.combine=Wr,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.envMapRotation.copy(e.envMapRotation),this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.fog=e.fog,this}}const ti=RM();function RM(){const s=new ArrayBuffer(4),e=new Float32Array(s),t=new Uint32Array(s),n=new Uint32Array(512),i=new Uint32Array(512);for(let l=0;l<256;++l){const c=l-127;c<-27?(n[l]=0,n[l|256]=32768,i[l]=24,i[l|256]=24):c<-14?(n[l]=1024>>-c-14,n[l|256]=1024>>-c-14|32768,i[l]=-c-1,i[l|256]=-c-1):c<=15?(n[l]=c+15<<10,n[l|256]=c+15<<10|32768,i[l]=13,i[l|256]=13):c<128?(n[l]=31744,n[l|256]=64512,i[l]=24,i[l|256]=24):(n[l]=31744,n[l|256]=64512,i[l]=13,i[l|256]=13)}const r=new Uint32Array(2048),o=new Uint32Array(64),a=new Uint32Array(64);for(let l=1;l<1024;++l){let c=l<<13,u=0;for(;!(c&8388608);)c<<=1,u-=8388608;c&=-8388609,u+=947912704,r[l]=c|u}for(let l=1024;l<2048;++l)r[l]=939524096+(l-1024<<13);for(let l=1;l<31;++l)o[l]=l<<23;o[31]=1199570944,o[32]=2147483648;for(let l=33;l<63;++l)o[l]=2147483648+(l-32<<23);o[63]=3347054592;for(let l=1;l<64;++l)l!==32&&(a[l]=1024);return{floatView:e,uint32View:t,baseTable:n,shiftTable:i,mantissaTable:r,exponentTable:o,offsetTable:a}}function an(s){Math.abs(s)>65504&&console.warn("THREE.DataUtils.toHalfFloat(): Value out of range."),s=Ct(s,-65504,65504),ti.floatView[0]=s;const e=ti.uint32View[0],t=e>>23&511;return ti.baseTable[t]+((e&8388607)>>ti.shiftTable[t])}function cr(s){const e=s>>10;return ti.uint32View[0]=ti.mantissaTable[ti.offsetTable[e]+(s&1023)]+ti.exponentTable[e],ti.floatView[0]}const IM={toHalfFloat:an,fromHalfFloat:cr},Dt=new N,go=new se;class pt{constructor(e,t,n=!1){if(Array.isArray(e))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.isBufferAttribute=!0,this.name="",this.array=e,this.itemSize=t,this.count=e!==void 0?e.length/t:0,this.normalized=n,this.usage=Pr,this._updateRange={offset:0,count:-1},this.updateRanges=[],this.gpuType=gn,this.version=0}onUploadCallback(){}set needsUpdate(e){e===!0&&this.version++}get updateRange(){return gu("THREE.BufferAttribute: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead."),this._updateRange}setUsage(e){return this.usage=e,this}addUpdateRange(e,t){this.updateRanges.push({start:e,count:t})}clearUpdateRanges(){this.updateRanges.length=0}copy(e){return this.name=e.name,this.array=new e.array.constructor(e.array),this.itemSize=e.itemSize,this.count=e.count,this.normalized=e.normalized,this.usage=e.usage,this.gpuType=e.gpuType,this}copyAt(e,t,n){e*=this.itemSize,n*=t.itemSize;for(let i=0,r=this.itemSize;i0&&(e.userData=this.userData),this.parameters!==void 0){const l=this.parameters;for(const c in l)l[c]!==void 0&&(e[c]=l[c]);return e}e.data={attributes:{}};const t=this.index;t!==null&&(e.data.index={type:t.array.constructor.name,array:Array.prototype.slice.call(t.array)});const n=this.attributes;for(const l in n){const c=n[l];e.data.attributes[l]=c.toJSON(e.data)}const i={};let r=!1;for(const l in this.morphAttributes){const c=this.morphAttributes[l],u=[];for(let h=0,d=c.length;h0&&(i[l]=u,r=!0)}r&&(e.data.morphAttributes=i,e.data.morphTargetsRelative=this.morphTargetsRelative);const o=this.groups;o.length>0&&(e.data.groups=JSON.parse(JSON.stringify(o)));const a=this.boundingSphere;return a!==null&&(e.data.boundingSphere={center:a.center.toArray(),radius:a.radius}),e}clone(){return new this.constructor().copy(this)}copy(e){this.index=null,this.attributes={},this.morphAttributes={},this.groups=[],this.boundingBox=null,this.boundingSphere=null;const t={};this.name=e.name;const n=e.index;n!==null&&this.setIndex(n.clone(t));const i=e.attributes;for(const c in i){const u=i[c];this.setAttribute(c,u.clone(t))}const r=e.morphAttributes;for(const c in r){const u=[],h=r[c];for(let d=0,f=h.length;d0){const i=t[n[0]];if(i!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let r=0,o=i.length;r(e.far-e.near)**2))&&(mh.copy(r).invert(),Fi.copy(e.ray).applyMatrix4(mh),!(n.boundingBox!==null&&Fi.intersectsBox(n.boundingBox)===!1)&&this._computeIntersections(e,t,Fi)))}_computeIntersections(e,t,n){let i;const r=this.geometry,o=this.material,a=r.index,l=r.attributes.position,c=r.attributes.uv,u=r.attributes.uv1,h=r.attributes.normal,d=r.groups,f=r.drawRange;if(a!==null)if(Array.isArray(o))for(let g=0,v=d.length;gt.far?null:{distance:c,point:So.clone(),object:s}}function wo(s,e,t,n,i,r,o,a,l,c){s.getVertexPosition(a,bs),s.getVertexPosition(l,Ss),s.getVertexPosition(c,ws);const u=BM(s,e,t,n,bs,Ss,ws,bo);if(u){i&&(yo.fromBufferAttribute(i,a),xo.fromBufferAttribute(i,l),Mo.fromBufferAttribute(i,c),u.uv=mn.getInterpolation(bo,bs,Ss,ws,yo,xo,Mo,new se)),r&&(yo.fromBufferAttribute(r,a),xo.fromBufferAttribute(r,l),Mo.fromBufferAttribute(r,c),u.uv1=mn.getInterpolation(bo,bs,Ss,ws,yo,xo,Mo,new se)),o&&(vh.fromBufferAttribute(o,a),_h.fromBufferAttribute(o,l),yh.fromBufferAttribute(o,c),u.normal=mn.getInterpolation(bo,bs,Ss,ws,vh,_h,yh,new N),u.normal.dot(n.direction)>0&&u.normal.multiplyScalar(-1));const h={a,b:l,c,normal:new N,materialIndex:0};mn.getNormal(bs,Ss,ws,h.normal),u.face=h}return u}class cs extends it{constructor(e=1,t=1,n=1,i=1,r=1,o=1){super(),this.type="BoxGeometry",this.parameters={width:e,height:t,depth:n,widthSegments:i,heightSegments:r,depthSegments:o};const a=this;i=Math.floor(i),r=Math.floor(r),o=Math.floor(o);const l=[],c=[],u=[],h=[];let d=0,f=0;g("z","y","x",-1,-1,n,t,e,o,r,0),g("z","y","x",1,-1,n,t,-e,o,r,1),g("x","z","y",1,1,e,n,t,i,o,2),g("x","z","y",1,-1,e,n,-t,i,o,3),g("x","y","z",1,-1,e,t,n,i,r,4),g("x","y","z",-1,-1,e,t,-n,i,r,5),this.setIndex(l),this.setAttribute("position",new Ne(c,3)),this.setAttribute("normal",new Ne(u,3)),this.setAttribute("uv",new Ne(h,2));function g(v,p,m,y,_,x,A,b,E,I,w){const M=x/E,F=A/I,V=x/2,G=A/2,q=b/2,ae=E+1,j=I+1;let oe=0,B=0;const Me=new N;for(let be=0;be0?1:-1,u.push(Me.x,Me.y,Me.z),h.push(ge/E),h.push(1-be/I),oe+=1}}for(let be=0;be0&&(t.defines=this.defines),t.vertexShader=this.vertexShader,t.fragmentShader=this.fragmentShader,t.lights=this.lights,t.clipping=this.clipping;const n={};for(const i in this.extensions)this.extensions[i]===!0&&(n[i]=!0);return Object.keys(n).length>0&&(t.extensions=n),t}}class qr extends ct{constructor(){super(),this.isCamera=!0,this.type="Camera",this.matrixWorldInverse=new qe,this.projectionMatrix=new qe,this.projectionMatrixInverse=new qe,this.coordinateSystem=zn}copy(e,t){return super.copy(e,t),this.matrixWorldInverse.copy(e.matrixWorldInverse),this.projectionMatrix.copy(e.projectionMatrix),this.projectionMatrixInverse.copy(e.projectionMatrixInverse),this.coordinateSystem=e.coordinateSystem,this}getWorldDirection(e){return super.getWorldDirection(e).negate()}updateMatrixWorld(e){super.updateMatrixWorld(e),this.matrixWorldInverse.copy(this.matrixWorld).invert()}updateWorldMatrix(e,t){super.updateWorldMatrix(e,t),this.matrixWorldInverse.copy(this.matrixWorld).invert()}clone(){return new this.constructor().copy(this)}}const yi=new N,xh=new se,Mh=new se;class Ut extends qr{constructor(e=50,t=1,n=.1,i=2e3){super(),this.isPerspectiveCamera=!0,this.type="PerspectiveCamera",this.fov=e,this.zoom=1,this.near=n,this.far=i,this.focus=10,this.aspect=t,this.view=null,this.filmGauge=35,this.filmOffset=0,this.updateProjectionMatrix()}copy(e,t){return super.copy(e,t),this.fov=e.fov,this.zoom=e.zoom,this.near=e.near,this.far=e.far,this.focus=e.focus,this.aspect=e.aspect,this.view=e.view===null?null:Object.assign({},e.view),this.filmGauge=e.filmGauge,this.filmOffset=e.filmOffset,this}setFocalLength(e){const t=.5*this.getFilmHeight()/e;this.fov=Vs*2*Math.atan(t),this.updateProjectionMatrix()}getFocalLength(){const e=Math.tan(ns*.5*this.fov);return .5*this.getFilmHeight()/e}getEffectiveFOV(){return Vs*2*Math.atan(Math.tan(ns*.5*this.fov)/this.zoom)}getFilmWidth(){return this.filmGauge*Math.min(this.aspect,1)}getFilmHeight(){return this.filmGauge/Math.max(this.aspect,1)}getViewBounds(e,t,n){yi.set(-1,-1,.5).applyMatrix4(this.projectionMatrixInverse),t.set(yi.x,yi.y).multiplyScalar(-e/yi.z),yi.set(1,1,.5).applyMatrix4(this.projectionMatrixInverse),n.set(yi.x,yi.y).multiplyScalar(-e/yi.z)}getViewSize(e,t){return this.getViewBounds(e,xh,Mh),t.subVectors(Mh,xh)}setViewOffset(e,t,n,i,r,o){this.aspect=e/t,this.view===null&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=e,this.view.fullHeight=t,this.view.offsetX=n,this.view.offsetY=i,this.view.width=r,this.view.height=o,this.updateProjectionMatrix()}clearViewOffset(){this.view!==null&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const e=this.near;let t=e*Math.tan(ns*.5*this.fov)/this.zoom,n=2*t,i=this.aspect*n,r=-.5*i;const o=this.view;if(this.view!==null&&this.view.enabled){const l=o.fullWidth,c=o.fullHeight;r+=o.offsetX*i/l,t-=o.offsetY*n/c,i*=o.width/l,n*=o.height/c}const a=this.filmOffset;a!==0&&(r+=e*a/this.getFilmWidth()),this.projectionMatrix.makePerspective(r,r+i,t,t-n,e,this.far,this.coordinateSystem),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(e){const t=super.toJSON(e);return t.object.fov=this.fov,t.object.zoom=this.zoom,t.object.near=this.near,t.object.far=this.far,t.object.focus=this.focus,t.object.aspect=this.aspect,this.view!==null&&(t.object.view=Object.assign({},this.view)),t.object.filmGauge=this.filmGauge,t.object.filmOffset=this.filmOffset,t}}const As=-90,Ts=1;class bp extends ct{constructor(e,t,n){super(),this.type="CubeCamera",this.renderTarget=n,this.coordinateSystem=null,this.activeMipmapLevel=0;const i=new Ut(As,Ts,e,t);i.layers=this.layers,this.add(i);const r=new Ut(As,Ts,e,t);r.layers=this.layers,this.add(r);const o=new Ut(As,Ts,e,t);o.layers=this.layers,this.add(o);const a=new Ut(As,Ts,e,t);a.layers=this.layers,this.add(a);const l=new Ut(As,Ts,e,t);l.layers=this.layers,this.add(l);const c=new Ut(As,Ts,e,t);c.layers=this.layers,this.add(c)}updateCoordinateSystem(){const e=this.coordinateSystem,t=this.children.concat(),[n,i,r,o,a,l]=t;for(const c of t)this.remove(c);if(e===zn)n.up.set(0,1,0),n.lookAt(1,0,0),i.up.set(0,1,0),i.lookAt(-1,0,0),r.up.set(0,0,-1),r.lookAt(0,1,0),o.up.set(0,0,1),o.lookAt(0,-1,0),a.up.set(0,1,0),a.lookAt(0,0,1),l.up.set(0,1,0),l.lookAt(0,0,-1);else if(e===Rr)n.up.set(0,-1,0),n.lookAt(-1,0,0),i.up.set(0,-1,0),i.lookAt(1,0,0),r.up.set(0,0,1),r.lookAt(0,1,0),o.up.set(0,0,-1),o.lookAt(0,-1,0),a.up.set(0,-1,0),a.lookAt(0,0,1),l.up.set(0,-1,0),l.lookAt(0,0,-1);else throw new Error("THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: "+e);for(const c of t)this.add(c),c.updateMatrixWorld()}update(e,t){this.parent===null&&this.updateMatrixWorld();const{renderTarget:n,activeMipmapLevel:i}=this;this.coordinateSystem!==e.coordinateSystem&&(this.coordinateSystem=e.coordinateSystem,this.updateCoordinateSystem());const[r,o,a,l,c,u]=this.children,h=e.getRenderTarget(),d=e.getActiveCubeFace(),f=e.getActiveMipmapLevel(),g=e.xr.enabled;e.xr.enabled=!1;const v=n.texture.generateMipmaps;n.texture.generateMipmaps=!1,e.setRenderTarget(n,0,i),e.render(t,r),e.setRenderTarget(n,1,i),e.render(t,o),e.setRenderTarget(n,2,i),e.render(t,a),e.setRenderTarget(n,3,i),e.render(t,l),e.setRenderTarget(n,4,i),e.render(t,c),n.texture.generateMipmaps=v,e.setRenderTarget(n,5,i),e.render(t,u),e.setRenderTarget(h,d,f),e.xr.enabled=g,n.texture.needsPMREMUpdate=!0}}class Yr extends Pt{constructor(e,t,n,i,r,o,a,l,c,u){e=e!==void 0?e:[],t=t!==void 0?t:oi,super(e,t,n,i,r,o,a,l,c,u),this.isCubeTexture=!0,this.flipY=!1}get images(){return this.image}set images(e){this.image=e}}class Sp extends In{constructor(e=1,t={}){super(e,e,t),this.isWebGLCubeRenderTarget=!0;const n={width:e,height:e,depth:1},i=[n,n,n,n,n,n];this.texture=new Yr(i,t.mapping,t.wrapS,t.wrapT,t.magFilter,t.minFilter,t.format,t.type,t.anisotropy,t.colorSpace),this.texture.isRenderTargetTexture=!0,this.texture.generateMipmaps=t.generateMipmaps!==void 0?t.generateMipmaps:!1,this.texture.minFilter=t.minFilter!==void 0?t.minFilter:Ot}fromEquirectangularTexture(e,t){this.texture.type=t.type,this.texture.colorSpace=t.colorSpace,this.texture.generateMipmaps=t.generateMipmaps,this.texture.minFilter=t.minFilter,this.texture.magFilter=t.magFilter;const n={uniforms:{tEquirect:{value:null}},vertexShader:` - - varying vec3 vWorldDirection; - - vec3 transformDirection( in vec3 dir, in mat4 matrix ) { - - return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); - - } - - void main() { - - vWorldDirection = transformDirection( position, modelMatrix ); - - #include - #include - - } - `,fragmentShader:` - - uniform sampler2D tEquirect; - - varying vec3 vWorldDirection; - - #include - - void main() { - - vec3 direction = normalize( vWorldDirection ); - - vec2 sampleUV = equirectUv( direction ); - - gl_FragColor = texture2D( tEquirect, sampleUV ); - - } - `},i=new cs(5,5,5),r=new Ln({name:"CubemapFromEquirect",uniforms:Hs(n.uniforms),vertexShader:n.vertexShader,fragmentShader:n.fragmentShader,side:nn,blending:ii});r.uniforms.tEquirect.value=t;const o=new Nt(i,r),a=t.minFilter;return t.minFilter===Bn&&(t.minFilter=Ot),new bp(1,10,this).update(e,o),t.minFilter=a,o.geometry.dispose(),o.material.dispose(),this}clear(e,t,n,i){const r=e.getRenderTarget();for(let o=0;o<6;o++)e.setRenderTarget(this,o),e.clear(t,n,i);e.setRenderTarget(r)}}const El=new N,GM=new N,WM=new Ze;class Si{constructor(e=new N(1,0,0),t=0){this.isPlane=!0,this.normal=e,this.constant=t}set(e,t){return this.normal.copy(e),this.constant=t,this}setComponents(e,t,n,i){return this.normal.set(e,t,n),this.constant=i,this}setFromNormalAndCoplanarPoint(e,t){return this.normal.copy(e),this.constant=-t.dot(this.normal),this}setFromCoplanarPoints(e,t,n){const i=El.subVectors(n,t).cross(GM.subVectors(e,t)).normalize();return this.setFromNormalAndCoplanarPoint(i,e),this}copy(e){return this.normal.copy(e.normal),this.constant=e.constant,this}normalize(){const e=1/this.normal.length();return this.normal.multiplyScalar(e),this.constant*=e,this}negate(){return this.constant*=-1,this.normal.negate(),this}distanceToPoint(e){return this.normal.dot(e)+this.constant}distanceToSphere(e){return this.distanceToPoint(e.center)-e.radius}projectPoint(e,t){return t.copy(e).addScaledVector(this.normal,-this.distanceToPoint(e))}intersectLine(e,t){const n=e.delta(El),i=this.normal.dot(n);if(i===0)return this.distanceToPoint(e.start)===0?t.copy(e.start):null;const r=-(e.start.dot(this.normal)+this.constant)/i;return r<0||r>1?null:t.copy(e.start).addScaledVector(n,r)}intersectsLine(e){const t=this.distanceToPoint(e.start),n=this.distanceToPoint(e.end);return t<0&&n>0||n<0&&t>0}intersectsBox(e){return e.intersectsPlane(this)}intersectsSphere(e){return e.intersectsPlane(this)}coplanarPoint(e){return e.copy(this.normal).multiplyScalar(-this.constant)}applyMatrix4(e,t){const n=t||WM.getNormalMatrix(e),i=this.coplanarPoint(El).applyMatrix4(e),r=this.normal.applyMatrix3(n).normalize();return this.constant=-i.dot(r),this}translate(e){return this.constant-=e.dot(this.normal),this}equals(e){return e.normal.equals(this.normal)&&e.constant===this.constant}clone(){return new this.constructor().copy(this)}}const ki=new Zt,Ao=new N;class Zr{constructor(e=new Si,t=new Si,n=new Si,i=new Si,r=new Si,o=new Si){this.planes=[e,t,n,i,r,o]}set(e,t,n,i,r,o){const a=this.planes;return a[0].copy(e),a[1].copy(t),a[2].copy(n),a[3].copy(i),a[4].copy(r),a[5].copy(o),this}copy(e){const t=this.planes;for(let n=0;n<6;n++)t[n].copy(e.planes[n]);return this}setFromProjectionMatrix(e,t=zn){const n=this.planes,i=e.elements,r=i[0],o=i[1],a=i[2],l=i[3],c=i[4],u=i[5],h=i[6],d=i[7],f=i[8],g=i[9],v=i[10],p=i[11],m=i[12],y=i[13],_=i[14],x=i[15];if(n[0].setComponents(l-r,d-c,p-f,x-m).normalize(),n[1].setComponents(l+r,d+c,p+f,x+m).normalize(),n[2].setComponents(l+o,d+u,p+g,x+y).normalize(),n[3].setComponents(l-o,d-u,p-g,x-y).normalize(),n[4].setComponents(l-a,d-h,p-v,x-_).normalize(),t===zn)n[5].setComponents(l+a,d+h,p+v,x+_).normalize();else if(t===Rr)n[5].setComponents(a,h,v,_).normalize();else throw new Error("THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: "+t);return this}intersectsObject(e){if(e.boundingSphere!==void 0)e.boundingSphere===null&&e.computeBoundingSphere(),ki.copy(e.boundingSphere).applyMatrix4(e.matrixWorld);else{const t=e.geometry;t.boundingSphere===null&&t.computeBoundingSphere(),ki.copy(t.boundingSphere).applyMatrix4(e.matrixWorld)}return this.intersectsSphere(ki)}intersectsSprite(e){return ki.center.set(0,0,0),ki.radius=.7071067811865476,ki.applyMatrix4(e.matrixWorld),this.intersectsSphere(ki)}intersectsSphere(e){const t=this.planes,n=e.center,i=-e.radius;for(let r=0;r<6;r++)if(t[r].distanceToPoint(n)0?e.max.x:e.min.x,Ao.y=i.normal.y>0?e.max.y:e.min.y,Ao.z=i.normal.z>0?e.max.z:e.min.z,i.distanceToPoint(Ao)<0)return!1}return!0}containsPoint(e){const t=this.planes;for(let n=0;n<6;n++)if(t[n].distanceToPoint(e)<0)return!1;return!0}clone(){return new this.constructor().copy(this)}}function wp(){let s=null,e=!1,t=null,n=null;function i(r,o){t(r,o),n=s.requestAnimationFrame(i)}return{start:function(){e!==!0&&t!==null&&(n=s.requestAnimationFrame(i),e=!0)},stop:function(){s.cancelAnimationFrame(n),e=!1},setAnimationLoop:function(r){t=r},setContext:function(r){s=r}}}function $M(s){const e=new WeakMap;function t(a,l){const c=a.array,u=a.usage,h=c.byteLength,d=s.createBuffer();s.bindBuffer(l,d),s.bufferData(l,c,u),a.onUploadCallback();let f;if(c instanceof Float32Array)f=s.FLOAT;else if(c instanceof Uint16Array)a.isFloat16BufferAttribute?f=s.HALF_FLOAT:f=s.UNSIGNED_SHORT;else if(c instanceof Int16Array)f=s.SHORT;else if(c instanceof Uint32Array)f=s.UNSIGNED_INT;else if(c instanceof Int32Array)f=s.INT;else if(c instanceof Int8Array)f=s.BYTE;else if(c instanceof Uint8Array)f=s.UNSIGNED_BYTE;else if(c instanceof Uint8ClampedArray)f=s.UNSIGNED_BYTE;else throw new Error("THREE.WebGLAttributes: Unsupported buffer data format: "+c);return{buffer:d,type:f,bytesPerElement:c.BYTES_PER_ELEMENT,version:a.version,size:h}}function n(a,l,c){const u=l.array,h=l._updateRange,d=l.updateRanges;if(s.bindBuffer(c,a),h.count===-1&&d.length===0&&s.bufferSubData(c,0,u),d.length!==0){for(let f=0,g=d.length;f 0 - vec4 plane; - #ifdef ALPHA_TO_COVERAGE - float distanceToPlane, distanceGradient; - float clipOpacity = 1.0; - #pragma unroll_loop_start - for ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) { - plane = clippingPlanes[ i ]; - distanceToPlane = - dot( vClipPosition, plane.xyz ) + plane.w; - distanceGradient = fwidth( distanceToPlane ) / 2.0; - clipOpacity *= smoothstep( - distanceGradient, distanceGradient, distanceToPlane ); - if ( clipOpacity == 0.0 ) discard; - } - #pragma unroll_loop_end - #if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES - float unionClipOpacity = 1.0; - #pragma unroll_loop_start - for ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) { - plane = clippingPlanes[ i ]; - distanceToPlane = - dot( vClipPosition, plane.xyz ) + plane.w; - distanceGradient = fwidth( distanceToPlane ) / 2.0; - unionClipOpacity *= 1.0 - smoothstep( - distanceGradient, distanceGradient, distanceToPlane ); - } - #pragma unroll_loop_end - clipOpacity *= 1.0 - unionClipOpacity; - #endif - diffuseColor.a *= clipOpacity; - if ( diffuseColor.a == 0.0 ) discard; - #else - #pragma unroll_loop_start - for ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) { - plane = clippingPlanes[ i ]; - if ( dot( vClipPosition, plane.xyz ) > plane.w ) discard; - } - #pragma unroll_loop_end - #if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES - bool clipped = true; - #pragma unroll_loop_start - for ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) { - plane = clippingPlanes[ i ]; - clipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped; - } - #pragma unroll_loop_end - if ( clipped ) discard; - #endif - #endif -#endif`,lb=`#if NUM_CLIPPING_PLANES > 0 - varying vec3 vClipPosition; - uniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ]; -#endif`,cb=`#if NUM_CLIPPING_PLANES > 0 - varying vec3 vClipPosition; -#endif`,ub=`#if NUM_CLIPPING_PLANES > 0 - vClipPosition = - mvPosition.xyz; -#endif`,hb=`#if defined( USE_COLOR_ALPHA ) - diffuseColor *= vColor; -#elif defined( USE_COLOR ) - diffuseColor.rgb *= vColor; -#endif`,db=`#if defined( USE_COLOR_ALPHA ) - varying vec4 vColor; -#elif defined( USE_COLOR ) - varying vec3 vColor; -#endif`,fb=`#if defined( USE_COLOR_ALPHA ) - varying vec4 vColor; -#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR ) - varying vec3 vColor; -#endif`,pb=`#if defined( USE_COLOR_ALPHA ) - vColor = vec4( 1.0 ); -#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR ) - vColor = vec3( 1.0 ); -#endif -#ifdef USE_COLOR - vColor *= color; -#endif -#ifdef USE_INSTANCING_COLOR - vColor.xyz *= instanceColor.xyz; -#endif -#ifdef USE_BATCHING_COLOR - vec3 batchingColor = getBatchingColor( batchId ); - vColor.xyz *= batchingColor.xyz; -#endif`,mb=`#define PI 3.141592653589793 -#define PI2 6.283185307179586 -#define PI_HALF 1.5707963267948966 -#define RECIPROCAL_PI 0.3183098861837907 -#define RECIPROCAL_PI2 0.15915494309189535 -#define EPSILON 1e-6 -#ifndef saturate -#define saturate( a ) clamp( a, 0.0, 1.0 ) -#endif -#define whiteComplement( a ) ( 1.0 - saturate( a ) ) -float pow2( const in float x ) { return x*x; } -vec3 pow2( const in vec3 x ) { return x*x; } -float pow3( const in float x ) { return x*x*x; } -float pow4( const in float x ) { float x2 = x*x; return x2*x2; } -float max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); } -float average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); } -highp float rand( const in vec2 uv ) { - const highp float a = 12.9898, b = 78.233, c = 43758.5453; - highp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI ); - return fract( sin( sn ) * c ); -} -#ifdef HIGH_PRECISION - float precisionSafeLength( vec3 v ) { return length( v ); } -#else - float precisionSafeLength( vec3 v ) { - float maxComponent = max3( abs( v ) ); - return length( v / maxComponent ) * maxComponent; - } -#endif -struct IncidentLight { - vec3 color; - vec3 direction; - bool visible; -}; -struct ReflectedLight { - vec3 directDiffuse; - vec3 directSpecular; - vec3 indirectDiffuse; - vec3 indirectSpecular; -}; -#ifdef USE_ALPHAHASH - varying vec3 vPosition; -#endif -vec3 transformDirection( in vec3 dir, in mat4 matrix ) { - return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); -} -vec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) { - return normalize( ( vec4( dir, 0.0 ) * matrix ).xyz ); -} -mat3 transposeMat3( const in mat3 m ) { - mat3 tmp; - tmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x ); - tmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y ); - tmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z ); - return tmp; -} -float luminance( const in vec3 rgb ) { - const vec3 weights = vec3( 0.2126729, 0.7151522, 0.0721750 ); - return dot( weights, rgb ); -} -bool isPerspectiveMatrix( mat4 m ) { - return m[ 2 ][ 3 ] == - 1.0; -} -vec2 equirectUv( in vec3 dir ) { - float u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5; - float v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5; - return vec2( u, v ); -} -vec3 BRDF_Lambert( const in vec3 diffuseColor ) { - return RECIPROCAL_PI * diffuseColor; -} -vec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) { - float fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH ); - return f0 * ( 1.0 - fresnel ) + ( f90 * fresnel ); -} -float F_Schlick( const in float f0, const in float f90, const in float dotVH ) { - float fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH ); - return f0 * ( 1.0 - fresnel ) + ( f90 * fresnel ); -} // validated`,gb=`#ifdef ENVMAP_TYPE_CUBE_UV - #define cubeUV_minMipLevel 4.0 - #define cubeUV_minTileSize 16.0 - float getFace( vec3 direction ) { - vec3 absDirection = abs( direction ); - float face = - 1.0; - if ( absDirection.x > absDirection.z ) { - if ( absDirection.x > absDirection.y ) - face = direction.x > 0.0 ? 0.0 : 3.0; - else - face = direction.y > 0.0 ? 1.0 : 4.0; - } else { - if ( absDirection.z > absDirection.y ) - face = direction.z > 0.0 ? 2.0 : 5.0; - else - face = direction.y > 0.0 ? 1.0 : 4.0; - } - return face; - } - vec2 getUV( vec3 direction, float face ) { - vec2 uv; - if ( face == 0.0 ) { - uv = vec2( direction.z, direction.y ) / abs( direction.x ); - } else if ( face == 1.0 ) { - uv = vec2( - direction.x, - direction.z ) / abs( direction.y ); - } else if ( face == 2.0 ) { - uv = vec2( - direction.x, direction.y ) / abs( direction.z ); - } else if ( face == 3.0 ) { - uv = vec2( - direction.z, direction.y ) / abs( direction.x ); - } else if ( face == 4.0 ) { - uv = vec2( - direction.x, direction.z ) / abs( direction.y ); - } else { - uv = vec2( direction.x, direction.y ) / abs( direction.z ); - } - return 0.5 * ( uv + 1.0 ); - } - vec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) { - float face = getFace( direction ); - float filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 ); - mipInt = max( mipInt, cubeUV_minMipLevel ); - float faceSize = exp2( mipInt ); - highp vec2 uv = getUV( direction, face ) * ( faceSize - 2.0 ) + 1.0; - if ( face > 2.0 ) { - uv.y += faceSize; - face -= 3.0; - } - uv.x += face * faceSize; - uv.x += filterInt * 3.0 * cubeUV_minTileSize; - uv.y += 4.0 * ( exp2( CUBEUV_MAX_MIP ) - faceSize ); - uv.x *= CUBEUV_TEXEL_WIDTH; - uv.y *= CUBEUV_TEXEL_HEIGHT; - #ifdef texture2DGradEXT - return texture2DGradEXT( envMap, uv, vec2( 0.0 ), vec2( 0.0 ) ).rgb; - #else - return texture2D( envMap, uv ).rgb; - #endif - } - #define cubeUV_r0 1.0 - #define cubeUV_m0 - 2.0 - #define cubeUV_r1 0.8 - #define cubeUV_m1 - 1.0 - #define cubeUV_r4 0.4 - #define cubeUV_m4 2.0 - #define cubeUV_r5 0.305 - #define cubeUV_m5 3.0 - #define cubeUV_r6 0.21 - #define cubeUV_m6 4.0 - float roughnessToMip( float roughness ) { - float mip = 0.0; - if ( roughness >= cubeUV_r1 ) { - mip = ( cubeUV_r0 - roughness ) * ( cubeUV_m1 - cubeUV_m0 ) / ( cubeUV_r0 - cubeUV_r1 ) + cubeUV_m0; - } else if ( roughness >= cubeUV_r4 ) { - mip = ( cubeUV_r1 - roughness ) * ( cubeUV_m4 - cubeUV_m1 ) / ( cubeUV_r1 - cubeUV_r4 ) + cubeUV_m1; - } else if ( roughness >= cubeUV_r5 ) { - mip = ( cubeUV_r4 - roughness ) * ( cubeUV_m5 - cubeUV_m4 ) / ( cubeUV_r4 - cubeUV_r5 ) + cubeUV_m4; - } else if ( roughness >= cubeUV_r6 ) { - mip = ( cubeUV_r5 - roughness ) * ( cubeUV_m6 - cubeUV_m5 ) / ( cubeUV_r5 - cubeUV_r6 ) + cubeUV_m5; - } else { - mip = - 2.0 * log2( 1.16 * roughness ); } - return mip; - } - vec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) { - float mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP ); - float mipF = fract( mip ); - float mipInt = floor( mip ); - vec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt ); - if ( mipF == 0.0 ) { - return vec4( color0, 1.0 ); - } else { - vec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 ); - return vec4( mix( color0, color1, mipF ), 1.0 ); - } - } -#endif`,vb=`vec3 transformedNormal = objectNormal; -#ifdef USE_TANGENT - vec3 transformedTangent = objectTangent; -#endif -#ifdef USE_BATCHING - mat3 bm = mat3( batchingMatrix ); - transformedNormal /= vec3( dot( bm[ 0 ], bm[ 0 ] ), dot( bm[ 1 ], bm[ 1 ] ), dot( bm[ 2 ], bm[ 2 ] ) ); - transformedNormal = bm * transformedNormal; - #ifdef USE_TANGENT - transformedTangent = bm * transformedTangent; - #endif -#endif -#ifdef USE_INSTANCING - mat3 im = mat3( instanceMatrix ); - transformedNormal /= vec3( dot( im[ 0 ], im[ 0 ] ), dot( im[ 1 ], im[ 1 ] ), dot( im[ 2 ], im[ 2 ] ) ); - transformedNormal = im * transformedNormal; - #ifdef USE_TANGENT - transformedTangent = im * transformedTangent; - #endif -#endif -transformedNormal = normalMatrix * transformedNormal; -#ifdef FLIP_SIDED - transformedNormal = - transformedNormal; -#endif -#ifdef USE_TANGENT - transformedTangent = ( modelViewMatrix * vec4( transformedTangent, 0.0 ) ).xyz; - #ifdef FLIP_SIDED - transformedTangent = - transformedTangent; - #endif -#endif`,_b=`#ifdef USE_DISPLACEMENTMAP - uniform sampler2D displacementMap; - uniform float displacementScale; - uniform float displacementBias; -#endif`,yb=`#ifdef USE_DISPLACEMENTMAP - transformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias ); -#endif`,xb=`#ifdef USE_EMISSIVEMAP - vec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv ); - totalEmissiveRadiance *= emissiveColor.rgb; -#endif`,Mb=`#ifdef USE_EMISSIVEMAP - uniform sampler2D emissiveMap; -#endif`,bb="gl_FragColor = linearToOutputTexel( gl_FragColor );",Sb=` -const mat3 LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = mat3( - vec3( 0.8224621, 0.177538, 0.0 ), - vec3( 0.0331941, 0.9668058, 0.0 ), - vec3( 0.0170827, 0.0723974, 0.9105199 ) -); -const mat3 LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = mat3( - vec3( 1.2249401, - 0.2249404, 0.0 ), - vec3( - 0.0420569, 1.0420571, 0.0 ), - vec3( - 0.0196376, - 0.0786361, 1.0982735 ) -); -vec4 LinearSRGBToLinearDisplayP3( in vec4 value ) { - return vec4( value.rgb * LINEAR_SRGB_TO_LINEAR_DISPLAY_P3, value.a ); -} -vec4 LinearDisplayP3ToLinearSRGB( in vec4 value ) { - return vec4( value.rgb * LINEAR_DISPLAY_P3_TO_LINEAR_SRGB, value.a ); -} -vec4 LinearTransferOETF( in vec4 value ) { - return value; -} -vec4 sRGBTransferOETF( in vec4 value ) { - return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a ); -} -vec4 LinearToLinear( in vec4 value ) { - return value; -} -vec4 LinearTosRGB( in vec4 value ) { - return sRGBTransferOETF( value ); -}`,wb=`#ifdef USE_ENVMAP - #ifdef ENV_WORLDPOS - vec3 cameraToFrag; - if ( isOrthographic ) { - cameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) ); - } else { - cameraToFrag = normalize( vWorldPosition - cameraPosition ); - } - vec3 worldNormal = inverseTransformDirection( normal, viewMatrix ); - #ifdef ENVMAP_MODE_REFLECTION - vec3 reflectVec = reflect( cameraToFrag, worldNormal ); - #else - vec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio ); - #endif - #else - vec3 reflectVec = vReflect; - #endif - #ifdef ENVMAP_TYPE_CUBE - vec4 envColor = textureCube( envMap, envMapRotation * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) ); - #else - vec4 envColor = vec4( 0.0 ); - #endif - #ifdef ENVMAP_BLENDING_MULTIPLY - outgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity ); - #elif defined( ENVMAP_BLENDING_MIX ) - outgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity ); - #elif defined( ENVMAP_BLENDING_ADD ) - outgoingLight += envColor.xyz * specularStrength * reflectivity; - #endif -#endif`,Ab=`#ifdef USE_ENVMAP - uniform float envMapIntensity; - uniform float flipEnvMap; - uniform mat3 envMapRotation; - #ifdef ENVMAP_TYPE_CUBE - uniform samplerCube envMap; - #else - uniform sampler2D envMap; - #endif - -#endif`,Tb=`#ifdef USE_ENVMAP - uniform float reflectivity; - #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT ) - #define ENV_WORLDPOS - #endif - #ifdef ENV_WORLDPOS - varying vec3 vWorldPosition; - uniform float refractionRatio; - #else - varying vec3 vReflect; - #endif -#endif`,Eb=`#ifdef USE_ENVMAP - #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT ) - #define ENV_WORLDPOS - #endif - #ifdef ENV_WORLDPOS - - varying vec3 vWorldPosition; - #else - varying vec3 vReflect; - uniform float refractionRatio; - #endif -#endif`,Cb=`#ifdef USE_ENVMAP - #ifdef ENV_WORLDPOS - vWorldPosition = worldPosition.xyz; - #else - vec3 cameraToVertex; - if ( isOrthographic ) { - cameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) ); - } else { - cameraToVertex = normalize( worldPosition.xyz - cameraPosition ); - } - vec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix ); - #ifdef ENVMAP_MODE_REFLECTION - vReflect = reflect( cameraToVertex, worldNormal ); - #else - vReflect = refract( cameraToVertex, worldNormal, refractionRatio ); - #endif - #endif -#endif`,Pb=`#ifdef USE_FOG - vFogDepth = - mvPosition.z; -#endif`,Rb=`#ifdef USE_FOG - varying float vFogDepth; -#endif`,Ib=`#ifdef USE_FOG - #ifdef FOG_EXP2 - float fogFactor = 1.0 - exp( - fogDensity * fogDensity * vFogDepth * vFogDepth ); - #else - float fogFactor = smoothstep( fogNear, fogFar, vFogDepth ); - #endif - gl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor ); -#endif`,Lb=`#ifdef USE_FOG - uniform vec3 fogColor; - varying float vFogDepth; - #ifdef FOG_EXP2 - uniform float fogDensity; - #else - uniform float fogNear; - uniform float fogFar; - #endif -#endif`,Nb=`#ifdef USE_GRADIENTMAP - uniform sampler2D gradientMap; -#endif -vec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) { - float dotNL = dot( normal, lightDirection ); - vec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 ); - #ifdef USE_GRADIENTMAP - return vec3( texture2D( gradientMap, coord ).r ); - #else - vec2 fw = fwidth( coord ) * 0.5; - return mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( 0.7 - fw.x, 0.7 + fw.x, coord.x ) ); - #endif -}`,Db=`#ifdef USE_LIGHTMAP - uniform sampler2D lightMap; - uniform float lightMapIntensity; -#endif`,Ub=`LambertMaterial material; -material.diffuseColor = diffuseColor.rgb; -material.specularStrength = specularStrength;`,Ob=`varying vec3 vViewPosition; -struct LambertMaterial { - vec3 diffuseColor; - float specularStrength; -}; -void RE_Direct_Lambert( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) { - float dotNL = saturate( dot( geometryNormal, directLight.direction ) ); - vec3 irradiance = dotNL * directLight.color; - reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); -} -void RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) { - reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); -} -#define RE_Direct RE_Direct_Lambert -#define RE_IndirectDiffuse RE_IndirectDiffuse_Lambert`,Fb=`uniform bool receiveShadow; -uniform vec3 ambientLightColor; -#if defined( USE_LIGHT_PROBES ) - uniform vec3 lightProbe[ 9 ]; -#endif -vec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) { - float x = normal.x, y = normal.y, z = normal.z; - vec3 result = shCoefficients[ 0 ] * 0.886227; - result += shCoefficients[ 1 ] * 2.0 * 0.511664 * y; - result += shCoefficients[ 2 ] * 2.0 * 0.511664 * z; - result += shCoefficients[ 3 ] * 2.0 * 0.511664 * x; - result += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y; - result += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z; - result += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 ); - result += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z; - result += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y ); - return result; -} -vec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) { - vec3 worldNormal = inverseTransformDirection( normal, viewMatrix ); - vec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe ); - return irradiance; -} -vec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) { - vec3 irradiance = ambientLightColor; - return irradiance; -} -float getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) { - float distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 ); - if ( cutoffDistance > 0.0 ) { - distanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) ); - } - return distanceFalloff; -} -float getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) { - return smoothstep( coneCosine, penumbraCosine, angleCosine ); -} -#if NUM_DIR_LIGHTS > 0 - struct DirectionalLight { - vec3 direction; - vec3 color; - }; - uniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ]; - void getDirectionalLightInfo( const in DirectionalLight directionalLight, out IncidentLight light ) { - light.color = directionalLight.color; - light.direction = directionalLight.direction; - light.visible = true; - } -#endif -#if NUM_POINT_LIGHTS > 0 - struct PointLight { - vec3 position; - vec3 color; - float distance; - float decay; - }; - uniform PointLight pointLights[ NUM_POINT_LIGHTS ]; - void getPointLightInfo( const in PointLight pointLight, const in vec3 geometryPosition, out IncidentLight light ) { - vec3 lVector = pointLight.position - geometryPosition; - light.direction = normalize( lVector ); - float lightDistance = length( lVector ); - light.color = pointLight.color; - light.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay ); - light.visible = ( light.color != vec3( 0.0 ) ); - } -#endif -#if NUM_SPOT_LIGHTS > 0 - struct SpotLight { - vec3 position; - vec3 direction; - vec3 color; - float distance; - float decay; - float coneCos; - float penumbraCos; - }; - uniform SpotLight spotLights[ NUM_SPOT_LIGHTS ]; - void getSpotLightInfo( const in SpotLight spotLight, const in vec3 geometryPosition, out IncidentLight light ) { - vec3 lVector = spotLight.position - geometryPosition; - light.direction = normalize( lVector ); - float angleCos = dot( light.direction, spotLight.direction ); - float spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos ); - if ( spotAttenuation > 0.0 ) { - float lightDistance = length( lVector ); - light.color = spotLight.color * spotAttenuation; - light.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay ); - light.visible = ( light.color != vec3( 0.0 ) ); - } else { - light.color = vec3( 0.0 ); - light.visible = false; - } - } -#endif -#if NUM_RECT_AREA_LIGHTS > 0 - struct RectAreaLight { - vec3 color; - vec3 position; - vec3 halfWidth; - vec3 halfHeight; - }; - uniform sampler2D ltc_1; uniform sampler2D ltc_2; - uniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ]; -#endif -#if NUM_HEMI_LIGHTS > 0 - struct HemisphereLight { - vec3 direction; - vec3 skyColor; - vec3 groundColor; - }; - uniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ]; - vec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) { - float dotNL = dot( normal, hemiLight.direction ); - float hemiDiffuseWeight = 0.5 * dotNL + 0.5; - vec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight ); - return irradiance; - } -#endif`,kb=`#ifdef USE_ENVMAP - vec3 getIBLIrradiance( const in vec3 normal ) { - #ifdef ENVMAP_TYPE_CUBE_UV - vec3 worldNormal = inverseTransformDirection( normal, viewMatrix ); - vec4 envMapColor = textureCubeUV( envMap, envMapRotation * worldNormal, 1.0 ); - return PI * envMapColor.rgb * envMapIntensity; - #else - return vec3( 0.0 ); - #endif - } - vec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) { - #ifdef ENVMAP_TYPE_CUBE_UV - vec3 reflectVec = reflect( - viewDir, normal ); - reflectVec = normalize( mix( reflectVec, normal, roughness * roughness) ); - reflectVec = inverseTransformDirection( reflectVec, viewMatrix ); - vec4 envMapColor = textureCubeUV( envMap, envMapRotation * reflectVec, roughness ); - return envMapColor.rgb * envMapIntensity; - #else - return vec3( 0.0 ); - #endif - } - #ifdef USE_ANISOTROPY - vec3 getIBLAnisotropyRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in vec3 bitangent, const in float anisotropy ) { - #ifdef ENVMAP_TYPE_CUBE_UV - vec3 bentNormal = cross( bitangent, viewDir ); - bentNormal = normalize( cross( bentNormal, bitangent ) ); - bentNormal = normalize( mix( bentNormal, normal, pow2( pow2( 1.0 - anisotropy * ( 1.0 - roughness ) ) ) ) ); - return getIBLRadiance( viewDir, bentNormal, roughness ); - #else - return vec3( 0.0 ); - #endif - } - #endif -#endif`,Bb=`ToonMaterial material; -material.diffuseColor = diffuseColor.rgb;`,zb=`varying vec3 vViewPosition; -struct ToonMaterial { - vec3 diffuseColor; -}; -void RE_Direct_Toon( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) { - vec3 irradiance = getGradientIrradiance( geometryNormal, directLight.direction ) * directLight.color; - reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); -} -void RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) { - reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); -} -#define RE_Direct RE_Direct_Toon -#define RE_IndirectDiffuse RE_IndirectDiffuse_Toon`,Vb=`BlinnPhongMaterial material; -material.diffuseColor = diffuseColor.rgb; -material.specularColor = specular; -material.specularShininess = shininess; -material.specularStrength = specularStrength;`,Hb=`varying vec3 vViewPosition; -struct BlinnPhongMaterial { - vec3 diffuseColor; - vec3 specularColor; - float specularShininess; - float specularStrength; -}; -void RE_Direct_BlinnPhong( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) { - float dotNL = saturate( dot( geometryNormal, directLight.direction ) ); - vec3 irradiance = dotNL * directLight.color; - reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); - reflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometryViewDir, geometryNormal, material.specularColor, material.specularShininess ) * material.specularStrength; -} -void RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) { - reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); -} -#define RE_Direct RE_Direct_BlinnPhong -#define RE_IndirectDiffuse RE_IndirectDiffuse_BlinnPhong`,Gb=`PhysicalMaterial material; -material.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor ); -vec3 dxy = max( abs( dFdx( nonPerturbedNormal ) ), abs( dFdy( nonPerturbedNormal ) ) ); -float geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z ); -material.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness; -material.roughness = min( material.roughness, 1.0 ); -#ifdef IOR - material.ior = ior; - #ifdef USE_SPECULAR - float specularIntensityFactor = specularIntensity; - vec3 specularColorFactor = specularColor; - #ifdef USE_SPECULAR_COLORMAP - specularColorFactor *= texture2D( specularColorMap, vSpecularColorMapUv ).rgb; - #endif - #ifdef USE_SPECULAR_INTENSITYMAP - specularIntensityFactor *= texture2D( specularIntensityMap, vSpecularIntensityMapUv ).a; - #endif - material.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor ); - #else - float specularIntensityFactor = 1.0; - vec3 specularColorFactor = vec3( 1.0 ); - material.specularF90 = 1.0; - #endif - material.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor ); -#else - material.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor ); - material.specularF90 = 1.0; -#endif -#ifdef USE_CLEARCOAT - material.clearcoat = clearcoat; - material.clearcoatRoughness = clearcoatRoughness; - material.clearcoatF0 = vec3( 0.04 ); - material.clearcoatF90 = 1.0; - #ifdef USE_CLEARCOATMAP - material.clearcoat *= texture2D( clearcoatMap, vClearcoatMapUv ).x; - #endif - #ifdef USE_CLEARCOAT_ROUGHNESSMAP - material.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vClearcoatRoughnessMapUv ).y; - #endif - material.clearcoat = saturate( material.clearcoat ); material.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 ); - material.clearcoatRoughness += geometryRoughness; - material.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 ); -#endif -#ifdef USE_DISPERSION - material.dispersion = dispersion; -#endif -#ifdef USE_IRIDESCENCE - material.iridescence = iridescence; - material.iridescenceIOR = iridescenceIOR; - #ifdef USE_IRIDESCENCEMAP - material.iridescence *= texture2D( iridescenceMap, vIridescenceMapUv ).r; - #endif - #ifdef USE_IRIDESCENCE_THICKNESSMAP - material.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vIridescenceThicknessMapUv ).g + iridescenceThicknessMinimum; - #else - material.iridescenceThickness = iridescenceThicknessMaximum; - #endif -#endif -#ifdef USE_SHEEN - material.sheenColor = sheenColor; - #ifdef USE_SHEEN_COLORMAP - material.sheenColor *= texture2D( sheenColorMap, vSheenColorMapUv ).rgb; - #endif - material.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 ); - #ifdef USE_SHEEN_ROUGHNESSMAP - material.sheenRoughness *= texture2D( sheenRoughnessMap, vSheenRoughnessMapUv ).a; - #endif -#endif -#ifdef USE_ANISOTROPY - #ifdef USE_ANISOTROPYMAP - mat2 anisotropyMat = mat2( anisotropyVector.x, anisotropyVector.y, - anisotropyVector.y, anisotropyVector.x ); - vec3 anisotropyPolar = texture2D( anisotropyMap, vAnisotropyMapUv ).rgb; - vec2 anisotropyV = anisotropyMat * normalize( 2.0 * anisotropyPolar.rg - vec2( 1.0 ) ) * anisotropyPolar.b; - #else - vec2 anisotropyV = anisotropyVector; - #endif - material.anisotropy = length( anisotropyV ); - if( material.anisotropy == 0.0 ) { - anisotropyV = vec2( 1.0, 0.0 ); - } else { - anisotropyV /= material.anisotropy; - material.anisotropy = saturate( material.anisotropy ); - } - material.alphaT = mix( pow2( material.roughness ), 1.0, pow2( material.anisotropy ) ); - material.anisotropyT = tbn[ 0 ] * anisotropyV.x + tbn[ 1 ] * anisotropyV.y; - material.anisotropyB = tbn[ 1 ] * anisotropyV.x - tbn[ 0 ] * anisotropyV.y; -#endif`,Wb=`struct PhysicalMaterial { - vec3 diffuseColor; - float roughness; - vec3 specularColor; - float specularF90; - float dispersion; - #ifdef USE_CLEARCOAT - float clearcoat; - float clearcoatRoughness; - vec3 clearcoatF0; - float clearcoatF90; - #endif - #ifdef USE_IRIDESCENCE - float iridescence; - float iridescenceIOR; - float iridescenceThickness; - vec3 iridescenceFresnel; - vec3 iridescenceF0; - #endif - #ifdef USE_SHEEN - vec3 sheenColor; - float sheenRoughness; - #endif - #ifdef IOR - float ior; - #endif - #ifdef USE_TRANSMISSION - float transmission; - float transmissionAlpha; - float thickness; - float attenuationDistance; - vec3 attenuationColor; - #endif - #ifdef USE_ANISOTROPY - float anisotropy; - float alphaT; - vec3 anisotropyT; - vec3 anisotropyB; - #endif -}; -vec3 clearcoatSpecularDirect = vec3( 0.0 ); -vec3 clearcoatSpecularIndirect = vec3( 0.0 ); -vec3 sheenSpecularDirect = vec3( 0.0 ); -vec3 sheenSpecularIndirect = vec3(0.0 ); -vec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) { - float x = clamp( 1.0 - dotVH, 0.0, 1.0 ); - float x2 = x * x; - float x5 = clamp( x * x2 * x2, 0.0, 0.9999 ); - return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 ); -} -float V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) { - float a2 = pow2( alpha ); - float gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) ); - float gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) ); - return 0.5 / max( gv + gl, EPSILON ); -} -float D_GGX( const in float alpha, const in float dotNH ) { - float a2 = pow2( alpha ); - float denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0; - return RECIPROCAL_PI * a2 / pow2( denom ); -} -#ifdef USE_ANISOTROPY - float V_GGX_SmithCorrelated_Anisotropic( const in float alphaT, const in float alphaB, const in float dotTV, const in float dotBV, const in float dotTL, const in float dotBL, const in float dotNV, const in float dotNL ) { - float gv = dotNL * length( vec3( alphaT * dotTV, alphaB * dotBV, dotNV ) ); - float gl = dotNV * length( vec3( alphaT * dotTL, alphaB * dotBL, dotNL ) ); - float v = 0.5 / ( gv + gl ); - return saturate(v); - } - float D_GGX_Anisotropic( const in float alphaT, const in float alphaB, const in float dotNH, const in float dotTH, const in float dotBH ) { - float a2 = alphaT * alphaB; - highp vec3 v = vec3( alphaB * dotTH, alphaT * dotBH, a2 * dotNH ); - highp float v2 = dot( v, v ); - float w2 = a2 / v2; - return RECIPROCAL_PI * a2 * pow2 ( w2 ); - } -#endif -#ifdef USE_CLEARCOAT - vec3 BRDF_GGX_Clearcoat( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material) { - vec3 f0 = material.clearcoatF0; - float f90 = material.clearcoatF90; - float roughness = material.clearcoatRoughness; - float alpha = pow2( roughness ); - vec3 halfDir = normalize( lightDir + viewDir ); - float dotNL = saturate( dot( normal, lightDir ) ); - float dotNV = saturate( dot( normal, viewDir ) ); - float dotNH = saturate( dot( normal, halfDir ) ); - float dotVH = saturate( dot( viewDir, halfDir ) ); - vec3 F = F_Schlick( f0, f90, dotVH ); - float V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV ); - float D = D_GGX( alpha, dotNH ); - return F * ( V * D ); - } -#endif -vec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) { - vec3 f0 = material.specularColor; - float f90 = material.specularF90; - float roughness = material.roughness; - float alpha = pow2( roughness ); - vec3 halfDir = normalize( lightDir + viewDir ); - float dotNL = saturate( dot( normal, lightDir ) ); - float dotNV = saturate( dot( normal, viewDir ) ); - float dotNH = saturate( dot( normal, halfDir ) ); - float dotVH = saturate( dot( viewDir, halfDir ) ); - vec3 F = F_Schlick( f0, f90, dotVH ); - #ifdef USE_IRIDESCENCE - F = mix( F, material.iridescenceFresnel, material.iridescence ); - #endif - #ifdef USE_ANISOTROPY - float dotTL = dot( material.anisotropyT, lightDir ); - float dotTV = dot( material.anisotropyT, viewDir ); - float dotTH = dot( material.anisotropyT, halfDir ); - float dotBL = dot( material.anisotropyB, lightDir ); - float dotBV = dot( material.anisotropyB, viewDir ); - float dotBH = dot( material.anisotropyB, halfDir ); - float V = V_GGX_SmithCorrelated_Anisotropic( material.alphaT, alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL ); - float D = D_GGX_Anisotropic( material.alphaT, alpha, dotNH, dotTH, dotBH ); - #else - float V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV ); - float D = D_GGX( alpha, dotNH ); - #endif - return F * ( V * D ); -} -vec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) { - const float LUT_SIZE = 64.0; - const float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE; - const float LUT_BIAS = 0.5 / LUT_SIZE; - float dotNV = saturate( dot( N, V ) ); - vec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) ); - uv = uv * LUT_SCALE + LUT_BIAS; - return uv; -} -float LTC_ClippedSphereFormFactor( const in vec3 f ) { - float l = length( f ); - return max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 ); -} -vec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) { - float x = dot( v1, v2 ); - float y = abs( x ); - float a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y; - float b = 3.4175940 + ( 4.1616724 + y ) * y; - float v = a / b; - float theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v; - return cross( v1, v2 ) * theta_sintheta; -} -vec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) { - vec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ]; - vec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ]; - vec3 lightNormal = cross( v1, v2 ); - if( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 ); - vec3 T1, T2; - T1 = normalize( V - N * dot( V, N ) ); - T2 = - cross( N, T1 ); - mat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) ); - vec3 coords[ 4 ]; - coords[ 0 ] = mat * ( rectCoords[ 0 ] - P ); - coords[ 1 ] = mat * ( rectCoords[ 1 ] - P ); - coords[ 2 ] = mat * ( rectCoords[ 2 ] - P ); - coords[ 3 ] = mat * ( rectCoords[ 3 ] - P ); - coords[ 0 ] = normalize( coords[ 0 ] ); - coords[ 1 ] = normalize( coords[ 1 ] ); - coords[ 2 ] = normalize( coords[ 2 ] ); - coords[ 3 ] = normalize( coords[ 3 ] ); - vec3 vectorFormFactor = vec3( 0.0 ); - vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] ); - vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] ); - vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] ); - vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] ); - float result = LTC_ClippedSphereFormFactor( vectorFormFactor ); - return vec3( result ); -} -#if defined( USE_SHEEN ) -float D_Charlie( float roughness, float dotNH ) { - float alpha = pow2( roughness ); - float invAlpha = 1.0 / alpha; - float cos2h = dotNH * dotNH; - float sin2h = max( 1.0 - cos2h, 0.0078125 ); - return ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI ); -} -float V_Neubelt( float dotNV, float dotNL ) { - return saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) ); -} -vec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) { - vec3 halfDir = normalize( lightDir + viewDir ); - float dotNL = saturate( dot( normal, lightDir ) ); - float dotNV = saturate( dot( normal, viewDir ) ); - float dotNH = saturate( dot( normal, halfDir ) ); - float D = D_Charlie( sheenRoughness, dotNH ); - float V = V_Neubelt( dotNV, dotNL ); - return sheenColor * ( D * V ); -} -#endif -float IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) { - float dotNV = saturate( dot( normal, viewDir ) ); - float r2 = roughness * roughness; - float a = roughness < 0.25 ? -339.2 * r2 + 161.4 * roughness - 25.9 : -8.48 * r2 + 14.3 * roughness - 9.95; - float b = roughness < 0.25 ? 44.0 * r2 - 23.7 * roughness + 3.26 : 1.97 * r2 - 3.27 * roughness + 0.72; - float DG = exp( a * dotNV + b ) + ( roughness < 0.25 ? 0.0 : 0.1 * ( roughness - 0.25 ) ); - return saturate( DG * RECIPROCAL_PI ); -} -vec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) { - float dotNV = saturate( dot( normal, viewDir ) ); - const vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 ); - const vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 ); - vec4 r = roughness * c0 + c1; - float a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y; - vec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw; - return fab; -} -vec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) { - vec2 fab = DFGApprox( normal, viewDir, roughness ); - return specularColor * fab.x + specularF90 * fab.y; -} -#ifdef USE_IRIDESCENCE -void computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) { -#else -void computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) { -#endif - vec2 fab = DFGApprox( normal, viewDir, roughness ); - #ifdef USE_IRIDESCENCE - vec3 Fr = mix( specularColor, iridescenceF0, iridescence ); - #else - vec3 Fr = specularColor; - #endif - vec3 FssEss = Fr * fab.x + specularF90 * fab.y; - float Ess = fab.x + fab.y; - float Ems = 1.0 - Ess; - vec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619; vec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg ); - singleScatter += FssEss; - multiScatter += Fms * Ems; -} -#if NUM_RECT_AREA_LIGHTS > 0 - void RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { - vec3 normal = geometryNormal; - vec3 viewDir = geometryViewDir; - vec3 position = geometryPosition; - vec3 lightPos = rectAreaLight.position; - vec3 halfWidth = rectAreaLight.halfWidth; - vec3 halfHeight = rectAreaLight.halfHeight; - vec3 lightColor = rectAreaLight.color; - float roughness = material.roughness; - vec3 rectCoords[ 4 ]; - rectCoords[ 0 ] = lightPos + halfWidth - halfHeight; rectCoords[ 1 ] = lightPos - halfWidth - halfHeight; - rectCoords[ 2 ] = lightPos - halfWidth + halfHeight; - rectCoords[ 3 ] = lightPos + halfWidth + halfHeight; - vec2 uv = LTC_Uv( normal, viewDir, roughness ); - vec4 t1 = texture2D( ltc_1, uv ); - vec4 t2 = texture2D( ltc_2, uv ); - mat3 mInv = mat3( - vec3( t1.x, 0, t1.y ), - vec3( 0, 1, 0 ), - vec3( t1.z, 0, t1.w ) - ); - vec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y ); - reflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords ); - reflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords ); - } -#endif -void RE_Direct_Physical( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { - float dotNL = saturate( dot( geometryNormal, directLight.direction ) ); - vec3 irradiance = dotNL * directLight.color; - #ifdef USE_CLEARCOAT - float dotNLcc = saturate( dot( geometryClearcoatNormal, directLight.direction ) ); - vec3 ccIrradiance = dotNLcc * directLight.color; - clearcoatSpecularDirect += ccIrradiance * BRDF_GGX_Clearcoat( directLight.direction, geometryViewDir, geometryClearcoatNormal, material ); - #endif - #ifdef USE_SHEEN - sheenSpecularDirect += irradiance * BRDF_Sheen( directLight.direction, geometryViewDir, geometryNormal, material.sheenColor, material.sheenRoughness ); - #endif - reflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometryViewDir, geometryNormal, material ); - reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); -} -void RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { - reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); -} -void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) { - #ifdef USE_CLEARCOAT - clearcoatSpecularIndirect += clearcoatRadiance * EnvironmentBRDF( geometryClearcoatNormal, geometryViewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness ); - #endif - #ifdef USE_SHEEN - sheenSpecularIndirect += irradiance * material.sheenColor * IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness ); - #endif - vec3 singleScattering = vec3( 0.0 ); - vec3 multiScattering = vec3( 0.0 ); - vec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI; - #ifdef USE_IRIDESCENCE - computeMultiscatteringIridescence( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness, singleScattering, multiScattering ); - #else - computeMultiscattering( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering ); - #endif - vec3 totalScattering = singleScattering + multiScattering; - vec3 diffuse = material.diffuseColor * ( 1.0 - max( max( totalScattering.r, totalScattering.g ), totalScattering.b ) ); - reflectedLight.indirectSpecular += radiance * singleScattering; - reflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance; - reflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance; -} -#define RE_Direct RE_Direct_Physical -#define RE_Direct_RectArea RE_Direct_RectArea_Physical -#define RE_IndirectDiffuse RE_IndirectDiffuse_Physical -#define RE_IndirectSpecular RE_IndirectSpecular_Physical -float computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) { - return saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion ); -}`,$b=` -vec3 geometryPosition = - vViewPosition; -vec3 geometryNormal = normal; -vec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition ); -vec3 geometryClearcoatNormal = vec3( 0.0 ); -#ifdef USE_CLEARCOAT - geometryClearcoatNormal = clearcoatNormal; -#endif -#ifdef USE_IRIDESCENCE - float dotNVi = saturate( dot( normal, geometryViewDir ) ); - if ( material.iridescenceThickness == 0.0 ) { - material.iridescence = 0.0; - } else { - material.iridescence = saturate( material.iridescence ); - } - if ( material.iridescence > 0.0 ) { - material.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor ); - material.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi ); - } -#endif -IncidentLight directLight; -#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct ) - PointLight pointLight; - #if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0 - PointLightShadow pointLightShadow; - #endif - #pragma unroll_loop_start - for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) { - pointLight = pointLights[ i ]; - getPointLightInfo( pointLight, geometryPosition, directLight ); - #if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS ) - pointLightShadow = pointLightShadows[ i ]; - directLight.color *= ( directLight.visible && receiveShadow ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0; - #endif - RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); - } - #pragma unroll_loop_end -#endif -#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct ) - SpotLight spotLight; - vec4 spotColor; - vec3 spotLightCoord; - bool inSpotLightMap; - #if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0 - SpotLightShadow spotLightShadow; - #endif - #pragma unroll_loop_start - for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) { - spotLight = spotLights[ i ]; - getSpotLightInfo( spotLight, geometryPosition, directLight ); - #if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS ) - #define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX - #elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS ) - #define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS - #else - #define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS ) - #endif - #if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS ) - spotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w; - inSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) ); - spotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy ); - directLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color; - #endif - #undef SPOT_LIGHT_MAP_INDEX - #if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS ) - spotLightShadow = spotLightShadows[ i ]; - directLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0; - #endif - RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); - } - #pragma unroll_loop_end -#endif -#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct ) - DirectionalLight directionalLight; - #if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0 - DirectionalLightShadow directionalLightShadow; - #endif - #pragma unroll_loop_start - for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) { - directionalLight = directionalLights[ i ]; - getDirectionalLightInfo( directionalLight, directLight ); - #if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS ) - directionalLightShadow = directionalLightShadows[ i ]; - directLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0; - #endif - RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); - } - #pragma unroll_loop_end -#endif -#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea ) - RectAreaLight rectAreaLight; - #pragma unroll_loop_start - for ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) { - rectAreaLight = rectAreaLights[ i ]; - RE_Direct_RectArea( rectAreaLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); - } - #pragma unroll_loop_end -#endif -#if defined( RE_IndirectDiffuse ) - vec3 iblIrradiance = vec3( 0.0 ); - vec3 irradiance = getAmbientLightIrradiance( ambientLightColor ); - #if defined( USE_LIGHT_PROBES ) - irradiance += getLightProbeIrradiance( lightProbe, geometryNormal ); - #endif - #if ( NUM_HEMI_LIGHTS > 0 ) - #pragma unroll_loop_start - for ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) { - irradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometryNormal ); - } - #pragma unroll_loop_end - #endif -#endif -#if defined( RE_IndirectSpecular ) - vec3 radiance = vec3( 0.0 ); - vec3 clearcoatRadiance = vec3( 0.0 ); -#endif`,Xb=`#if defined( RE_IndirectDiffuse ) - #ifdef USE_LIGHTMAP - vec4 lightMapTexel = texture2D( lightMap, vLightMapUv ); - vec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity; - irradiance += lightMapIrradiance; - #endif - #if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV ) - iblIrradiance += getIBLIrradiance( geometryNormal ); - #endif -#endif -#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular ) - #ifdef USE_ANISOTROPY - radiance += getIBLAnisotropyRadiance( geometryViewDir, geometryNormal, material.roughness, material.anisotropyB, material.anisotropy ); - #else - radiance += getIBLRadiance( geometryViewDir, geometryNormal, material.roughness ); - #endif - #ifdef USE_CLEARCOAT - clearcoatRadiance += getIBLRadiance( geometryViewDir, geometryClearcoatNormal, material.clearcoatRoughness ); - #endif -#endif`,qb=`#if defined( RE_IndirectDiffuse ) - RE_IndirectDiffuse( irradiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); -#endif -#if defined( RE_IndirectSpecular ) - RE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); -#endif`,Yb=`#if defined( USE_LOGDEPTHBUF ) - gl_FragDepth = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5; -#endif`,Zb=`#if defined( USE_LOGDEPTHBUF ) - uniform float logDepthBufFC; - varying float vFragDepth; - varying float vIsPerspective; -#endif`,Jb=`#ifdef USE_LOGDEPTHBUF - varying float vFragDepth; - varying float vIsPerspective; -#endif`,Kb=`#ifdef USE_LOGDEPTHBUF - vFragDepth = 1.0 + gl_Position.w; - vIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) ); -#endif`,jb=`#ifdef USE_MAP - vec4 sampledDiffuseColor = texture2D( map, vMapUv ); - #ifdef DECODE_VIDEO_TEXTURE - sampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w ); - - #endif - diffuseColor *= sampledDiffuseColor; -#endif`,Qb=`#ifdef USE_MAP - uniform sampler2D map; -#endif`,eS=`#if defined( USE_MAP ) || defined( USE_ALPHAMAP ) - #if defined( USE_POINTS_UV ) - vec2 uv = vUv; - #else - vec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy; - #endif -#endif -#ifdef USE_MAP - diffuseColor *= texture2D( map, uv ); -#endif -#ifdef USE_ALPHAMAP - diffuseColor.a *= texture2D( alphaMap, uv ).g; -#endif`,tS=`#if defined( USE_POINTS_UV ) - varying vec2 vUv; -#else - #if defined( USE_MAP ) || defined( USE_ALPHAMAP ) - uniform mat3 uvTransform; - #endif -#endif -#ifdef USE_MAP - uniform sampler2D map; -#endif -#ifdef USE_ALPHAMAP - uniform sampler2D alphaMap; -#endif`,nS=`float metalnessFactor = metalness; -#ifdef USE_METALNESSMAP - vec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv ); - metalnessFactor *= texelMetalness.b; -#endif`,iS=`#ifdef USE_METALNESSMAP - uniform sampler2D metalnessMap; -#endif`,sS=`#ifdef USE_INSTANCING_MORPH - float morphTargetInfluences[ MORPHTARGETS_COUNT ]; - float morphTargetBaseInfluence = texelFetch( morphTexture, ivec2( 0, gl_InstanceID ), 0 ).r; - for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { - morphTargetInfluences[i] = texelFetch( morphTexture, ivec2( i + 1, gl_InstanceID ), 0 ).r; - } -#endif`,rS=`#if defined( USE_MORPHCOLORS ) - vColor *= morphTargetBaseInfluence; - for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { - #if defined( USE_COLOR_ALPHA ) - if ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ) * morphTargetInfluences[ i ]; - #elif defined( USE_COLOR ) - if ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ).rgb * morphTargetInfluences[ i ]; - #endif - } -#endif`,oS=`#ifdef USE_MORPHNORMALS - objectNormal *= morphTargetBaseInfluence; - for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { - if ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1 ).xyz * morphTargetInfluences[ i ]; - } -#endif`,aS=`#ifdef USE_MORPHTARGETS - #ifndef USE_INSTANCING_MORPH - uniform float morphTargetBaseInfluence; - uniform float morphTargetInfluences[ MORPHTARGETS_COUNT ]; - #endif - uniform sampler2DArray morphTargetsTexture; - uniform ivec2 morphTargetsTextureSize; - vec4 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset ) { - int texelIndex = vertexIndex * MORPHTARGETS_TEXTURE_STRIDE + offset; - int y = texelIndex / morphTargetsTextureSize.x; - int x = texelIndex - y * morphTargetsTextureSize.x; - ivec3 morphUV = ivec3( x, y, morphTargetIndex ); - return texelFetch( morphTargetsTexture, morphUV, 0 ); - } -#endif`,lS=`#ifdef USE_MORPHTARGETS - transformed *= morphTargetBaseInfluence; - for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { - if ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ]; - } -#endif`,cS=`float faceDirection = gl_FrontFacing ? 1.0 : - 1.0; -#ifdef FLAT_SHADED - vec3 fdx = dFdx( vViewPosition ); - vec3 fdy = dFdy( vViewPosition ); - vec3 normal = normalize( cross( fdx, fdy ) ); -#else - vec3 normal = normalize( vNormal ); - #ifdef DOUBLE_SIDED - normal *= faceDirection; - #endif -#endif -#if defined( USE_NORMALMAP_TANGENTSPACE ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) - #ifdef USE_TANGENT - mat3 tbn = mat3( normalize( vTangent ), normalize( vBitangent ), normal ); - #else - mat3 tbn = getTangentFrame( - vViewPosition, normal, - #if defined( USE_NORMALMAP ) - vNormalMapUv - #elif defined( USE_CLEARCOAT_NORMALMAP ) - vClearcoatNormalMapUv - #else - vUv - #endif - ); - #endif - #if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED ) - tbn[0] *= faceDirection; - tbn[1] *= faceDirection; - #endif -#endif -#ifdef USE_CLEARCOAT_NORMALMAP - #ifdef USE_TANGENT - mat3 tbn2 = mat3( normalize( vTangent ), normalize( vBitangent ), normal ); - #else - mat3 tbn2 = getTangentFrame( - vViewPosition, normal, vClearcoatNormalMapUv ); - #endif - #if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED ) - tbn2[0] *= faceDirection; - tbn2[1] *= faceDirection; - #endif -#endif -vec3 nonPerturbedNormal = normal;`,uS=`#ifdef USE_NORMALMAP_OBJECTSPACE - normal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0; - #ifdef FLIP_SIDED - normal = - normal; - #endif - #ifdef DOUBLE_SIDED - normal = normal * faceDirection; - #endif - normal = normalize( normalMatrix * normal ); -#elif defined( USE_NORMALMAP_TANGENTSPACE ) - vec3 mapN = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0; - mapN.xy *= normalScale; - normal = normalize( tbn * mapN ); -#elif defined( USE_BUMPMAP ) - normal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection ); -#endif`,hS=`#ifndef FLAT_SHADED - varying vec3 vNormal; - #ifdef USE_TANGENT - varying vec3 vTangent; - varying vec3 vBitangent; - #endif -#endif`,dS=`#ifndef FLAT_SHADED - varying vec3 vNormal; - #ifdef USE_TANGENT - varying vec3 vTangent; - varying vec3 vBitangent; - #endif -#endif`,fS=`#ifndef FLAT_SHADED - vNormal = normalize( transformedNormal ); - #ifdef USE_TANGENT - vTangent = normalize( transformedTangent ); - vBitangent = normalize( cross( vNormal, vTangent ) * tangent.w ); - #endif -#endif`,pS=`#ifdef USE_NORMALMAP - uniform sampler2D normalMap; - uniform vec2 normalScale; -#endif -#ifdef USE_NORMALMAP_OBJECTSPACE - uniform mat3 normalMatrix; -#endif -#if ! defined ( USE_TANGENT ) && ( defined ( USE_NORMALMAP_TANGENTSPACE ) || defined ( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) ) - mat3 getTangentFrame( vec3 eye_pos, vec3 surf_norm, vec2 uv ) { - vec3 q0 = dFdx( eye_pos.xyz ); - vec3 q1 = dFdy( eye_pos.xyz ); - vec2 st0 = dFdx( uv.st ); - vec2 st1 = dFdy( uv.st ); - vec3 N = surf_norm; - vec3 q1perp = cross( q1, N ); - vec3 q0perp = cross( N, q0 ); - vec3 T = q1perp * st0.x + q0perp * st1.x; - vec3 B = q1perp * st0.y + q0perp * st1.y; - float det = max( dot( T, T ), dot( B, B ) ); - float scale = ( det == 0.0 ) ? 0.0 : inversesqrt( det ); - return mat3( T * scale, B * scale, N ); - } -#endif`,mS=`#ifdef USE_CLEARCOAT - vec3 clearcoatNormal = nonPerturbedNormal; -#endif`,gS=`#ifdef USE_CLEARCOAT_NORMALMAP - vec3 clearcoatMapN = texture2D( clearcoatNormalMap, vClearcoatNormalMapUv ).xyz * 2.0 - 1.0; - clearcoatMapN.xy *= clearcoatNormalScale; - clearcoatNormal = normalize( tbn2 * clearcoatMapN ); -#endif`,vS=`#ifdef USE_CLEARCOATMAP - uniform sampler2D clearcoatMap; -#endif -#ifdef USE_CLEARCOAT_NORMALMAP - uniform sampler2D clearcoatNormalMap; - uniform vec2 clearcoatNormalScale; -#endif -#ifdef USE_CLEARCOAT_ROUGHNESSMAP - uniform sampler2D clearcoatRoughnessMap; -#endif`,_S=`#ifdef USE_IRIDESCENCEMAP - uniform sampler2D iridescenceMap; -#endif -#ifdef USE_IRIDESCENCE_THICKNESSMAP - uniform sampler2D iridescenceThicknessMap; -#endif`,yS=`#ifdef OPAQUE -diffuseColor.a = 1.0; -#endif -#ifdef USE_TRANSMISSION -diffuseColor.a *= material.transmissionAlpha; -#endif -gl_FragColor = vec4( outgoingLight, diffuseColor.a );`,xS=`vec3 packNormalToRGB( const in vec3 normal ) { - return normalize( normal ) * 0.5 + 0.5; -} -vec3 unpackRGBToNormal( const in vec3 rgb ) { - return 2.0 * rgb.xyz - 1.0; -} -const float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.; -const vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. ); -const vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. ); -const float ShiftRight8 = 1. / 256.; -vec4 packDepthToRGBA( const in float v ) { - vec4 r = vec4( fract( v * PackFactors ), v ); - r.yzw -= r.xyz * ShiftRight8; return r * PackUpscale; -} -float unpackRGBAToDepth( const in vec4 v ) { - return dot( v, UnpackFactors ); -} -vec2 packDepthToRG( in highp float v ) { - return packDepthToRGBA( v ).yx; -} -float unpackRGToDepth( const in highp vec2 v ) { - return unpackRGBAToDepth( vec4( v.xy, 0.0, 0.0 ) ); -} -vec4 pack2HalfToRGBA( vec2 v ) { - vec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) ); - return vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w ); -} -vec2 unpackRGBATo2Half( vec4 v ) { - return vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) ); -} -float viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) { - return ( viewZ + near ) / ( near - far ); -} -float orthographicDepthToViewZ( const in float depth, const in float near, const in float far ) { - return depth * ( near - far ) - near; -} -float viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) { - return ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ ); -} -float perspectiveDepthToViewZ( const in float depth, const in float near, const in float far ) { - return ( near * far ) / ( ( far - near ) * depth - far ); -}`,MS=`#ifdef PREMULTIPLIED_ALPHA - gl_FragColor.rgb *= gl_FragColor.a; -#endif`,bS=`vec4 mvPosition = vec4( transformed, 1.0 ); -#ifdef USE_BATCHING - mvPosition = batchingMatrix * mvPosition; -#endif -#ifdef USE_INSTANCING - mvPosition = instanceMatrix * mvPosition; -#endif -mvPosition = modelViewMatrix * mvPosition; -gl_Position = projectionMatrix * mvPosition;`,SS=`#ifdef DITHERING - gl_FragColor.rgb = dithering( gl_FragColor.rgb ); -#endif`,wS=`#ifdef DITHERING - vec3 dithering( vec3 color ) { - float grid_position = rand( gl_FragCoord.xy ); - vec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 ); - dither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position ); - return color + dither_shift_RGB; - } -#endif`,AS=`float roughnessFactor = roughness; -#ifdef USE_ROUGHNESSMAP - vec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv ); - roughnessFactor *= texelRoughness.g; -#endif`,TS=`#ifdef USE_ROUGHNESSMAP - uniform sampler2D roughnessMap; -#endif`,ES=`#if NUM_SPOT_LIGHT_COORDS > 0 - varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ]; -#endif -#if NUM_SPOT_LIGHT_MAPS > 0 - uniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ]; -#endif -#ifdef USE_SHADOWMAP - #if NUM_DIR_LIGHT_SHADOWS > 0 - uniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ]; - varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ]; - struct DirectionalLightShadow { - float shadowBias; - float shadowNormalBias; - float shadowRadius; - vec2 shadowMapSize; - }; - uniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ]; - #endif - #if NUM_SPOT_LIGHT_SHADOWS > 0 - uniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ]; - struct SpotLightShadow { - float shadowBias; - float shadowNormalBias; - float shadowRadius; - vec2 shadowMapSize; - }; - uniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ]; - #endif - #if NUM_POINT_LIGHT_SHADOWS > 0 - uniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ]; - varying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ]; - struct PointLightShadow { - float shadowBias; - float shadowNormalBias; - float shadowRadius; - vec2 shadowMapSize; - float shadowCameraNear; - float shadowCameraFar; - }; - uniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ]; - #endif - float texture2DCompare( sampler2D depths, vec2 uv, float compare ) { - return step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) ); - } - vec2 texture2DDistribution( sampler2D shadow, vec2 uv ) { - return unpackRGBATo2Half( texture2D( shadow, uv ) ); - } - float VSMShadow (sampler2D shadow, vec2 uv, float compare ){ - float occlusion = 1.0; - vec2 distribution = texture2DDistribution( shadow, uv ); - float hard_shadow = step( compare , distribution.x ); - if (hard_shadow != 1.0 ) { - float distance = compare - distribution.x ; - float variance = max( 0.00000, distribution.y * distribution.y ); - float softness_probability = variance / (variance + distance * distance ); softness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 ); occlusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 ); - } - return occlusion; - } - float getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) { - float shadow = 1.0; - shadowCoord.xyz /= shadowCoord.w; - shadowCoord.z += shadowBias; - bool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0; - bool frustumTest = inFrustum && shadowCoord.z <= 1.0; - if ( frustumTest ) { - #if defined( SHADOWMAP_TYPE_PCF ) - vec2 texelSize = vec2( 1.0 ) / shadowMapSize; - float dx0 = - texelSize.x * shadowRadius; - float dy0 = - texelSize.y * shadowRadius; - float dx1 = + texelSize.x * shadowRadius; - float dy1 = + texelSize.y * shadowRadius; - float dx2 = dx0 / 2.0; - float dy2 = dy0 / 2.0; - float dx3 = dx1 / 2.0; - float dy3 = dy1 / 2.0; - shadow = ( - texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) + - texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) + - texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) + - texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) + - texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) + - texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) + - texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) + - texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) + - texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) + - texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) + - texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) + - texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) + - texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) + - texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) + - texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) + - texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) + - texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z ) - ) * ( 1.0 / 17.0 ); - #elif defined( SHADOWMAP_TYPE_PCF_SOFT ) - vec2 texelSize = vec2( 1.0 ) / shadowMapSize; - float dx = texelSize.x; - float dy = texelSize.y; - vec2 uv = shadowCoord.xy; - vec2 f = fract( uv * shadowMapSize + 0.5 ); - uv -= f * texelSize; - shadow = ( - texture2DCompare( shadowMap, uv, shadowCoord.z ) + - texture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) + - texture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) + - texture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) + - mix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ), - texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ), - f.x ) + - mix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ), - texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ), - f.x ) + - mix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ), - texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ), - f.y ) + - mix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ), - texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ), - f.y ) + - mix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ), - texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ), - f.x ), - mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ), - texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ), - f.x ), - f.y ) - ) * ( 1.0 / 9.0 ); - #elif defined( SHADOWMAP_TYPE_VSM ) - shadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z ); - #else - shadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ); - #endif - } - return shadow; - } - vec2 cubeToUV( vec3 v, float texelSizeY ) { - vec3 absV = abs( v ); - float scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) ); - absV *= scaleToCube; - v *= scaleToCube * ( 1.0 - 2.0 * texelSizeY ); - vec2 planar = v.xy; - float almostATexel = 1.5 * texelSizeY; - float almostOne = 1.0 - almostATexel; - if ( absV.z >= almostOne ) { - if ( v.z > 0.0 ) - planar.x = 4.0 - v.x; - } else if ( absV.x >= almostOne ) { - float signX = sign( v.x ); - planar.x = v.z * signX + 2.0 * signX; - } else if ( absV.y >= almostOne ) { - float signY = sign( v.y ); - planar.x = v.x + 2.0 * signY + 2.0; - planar.y = v.z * signY - 2.0; - } - return vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 ); - } - float getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) { - float shadow = 1.0; - vec3 lightToPosition = shadowCoord.xyz; - - float lightToPositionLength = length( lightToPosition ); - if ( lightToPositionLength - shadowCameraFar <= 0.0 && lightToPositionLength - shadowCameraNear >= 0.0 ) { - float dp = ( lightToPositionLength - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear ); dp += shadowBias; - vec3 bd3D = normalize( lightToPosition ); - vec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) ); - #if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM ) - vec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y; - shadow = ( - texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) + - texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) + - texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) + - texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) + - texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) + - texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) + - texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) + - texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) + - texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp ) - ) * ( 1.0 / 9.0 ); - #else - shadow = texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ); - #endif - } - return shadow; - } -#endif`,CS=`#if NUM_SPOT_LIGHT_COORDS > 0 - uniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ]; - varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ]; -#endif -#ifdef USE_SHADOWMAP - #if NUM_DIR_LIGHT_SHADOWS > 0 - uniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ]; - varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ]; - struct DirectionalLightShadow { - float shadowBias; - float shadowNormalBias; - float shadowRadius; - vec2 shadowMapSize; - }; - uniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ]; - #endif - #if NUM_SPOT_LIGHT_SHADOWS > 0 - struct SpotLightShadow { - float shadowBias; - float shadowNormalBias; - float shadowRadius; - vec2 shadowMapSize; - }; - uniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ]; - #endif - #if NUM_POINT_LIGHT_SHADOWS > 0 - uniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ]; - varying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ]; - struct PointLightShadow { - float shadowBias; - float shadowNormalBias; - float shadowRadius; - vec2 shadowMapSize; - float shadowCameraNear; - float shadowCameraFar; - }; - uniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ]; - #endif -#endif`,PS=`#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 ) - vec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix ); - vec4 shadowWorldPosition; -#endif -#if defined( USE_SHADOWMAP ) - #if NUM_DIR_LIGHT_SHADOWS > 0 - #pragma unroll_loop_start - for ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) { - shadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 ); - vDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition; - } - #pragma unroll_loop_end - #endif - #if NUM_POINT_LIGHT_SHADOWS > 0 - #pragma unroll_loop_start - for ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) { - shadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 ); - vPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition; - } - #pragma unroll_loop_end - #endif -#endif -#if NUM_SPOT_LIGHT_COORDS > 0 - #pragma unroll_loop_start - for ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) { - shadowWorldPosition = worldPosition; - #if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS ) - shadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias; - #endif - vSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition; - } - #pragma unroll_loop_end -#endif`,RS=`float getShadowMask() { - float shadow = 1.0; - #ifdef USE_SHADOWMAP - #if NUM_DIR_LIGHT_SHADOWS > 0 - DirectionalLightShadow directionalLight; - #pragma unroll_loop_start - for ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) { - directionalLight = directionalLightShadows[ i ]; - shadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0; - } - #pragma unroll_loop_end - #endif - #if NUM_SPOT_LIGHT_SHADOWS > 0 - SpotLightShadow spotLight; - #pragma unroll_loop_start - for ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) { - spotLight = spotLightShadows[ i ]; - shadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0; - } - #pragma unroll_loop_end - #endif - #if NUM_POINT_LIGHT_SHADOWS > 0 - PointLightShadow pointLight; - #pragma unroll_loop_start - for ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) { - pointLight = pointLightShadows[ i ]; - shadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0; - } - #pragma unroll_loop_end - #endif - #endif - return shadow; -}`,IS=`#ifdef USE_SKINNING - mat4 boneMatX = getBoneMatrix( skinIndex.x ); - mat4 boneMatY = getBoneMatrix( skinIndex.y ); - mat4 boneMatZ = getBoneMatrix( skinIndex.z ); - mat4 boneMatW = getBoneMatrix( skinIndex.w ); -#endif`,LS=`#ifdef USE_SKINNING - uniform mat4 bindMatrix; - uniform mat4 bindMatrixInverse; - uniform highp sampler2D boneTexture; - mat4 getBoneMatrix( const in float i ) { - int size = textureSize( boneTexture, 0 ).x; - int j = int( i ) * 4; - int x = j % size; - int y = j / size; - vec4 v1 = texelFetch( boneTexture, ivec2( x, y ), 0 ); - vec4 v2 = texelFetch( boneTexture, ivec2( x + 1, y ), 0 ); - vec4 v3 = texelFetch( boneTexture, ivec2( x + 2, y ), 0 ); - vec4 v4 = texelFetch( boneTexture, ivec2( x + 3, y ), 0 ); - return mat4( v1, v2, v3, v4 ); - } -#endif`,NS=`#ifdef USE_SKINNING - vec4 skinVertex = bindMatrix * vec4( transformed, 1.0 ); - vec4 skinned = vec4( 0.0 ); - skinned += boneMatX * skinVertex * skinWeight.x; - skinned += boneMatY * skinVertex * skinWeight.y; - skinned += boneMatZ * skinVertex * skinWeight.z; - skinned += boneMatW * skinVertex * skinWeight.w; - transformed = ( bindMatrixInverse * skinned ).xyz; -#endif`,DS=`#ifdef USE_SKINNING - mat4 skinMatrix = mat4( 0.0 ); - skinMatrix += skinWeight.x * boneMatX; - skinMatrix += skinWeight.y * boneMatY; - skinMatrix += skinWeight.z * boneMatZ; - skinMatrix += skinWeight.w * boneMatW; - skinMatrix = bindMatrixInverse * skinMatrix * bindMatrix; - objectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz; - #ifdef USE_TANGENT - objectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz; - #endif -#endif`,US=`float specularStrength; -#ifdef USE_SPECULARMAP - vec4 texelSpecular = texture2D( specularMap, vSpecularMapUv ); - specularStrength = texelSpecular.r; -#else - specularStrength = 1.0; -#endif`,OS=`#ifdef USE_SPECULARMAP - uniform sampler2D specularMap; -#endif`,FS=`#if defined( TONE_MAPPING ) - gl_FragColor.rgb = toneMapping( gl_FragColor.rgb ); -#endif`,kS=`#ifndef saturate -#define saturate( a ) clamp( a, 0.0, 1.0 ) -#endif -uniform float toneMappingExposure; -vec3 LinearToneMapping( vec3 color ) { - return saturate( toneMappingExposure * color ); -} -vec3 ReinhardToneMapping( vec3 color ) { - color *= toneMappingExposure; - return saturate( color / ( vec3( 1.0 ) + color ) ); -} -vec3 OptimizedCineonToneMapping( vec3 color ) { - color *= toneMappingExposure; - color = max( vec3( 0.0 ), color - 0.004 ); - return pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) ); -} -vec3 RRTAndODTFit( vec3 v ) { - vec3 a = v * ( v + 0.0245786 ) - 0.000090537; - vec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081; - return a / b; -} -vec3 ACESFilmicToneMapping( vec3 color ) { - const mat3 ACESInputMat = mat3( - vec3( 0.59719, 0.07600, 0.02840 ), vec3( 0.35458, 0.90834, 0.13383 ), - vec3( 0.04823, 0.01566, 0.83777 ) - ); - const mat3 ACESOutputMat = mat3( - vec3( 1.60475, -0.10208, -0.00327 ), vec3( -0.53108, 1.10813, -0.07276 ), - vec3( -0.07367, -0.00605, 1.07602 ) - ); - color *= toneMappingExposure / 0.6; - color = ACESInputMat * color; - color = RRTAndODTFit( color ); - color = ACESOutputMat * color; - return saturate( color ); -} -const mat3 LINEAR_REC2020_TO_LINEAR_SRGB = mat3( - vec3( 1.6605, - 0.1246, - 0.0182 ), - vec3( - 0.5876, 1.1329, - 0.1006 ), - vec3( - 0.0728, - 0.0083, 1.1187 ) -); -const mat3 LINEAR_SRGB_TO_LINEAR_REC2020 = mat3( - vec3( 0.6274, 0.0691, 0.0164 ), - vec3( 0.3293, 0.9195, 0.0880 ), - vec3( 0.0433, 0.0113, 0.8956 ) -); -vec3 agxDefaultContrastApprox( vec3 x ) { - vec3 x2 = x * x; - vec3 x4 = x2 * x2; - return + 15.5 * x4 * x2 - - 40.14 * x4 * x - + 31.96 * x4 - - 6.868 * x2 * x - + 0.4298 * x2 - + 0.1191 * x - - 0.00232; -} -vec3 AgXToneMapping( vec3 color ) { - const mat3 AgXInsetMatrix = mat3( - vec3( 0.856627153315983, 0.137318972929847, 0.11189821299995 ), - vec3( 0.0951212405381588, 0.761241990602591, 0.0767994186031903 ), - vec3( 0.0482516061458583, 0.101439036467562, 0.811302368396859 ) - ); - const mat3 AgXOutsetMatrix = mat3( - vec3( 1.1271005818144368, - 0.1413297634984383, - 0.14132976349843826 ), - vec3( - 0.11060664309660323, 1.157823702216272, - 0.11060664309660294 ), - vec3( - 0.016493938717834573, - 0.016493938717834257, 1.2519364065950405 ) - ); - const float AgxMinEv = - 12.47393; const float AgxMaxEv = 4.026069; - color *= toneMappingExposure; - color = LINEAR_SRGB_TO_LINEAR_REC2020 * color; - color = AgXInsetMatrix * color; - color = max( color, 1e-10 ); color = log2( color ); - color = ( color - AgxMinEv ) / ( AgxMaxEv - AgxMinEv ); - color = clamp( color, 0.0, 1.0 ); - color = agxDefaultContrastApprox( color ); - color = AgXOutsetMatrix * color; - color = pow( max( vec3( 0.0 ), color ), vec3( 2.2 ) ); - color = LINEAR_REC2020_TO_LINEAR_SRGB * color; - color = clamp( color, 0.0, 1.0 ); - return color; -} -vec3 NeutralToneMapping( vec3 color ) { - const float StartCompression = 0.8 - 0.04; - const float Desaturation = 0.15; - color *= toneMappingExposure; - float x = min( color.r, min( color.g, color.b ) ); - float offset = x < 0.08 ? x - 6.25 * x * x : 0.04; - color -= offset; - float peak = max( color.r, max( color.g, color.b ) ); - if ( peak < StartCompression ) return color; - float d = 1. - StartCompression; - float newPeak = 1. - d * d / ( peak + d - StartCompression ); - color *= newPeak / peak; - float g = 1. - 1. / ( Desaturation * ( peak - newPeak ) + 1. ); - return mix( color, vec3( newPeak ), g ); -} -vec3 CustomToneMapping( vec3 color ) { return color; }`,BS=`#ifdef USE_TRANSMISSION - material.transmission = transmission; - material.transmissionAlpha = 1.0; - material.thickness = thickness; - material.attenuationDistance = attenuationDistance; - material.attenuationColor = attenuationColor; - #ifdef USE_TRANSMISSIONMAP - material.transmission *= texture2D( transmissionMap, vTransmissionMapUv ).r; - #endif - #ifdef USE_THICKNESSMAP - material.thickness *= texture2D( thicknessMap, vThicknessMapUv ).g; - #endif - vec3 pos = vWorldPosition; - vec3 v = normalize( cameraPosition - pos ); - vec3 n = inverseTransformDirection( normal, viewMatrix ); - vec4 transmitted = getIBLVolumeRefraction( - n, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90, - pos, modelMatrix, viewMatrix, projectionMatrix, material.dispersion, material.ior, material.thickness, - material.attenuationColor, material.attenuationDistance ); - material.transmissionAlpha = mix( material.transmissionAlpha, transmitted.a, material.transmission ); - totalDiffuse = mix( totalDiffuse, transmitted.rgb, material.transmission ); -#endif`,zS=`#ifdef USE_TRANSMISSION - uniform float transmission; - uniform float thickness; - uniform float attenuationDistance; - uniform vec3 attenuationColor; - #ifdef USE_TRANSMISSIONMAP - uniform sampler2D transmissionMap; - #endif - #ifdef USE_THICKNESSMAP - uniform sampler2D thicknessMap; - #endif - uniform vec2 transmissionSamplerSize; - uniform sampler2D transmissionSamplerMap; - uniform mat4 modelMatrix; - uniform mat4 projectionMatrix; - varying vec3 vWorldPosition; - float w0( float a ) { - return ( 1.0 / 6.0 ) * ( a * ( a * ( - a + 3.0 ) - 3.0 ) + 1.0 ); - } - float w1( float a ) { - return ( 1.0 / 6.0 ) * ( a * a * ( 3.0 * a - 6.0 ) + 4.0 ); - } - float w2( float a ){ - return ( 1.0 / 6.0 ) * ( a * ( a * ( - 3.0 * a + 3.0 ) + 3.0 ) + 1.0 ); - } - float w3( float a ) { - return ( 1.0 / 6.0 ) * ( a * a * a ); - } - float g0( float a ) { - return w0( a ) + w1( a ); - } - float g1( float a ) { - return w2( a ) + w3( a ); - } - float h0( float a ) { - return - 1.0 + w1( a ) / ( w0( a ) + w1( a ) ); - } - float h1( float a ) { - return 1.0 + w3( a ) / ( w2( a ) + w3( a ) ); - } - vec4 bicubic( sampler2D tex, vec2 uv, vec4 texelSize, float lod ) { - uv = uv * texelSize.zw + 0.5; - vec2 iuv = floor( uv ); - vec2 fuv = fract( uv ); - float g0x = g0( fuv.x ); - float g1x = g1( fuv.x ); - float h0x = h0( fuv.x ); - float h1x = h1( fuv.x ); - float h0y = h0( fuv.y ); - float h1y = h1( fuv.y ); - vec2 p0 = ( vec2( iuv.x + h0x, iuv.y + h0y ) - 0.5 ) * texelSize.xy; - vec2 p1 = ( vec2( iuv.x + h1x, iuv.y + h0y ) - 0.5 ) * texelSize.xy; - vec2 p2 = ( vec2( iuv.x + h0x, iuv.y + h1y ) - 0.5 ) * texelSize.xy; - vec2 p3 = ( vec2( iuv.x + h1x, iuv.y + h1y ) - 0.5 ) * texelSize.xy; - return g0( fuv.y ) * ( g0x * textureLod( tex, p0, lod ) + g1x * textureLod( tex, p1, lod ) ) + - g1( fuv.y ) * ( g0x * textureLod( tex, p2, lod ) + g1x * textureLod( tex, p3, lod ) ); - } - vec4 textureBicubic( sampler2D sampler, vec2 uv, float lod ) { - vec2 fLodSize = vec2( textureSize( sampler, int( lod ) ) ); - vec2 cLodSize = vec2( textureSize( sampler, int( lod + 1.0 ) ) ); - vec2 fLodSizeInv = 1.0 / fLodSize; - vec2 cLodSizeInv = 1.0 / cLodSize; - vec4 fSample = bicubic( sampler, uv, vec4( fLodSizeInv, fLodSize ), floor( lod ) ); - vec4 cSample = bicubic( sampler, uv, vec4( cLodSizeInv, cLodSize ), ceil( lod ) ); - return mix( fSample, cSample, fract( lod ) ); - } - vec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) { - vec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior ); - vec3 modelScale; - modelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) ); - modelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) ); - modelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) ); - return normalize( refractionVector ) * thickness * modelScale; - } - float applyIorToRoughness( const in float roughness, const in float ior ) { - return roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 ); - } - vec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) { - float lod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior ); - return textureBicubic( transmissionSamplerMap, fragCoord.xy, lod ); - } - vec3 volumeAttenuation( const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) { - if ( isinf( attenuationDistance ) ) { - return vec3( 1.0 ); - } else { - vec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance; - vec3 transmittance = exp( - attenuationCoefficient * transmissionDistance ); return transmittance; - } - } - vec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor, - const in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix, - const in mat4 viewMatrix, const in mat4 projMatrix, const in float dispersion, const in float ior, const in float thickness, - const in vec3 attenuationColor, const in float attenuationDistance ) { - vec4 transmittedLight; - vec3 transmittance; - #ifdef USE_DISPERSION - float halfSpread = ( ior - 1.0 ) * 0.025 * dispersion; - vec3 iors = vec3( ior - halfSpread, ior, ior + halfSpread ); - for ( int i = 0; i < 3; i ++ ) { - vec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, iors[ i ], modelMatrix ); - vec3 refractedRayExit = position + transmissionRay; - - vec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 ); - vec2 refractionCoords = ndcPos.xy / ndcPos.w; - refractionCoords += 1.0; - refractionCoords /= 2.0; - - vec4 transmissionSample = getTransmissionSample( refractionCoords, roughness, iors[ i ] ); - transmittedLight[ i ] = transmissionSample[ i ]; - transmittedLight.a += transmissionSample.a; - transmittance[ i ] = diffuseColor[ i ] * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance )[ i ]; - } - transmittedLight.a /= 3.0; - - #else - - vec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix ); - vec3 refractedRayExit = position + transmissionRay; - vec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 ); - vec2 refractionCoords = ndcPos.xy / ndcPos.w; - refractionCoords += 1.0; - refractionCoords /= 2.0; - transmittedLight = getTransmissionSample( refractionCoords, roughness, ior ); - transmittance = diffuseColor * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance ); - - #endif - vec3 attenuatedColor = transmittance * transmittedLight.rgb; - vec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness ); - float transmittanceFactor = ( transmittance.r + transmittance.g + transmittance.b ) / 3.0; - return vec4( ( 1.0 - F ) * attenuatedColor, 1.0 - ( 1.0 - transmittedLight.a ) * transmittanceFactor ); - } -#endif`,VS=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) - varying vec2 vUv; -#endif -#ifdef USE_MAP - varying vec2 vMapUv; -#endif -#ifdef USE_ALPHAMAP - varying vec2 vAlphaMapUv; -#endif -#ifdef USE_LIGHTMAP - varying vec2 vLightMapUv; -#endif -#ifdef USE_AOMAP - varying vec2 vAoMapUv; -#endif -#ifdef USE_BUMPMAP - varying vec2 vBumpMapUv; -#endif -#ifdef USE_NORMALMAP - varying vec2 vNormalMapUv; -#endif -#ifdef USE_EMISSIVEMAP - varying vec2 vEmissiveMapUv; -#endif -#ifdef USE_METALNESSMAP - varying vec2 vMetalnessMapUv; -#endif -#ifdef USE_ROUGHNESSMAP - varying vec2 vRoughnessMapUv; -#endif -#ifdef USE_ANISOTROPYMAP - varying vec2 vAnisotropyMapUv; -#endif -#ifdef USE_CLEARCOATMAP - varying vec2 vClearcoatMapUv; -#endif -#ifdef USE_CLEARCOAT_NORMALMAP - varying vec2 vClearcoatNormalMapUv; -#endif -#ifdef USE_CLEARCOAT_ROUGHNESSMAP - varying vec2 vClearcoatRoughnessMapUv; -#endif -#ifdef USE_IRIDESCENCEMAP - varying vec2 vIridescenceMapUv; -#endif -#ifdef USE_IRIDESCENCE_THICKNESSMAP - varying vec2 vIridescenceThicknessMapUv; -#endif -#ifdef USE_SHEEN_COLORMAP - varying vec2 vSheenColorMapUv; -#endif -#ifdef USE_SHEEN_ROUGHNESSMAP - varying vec2 vSheenRoughnessMapUv; -#endif -#ifdef USE_SPECULARMAP - varying vec2 vSpecularMapUv; -#endif -#ifdef USE_SPECULAR_COLORMAP - varying vec2 vSpecularColorMapUv; -#endif -#ifdef USE_SPECULAR_INTENSITYMAP - varying vec2 vSpecularIntensityMapUv; -#endif -#ifdef USE_TRANSMISSIONMAP - uniform mat3 transmissionMapTransform; - varying vec2 vTransmissionMapUv; -#endif -#ifdef USE_THICKNESSMAP - uniform mat3 thicknessMapTransform; - varying vec2 vThicknessMapUv; -#endif`,HS=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) - varying vec2 vUv; -#endif -#ifdef USE_MAP - uniform mat3 mapTransform; - varying vec2 vMapUv; -#endif -#ifdef USE_ALPHAMAP - uniform mat3 alphaMapTransform; - varying vec2 vAlphaMapUv; -#endif -#ifdef USE_LIGHTMAP - uniform mat3 lightMapTransform; - varying vec2 vLightMapUv; -#endif -#ifdef USE_AOMAP - uniform mat3 aoMapTransform; - varying vec2 vAoMapUv; -#endif -#ifdef USE_BUMPMAP - uniform mat3 bumpMapTransform; - varying vec2 vBumpMapUv; -#endif -#ifdef USE_NORMALMAP - uniform mat3 normalMapTransform; - varying vec2 vNormalMapUv; -#endif -#ifdef USE_DISPLACEMENTMAP - uniform mat3 displacementMapTransform; - varying vec2 vDisplacementMapUv; -#endif -#ifdef USE_EMISSIVEMAP - uniform mat3 emissiveMapTransform; - varying vec2 vEmissiveMapUv; -#endif -#ifdef USE_METALNESSMAP - uniform mat3 metalnessMapTransform; - varying vec2 vMetalnessMapUv; -#endif -#ifdef USE_ROUGHNESSMAP - uniform mat3 roughnessMapTransform; - varying vec2 vRoughnessMapUv; -#endif -#ifdef USE_ANISOTROPYMAP - uniform mat3 anisotropyMapTransform; - varying vec2 vAnisotropyMapUv; -#endif -#ifdef USE_CLEARCOATMAP - uniform mat3 clearcoatMapTransform; - varying vec2 vClearcoatMapUv; -#endif -#ifdef USE_CLEARCOAT_NORMALMAP - uniform mat3 clearcoatNormalMapTransform; - varying vec2 vClearcoatNormalMapUv; -#endif -#ifdef USE_CLEARCOAT_ROUGHNESSMAP - uniform mat3 clearcoatRoughnessMapTransform; - varying vec2 vClearcoatRoughnessMapUv; -#endif -#ifdef USE_SHEEN_COLORMAP - uniform mat3 sheenColorMapTransform; - varying vec2 vSheenColorMapUv; -#endif -#ifdef USE_SHEEN_ROUGHNESSMAP - uniform mat3 sheenRoughnessMapTransform; - varying vec2 vSheenRoughnessMapUv; -#endif -#ifdef USE_IRIDESCENCEMAP - uniform mat3 iridescenceMapTransform; - varying vec2 vIridescenceMapUv; -#endif -#ifdef USE_IRIDESCENCE_THICKNESSMAP - uniform mat3 iridescenceThicknessMapTransform; - varying vec2 vIridescenceThicknessMapUv; -#endif -#ifdef USE_SPECULARMAP - uniform mat3 specularMapTransform; - varying vec2 vSpecularMapUv; -#endif -#ifdef USE_SPECULAR_COLORMAP - uniform mat3 specularColorMapTransform; - varying vec2 vSpecularColorMapUv; -#endif -#ifdef USE_SPECULAR_INTENSITYMAP - uniform mat3 specularIntensityMapTransform; - varying vec2 vSpecularIntensityMapUv; -#endif -#ifdef USE_TRANSMISSIONMAP - uniform mat3 transmissionMapTransform; - varying vec2 vTransmissionMapUv; -#endif -#ifdef USE_THICKNESSMAP - uniform mat3 thicknessMapTransform; - varying vec2 vThicknessMapUv; -#endif`,GS=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) - vUv = vec3( uv, 1 ).xy; -#endif -#ifdef USE_MAP - vMapUv = ( mapTransform * vec3( MAP_UV, 1 ) ).xy; -#endif -#ifdef USE_ALPHAMAP - vAlphaMapUv = ( alphaMapTransform * vec3( ALPHAMAP_UV, 1 ) ).xy; -#endif -#ifdef USE_LIGHTMAP - vLightMapUv = ( lightMapTransform * vec3( LIGHTMAP_UV, 1 ) ).xy; -#endif -#ifdef USE_AOMAP - vAoMapUv = ( aoMapTransform * vec3( AOMAP_UV, 1 ) ).xy; -#endif -#ifdef USE_BUMPMAP - vBumpMapUv = ( bumpMapTransform * vec3( BUMPMAP_UV, 1 ) ).xy; -#endif -#ifdef USE_NORMALMAP - vNormalMapUv = ( normalMapTransform * vec3( NORMALMAP_UV, 1 ) ).xy; -#endif -#ifdef USE_DISPLACEMENTMAP - vDisplacementMapUv = ( displacementMapTransform * vec3( DISPLACEMENTMAP_UV, 1 ) ).xy; -#endif -#ifdef USE_EMISSIVEMAP - vEmissiveMapUv = ( emissiveMapTransform * vec3( EMISSIVEMAP_UV, 1 ) ).xy; -#endif -#ifdef USE_METALNESSMAP - vMetalnessMapUv = ( metalnessMapTransform * vec3( METALNESSMAP_UV, 1 ) ).xy; -#endif -#ifdef USE_ROUGHNESSMAP - vRoughnessMapUv = ( roughnessMapTransform * vec3( ROUGHNESSMAP_UV, 1 ) ).xy; -#endif -#ifdef USE_ANISOTROPYMAP - vAnisotropyMapUv = ( anisotropyMapTransform * vec3( ANISOTROPYMAP_UV, 1 ) ).xy; -#endif -#ifdef USE_CLEARCOATMAP - vClearcoatMapUv = ( clearcoatMapTransform * vec3( CLEARCOATMAP_UV, 1 ) ).xy; -#endif -#ifdef USE_CLEARCOAT_NORMALMAP - vClearcoatNormalMapUv = ( clearcoatNormalMapTransform * vec3( CLEARCOAT_NORMALMAP_UV, 1 ) ).xy; -#endif -#ifdef USE_CLEARCOAT_ROUGHNESSMAP - vClearcoatRoughnessMapUv = ( clearcoatRoughnessMapTransform * vec3( CLEARCOAT_ROUGHNESSMAP_UV, 1 ) ).xy; -#endif -#ifdef USE_IRIDESCENCEMAP - vIridescenceMapUv = ( iridescenceMapTransform * vec3( IRIDESCENCEMAP_UV, 1 ) ).xy; -#endif -#ifdef USE_IRIDESCENCE_THICKNESSMAP - vIridescenceThicknessMapUv = ( iridescenceThicknessMapTransform * vec3( IRIDESCENCE_THICKNESSMAP_UV, 1 ) ).xy; -#endif -#ifdef USE_SHEEN_COLORMAP - vSheenColorMapUv = ( sheenColorMapTransform * vec3( SHEEN_COLORMAP_UV, 1 ) ).xy; -#endif -#ifdef USE_SHEEN_ROUGHNESSMAP - vSheenRoughnessMapUv = ( sheenRoughnessMapTransform * vec3( SHEEN_ROUGHNESSMAP_UV, 1 ) ).xy; -#endif -#ifdef USE_SPECULARMAP - vSpecularMapUv = ( specularMapTransform * vec3( SPECULARMAP_UV, 1 ) ).xy; -#endif -#ifdef USE_SPECULAR_COLORMAP - vSpecularColorMapUv = ( specularColorMapTransform * vec3( SPECULAR_COLORMAP_UV, 1 ) ).xy; -#endif -#ifdef USE_SPECULAR_INTENSITYMAP - vSpecularIntensityMapUv = ( specularIntensityMapTransform * vec3( SPECULAR_INTENSITYMAP_UV, 1 ) ).xy; -#endif -#ifdef USE_TRANSMISSIONMAP - vTransmissionMapUv = ( transmissionMapTransform * vec3( TRANSMISSIONMAP_UV, 1 ) ).xy; -#endif -#ifdef USE_THICKNESSMAP - vThicknessMapUv = ( thicknessMapTransform * vec3( THICKNESSMAP_UV, 1 ) ).xy; -#endif`,WS=`#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0 - vec4 worldPosition = vec4( transformed, 1.0 ); - #ifdef USE_BATCHING - worldPosition = batchingMatrix * worldPosition; - #endif - #ifdef USE_INSTANCING - worldPosition = instanceMatrix * worldPosition; - #endif - worldPosition = modelMatrix * worldPosition; -#endif`;const $S=`varying vec2 vUv; -uniform mat3 uvTransform; -void main() { - vUv = ( uvTransform * vec3( uv, 1 ) ).xy; - gl_Position = vec4( position.xy, 1.0, 1.0 ); -}`,XS=`uniform sampler2D t2D; -uniform float backgroundIntensity; -varying vec2 vUv; -void main() { - vec4 texColor = texture2D( t2D, vUv ); - #ifdef DECODE_VIDEO_TEXTURE - texColor = vec4( mix( pow( texColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), texColor.rgb * 0.0773993808, vec3( lessThanEqual( texColor.rgb, vec3( 0.04045 ) ) ) ), texColor.w ); - #endif - texColor.rgb *= backgroundIntensity; - gl_FragColor = texColor; - #include - #include -}`,qS=`varying vec3 vWorldDirection; -#include -void main() { - vWorldDirection = transformDirection( position, modelMatrix ); - #include - #include - gl_Position.z = gl_Position.w; -}`,YS=`#ifdef ENVMAP_TYPE_CUBE - uniform samplerCube envMap; -#elif defined( ENVMAP_TYPE_CUBE_UV ) - uniform sampler2D envMap; -#endif -uniform float flipEnvMap; -uniform float backgroundBlurriness; -uniform float backgroundIntensity; -uniform mat3 backgroundRotation; -varying vec3 vWorldDirection; -#include -void main() { - #ifdef ENVMAP_TYPE_CUBE - vec4 texColor = textureCube( envMap, backgroundRotation * vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) ); - #elif defined( ENVMAP_TYPE_CUBE_UV ) - vec4 texColor = textureCubeUV( envMap, backgroundRotation * vWorldDirection, backgroundBlurriness ); - #else - vec4 texColor = vec4( 0.0, 0.0, 0.0, 1.0 ); - #endif - texColor.rgb *= backgroundIntensity; - gl_FragColor = texColor; - #include - #include -}`,ZS=`varying vec3 vWorldDirection; -#include -void main() { - vWorldDirection = transformDirection( position, modelMatrix ); - #include - #include - gl_Position.z = gl_Position.w; -}`,JS=`uniform samplerCube tCube; -uniform float tFlip; -uniform float opacity; -varying vec3 vWorldDirection; -void main() { - vec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) ); - gl_FragColor = texColor; - gl_FragColor.a *= opacity; - #include - #include -}`,KS=`#include -#include -#include -#include -#include -#include -#include -#include -varying vec2 vHighPrecisionZW; -void main() { - #include - #include - #include - #include - #ifdef USE_DISPLACEMENTMAP - #include - #include - #include - #endif - #include - #include - #include - #include - #include - #include - #include - vHighPrecisionZW = gl_Position.zw; -}`,jS=`#if DEPTH_PACKING == 3200 - uniform float opacity; -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -varying vec2 vHighPrecisionZW; -void main() { - vec4 diffuseColor = vec4( 1.0 ); - #include - #if DEPTH_PACKING == 3200 - diffuseColor.a = opacity; - #endif - #include - #include - #include - #include - #include - float fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5; - #if DEPTH_PACKING == 3200 - gl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity ); - #elif DEPTH_PACKING == 3201 - gl_FragColor = packDepthToRGBA( fragCoordZ ); - #endif -}`,QS=`#define DISTANCE -varying vec3 vWorldPosition; -#include -#include -#include -#include -#include -#include -#include -void main() { - #include - #include - #include - #include - #ifdef USE_DISPLACEMENTMAP - #include - #include - #include - #endif - #include - #include - #include - #include - #include - #include - #include - vWorldPosition = worldPosition.xyz; -}`,ew=`#define DISTANCE -uniform vec3 referencePosition; -uniform float nearDistance; -uniform float farDistance; -varying vec3 vWorldPosition; -#include -#include -#include -#include -#include -#include -#include -#include -void main () { - vec4 diffuseColor = vec4( 1.0 ); - #include - #include - #include - #include - #include - float dist = length( vWorldPosition - referencePosition ); - dist = ( dist - nearDistance ) / ( farDistance - nearDistance ); - dist = saturate( dist ); - gl_FragColor = packDepthToRGBA( dist ); -}`,tw=`varying vec3 vWorldDirection; -#include -void main() { - vWorldDirection = transformDirection( position, modelMatrix ); - #include - #include -}`,nw=`uniform sampler2D tEquirect; -varying vec3 vWorldDirection; -#include -void main() { - vec3 direction = normalize( vWorldDirection ); - vec2 sampleUV = equirectUv( direction ); - gl_FragColor = texture2D( tEquirect, sampleUV ); - #include - #include -}`,iw=`uniform float scale; -attribute float lineDistance; -varying float vLineDistance; -#include -#include -#include -#include -#include -#include -#include -void main() { - vLineDistance = scale * lineDistance; - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include -}`,sw=`uniform vec3 diffuse; -uniform float opacity; -uniform float dashSize; -uniform float totalSize; -varying float vLineDistance; -#include -#include -#include -#include -#include -#include -#include -void main() { - vec4 diffuseColor = vec4( diffuse, opacity ); - #include - if ( mod( vLineDistance, totalSize ) > dashSize ) { - discard; - } - vec3 outgoingLight = vec3( 0.0 ); - #include - #include - #include - outgoingLight = diffuseColor.rgb; - #include - #include - #include - #include - #include -}`,rw=`#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -void main() { - #include - #include - #include - #include - #include - #if defined ( USE_ENVMAP ) || defined ( USE_SKINNING ) - #include - #include - #include - #include - #include - #endif - #include - #include - #include - #include - #include - #include - #include - #include - #include -}`,ow=`uniform vec3 diffuse; -uniform float opacity; -#ifndef FLAT_SHADED - varying vec3 vNormal; -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -void main() { - vec4 diffuseColor = vec4( diffuse, opacity ); - #include - #include - #include - #include - #include - #include - #include - #include - ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); - #ifdef USE_LIGHTMAP - vec4 lightMapTexel = texture2D( lightMap, vLightMapUv ); - reflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI; - #else - reflectedLight.indirectDiffuse += vec3( 1.0 ); - #endif - #include - reflectedLight.indirectDiffuse *= diffuseColor.rgb; - vec3 outgoingLight = reflectedLight.indirectDiffuse; - #include - #include - #include - #include - #include - #include - #include -}`,aw=`#define LAMBERT -varying vec3 vViewPosition; -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -void main() { - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - vViewPosition = - mvPosition.xyz; - #include - #include - #include - #include -}`,lw=`#define LAMBERT -uniform vec3 diffuse; -uniform vec3 emissive; -uniform float opacity; -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -void main() { - vec4 diffuseColor = vec4( diffuse, opacity ); - #include - ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); - vec3 totalEmissiveRadiance = emissive; - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance; - #include - #include - #include - #include - #include - #include - #include -}`,cw=`#define MATCAP -varying vec3 vViewPosition; -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -void main() { - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - vViewPosition = - mvPosition.xyz; -}`,uw=`#define MATCAP -uniform vec3 diffuse; -uniform float opacity; -uniform sampler2D matcap; -varying vec3 vViewPosition; -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -void main() { - vec4 diffuseColor = vec4( diffuse, opacity ); - #include - #include - #include - #include - #include - #include - #include - #include - #include - vec3 viewDir = normalize( vViewPosition ); - vec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) ); - vec3 y = cross( viewDir, x ); - vec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5; - #ifdef USE_MATCAP - vec4 matcapColor = texture2D( matcap, uv ); - #else - vec4 matcapColor = vec4( vec3( mix( 0.2, 0.8, uv.y ) ), 1.0 ); - #endif - vec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb; - #include - #include - #include - #include - #include - #include -}`,hw=`#define NORMAL -#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE ) - varying vec3 vViewPosition; -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -void main() { - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include -#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE ) - vViewPosition = - mvPosition.xyz; -#endif -}`,dw=`#define NORMAL -uniform float opacity; -#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE ) - varying vec3 vViewPosition; -#endif -#include -#include -#include -#include -#include -#include -#include -void main() { - vec4 diffuseColor = vec4( 0.0, 0.0, 0.0, opacity ); - #include - #include - #include - #include - gl_FragColor = vec4( packNormalToRGB( normal ), diffuseColor.a ); - #ifdef OPAQUE - gl_FragColor.a = 1.0; - #endif -}`,fw=`#define PHONG -varying vec3 vViewPosition; -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -void main() { - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - vViewPosition = - mvPosition.xyz; - #include - #include - #include - #include -}`,pw=`#define PHONG -uniform vec3 diffuse; -uniform vec3 emissive; -uniform vec3 specular; -uniform float shininess; -uniform float opacity; -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -void main() { - vec4 diffuseColor = vec4( diffuse, opacity ); - #include - ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); - vec3 totalEmissiveRadiance = emissive; - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance; - #include - #include - #include - #include - #include - #include - #include -}`,mw=`#define STANDARD -varying vec3 vViewPosition; -#ifdef USE_TRANSMISSION - varying vec3 vWorldPosition; -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -void main() { - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - vViewPosition = - mvPosition.xyz; - #include - #include - #include -#ifdef USE_TRANSMISSION - vWorldPosition = worldPosition.xyz; -#endif -}`,gw=`#define STANDARD -#ifdef PHYSICAL - #define IOR - #define USE_SPECULAR -#endif -uniform vec3 diffuse; -uniform vec3 emissive; -uniform float roughness; -uniform float metalness; -uniform float opacity; -#ifdef IOR - uniform float ior; -#endif -#ifdef USE_SPECULAR - uniform float specularIntensity; - uniform vec3 specularColor; - #ifdef USE_SPECULAR_COLORMAP - uniform sampler2D specularColorMap; - #endif - #ifdef USE_SPECULAR_INTENSITYMAP - uniform sampler2D specularIntensityMap; - #endif -#endif -#ifdef USE_CLEARCOAT - uniform float clearcoat; - uniform float clearcoatRoughness; -#endif -#ifdef USE_DISPERSION - uniform float dispersion; -#endif -#ifdef USE_IRIDESCENCE - uniform float iridescence; - uniform float iridescenceIOR; - uniform float iridescenceThicknessMinimum; - uniform float iridescenceThicknessMaximum; -#endif -#ifdef USE_SHEEN - uniform vec3 sheenColor; - uniform float sheenRoughness; - #ifdef USE_SHEEN_COLORMAP - uniform sampler2D sheenColorMap; - #endif - #ifdef USE_SHEEN_ROUGHNESSMAP - uniform sampler2D sheenRoughnessMap; - #endif -#endif -#ifdef USE_ANISOTROPY - uniform vec2 anisotropyVector; - #ifdef USE_ANISOTROPYMAP - uniform sampler2D anisotropyMap; - #endif -#endif -varying vec3 vViewPosition; -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -void main() { - vec4 diffuseColor = vec4( diffuse, opacity ); - #include - ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); - vec3 totalEmissiveRadiance = emissive; - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - vec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse; - vec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular; - #include - vec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance; - #ifdef USE_SHEEN - float sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor ); - outgoingLight = outgoingLight * sheenEnergyComp + sheenSpecularDirect + sheenSpecularIndirect; - #endif - #ifdef USE_CLEARCOAT - float dotNVcc = saturate( dot( geometryClearcoatNormal, geometryViewDir ) ); - vec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc ); - outgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + ( clearcoatSpecularDirect + clearcoatSpecularIndirect ) * material.clearcoat; - #endif - #include - #include - #include - #include - #include - #include -}`,vw=`#define TOON -varying vec3 vViewPosition; -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -void main() { - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - vViewPosition = - mvPosition.xyz; - #include - #include - #include -}`,_w=`#define TOON -uniform vec3 diffuse; -uniform vec3 emissive; -uniform float opacity; -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -void main() { - vec4 diffuseColor = vec4( diffuse, opacity ); - #include - ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); - vec3 totalEmissiveRadiance = emissive; - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance; - #include - #include - #include - #include - #include - #include -}`,yw=`uniform float size; -uniform float scale; -#include -#include -#include -#include -#include -#include -#ifdef USE_POINTS_UV - varying vec2 vUv; - uniform mat3 uvTransform; -#endif -void main() { - #ifdef USE_POINTS_UV - vUv = ( uvTransform * vec3( uv, 1 ) ).xy; - #endif - #include - #include - #include - #include - #include - #include - gl_PointSize = size; - #ifdef USE_SIZEATTENUATION - bool isPerspective = isPerspectiveMatrix( projectionMatrix ); - if ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z ); - #endif - #include - #include - #include - #include -}`,xw=`uniform vec3 diffuse; -uniform float opacity; -#include -#include -#include -#include -#include -#include -#include -#include -void main() { - vec4 diffuseColor = vec4( diffuse, opacity ); - #include - vec3 outgoingLight = vec3( 0.0 ); - #include - #include - #include - #include - #include - outgoingLight = diffuseColor.rgb; - #include - #include - #include - #include - #include -}`,Mw=`#include -#include -#include -#include -#include -#include -#include -void main() { - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include -}`,bw=`uniform vec3 color; -uniform float opacity; -#include -#include -#include -#include -#include -#include -#include -#include -void main() { - #include - gl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) ); - #include - #include - #include -}`,Sw=`uniform float rotation; -uniform vec2 center; -#include -#include -#include -#include -#include -void main() { - #include - vec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 ); - vec2 scale; - scale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) ); - scale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) ); - #ifndef USE_SIZEATTENUATION - bool isPerspective = isPerspectiveMatrix( projectionMatrix ); - if ( isPerspective ) scale *= - mvPosition.z; - #endif - vec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale; - vec2 rotatedPosition; - rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y; - rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y; - mvPosition.xy += rotatedPosition; - gl_Position = projectionMatrix * mvPosition; - #include - #include - #include -}`,ww=`uniform vec3 diffuse; -uniform float opacity; -#include -#include -#include -#include -#include -#include -#include -#include -#include -void main() { - vec4 diffuseColor = vec4( diffuse, opacity ); - #include - vec3 outgoingLight = vec3( 0.0 ); - #include - #include - #include - #include - #include - outgoingLight = diffuseColor.rgb; - #include - #include - #include - #include -}`,nt={alphahash_fragment:XM,alphahash_pars_fragment:qM,alphamap_fragment:YM,alphamap_pars_fragment:ZM,alphatest_fragment:JM,alphatest_pars_fragment:KM,aomap_fragment:jM,aomap_pars_fragment:QM,batching_pars_vertex:eb,batching_vertex:tb,begin_vertex:nb,beginnormal_vertex:ib,bsdfs:sb,iridescence_fragment:rb,bumpmap_pars_fragment:ob,clipping_planes_fragment:ab,clipping_planes_pars_fragment:lb,clipping_planes_pars_vertex:cb,clipping_planes_vertex:ub,color_fragment:hb,color_pars_fragment:db,color_pars_vertex:fb,color_vertex:pb,common:mb,cube_uv_reflection_fragment:gb,defaultnormal_vertex:vb,displacementmap_pars_vertex:_b,displacementmap_vertex:yb,emissivemap_fragment:xb,emissivemap_pars_fragment:Mb,colorspace_fragment:bb,colorspace_pars_fragment:Sb,envmap_fragment:wb,envmap_common_pars_fragment:Ab,envmap_pars_fragment:Tb,envmap_pars_vertex:Eb,envmap_physical_pars_fragment:kb,envmap_vertex:Cb,fog_vertex:Pb,fog_pars_vertex:Rb,fog_fragment:Ib,fog_pars_fragment:Lb,gradientmap_pars_fragment:Nb,lightmap_pars_fragment:Db,lights_lambert_fragment:Ub,lights_lambert_pars_fragment:Ob,lights_pars_begin:Fb,lights_toon_fragment:Bb,lights_toon_pars_fragment:zb,lights_phong_fragment:Vb,lights_phong_pars_fragment:Hb,lights_physical_fragment:Gb,lights_physical_pars_fragment:Wb,lights_fragment_begin:$b,lights_fragment_maps:Xb,lights_fragment_end:qb,logdepthbuf_fragment:Yb,logdepthbuf_pars_fragment:Zb,logdepthbuf_pars_vertex:Jb,logdepthbuf_vertex:Kb,map_fragment:jb,map_pars_fragment:Qb,map_particle_fragment:eS,map_particle_pars_fragment:tS,metalnessmap_fragment:nS,metalnessmap_pars_fragment:iS,morphinstance_vertex:sS,morphcolor_vertex:rS,morphnormal_vertex:oS,morphtarget_pars_vertex:aS,morphtarget_vertex:lS,normal_fragment_begin:cS,normal_fragment_maps:uS,normal_pars_fragment:hS,normal_pars_vertex:dS,normal_vertex:fS,normalmap_pars_fragment:pS,clearcoat_normal_fragment_begin:mS,clearcoat_normal_fragment_maps:gS,clearcoat_pars_fragment:vS,iridescence_pars_fragment:_S,opaque_fragment:yS,packing:xS,premultiplied_alpha_fragment:MS,project_vertex:bS,dithering_fragment:SS,dithering_pars_fragment:wS,roughnessmap_fragment:AS,roughnessmap_pars_fragment:TS,shadowmap_pars_fragment:ES,shadowmap_pars_vertex:CS,shadowmap_vertex:PS,shadowmask_pars_fragment:RS,skinbase_vertex:IS,skinning_pars_vertex:LS,skinning_vertex:NS,skinnormal_vertex:DS,specularmap_fragment:US,specularmap_pars_fragment:OS,tonemapping_fragment:FS,tonemapping_pars_fragment:kS,transmission_fragment:BS,transmission_pars_fragment:zS,uv_pars_fragment:VS,uv_pars_vertex:HS,uv_vertex:GS,worldpos_vertex:WS,background_vert:$S,background_frag:XS,backgroundCube_vert:qS,backgroundCube_frag:YS,cube_vert:ZS,cube_frag:JS,depth_vert:KS,depth_frag:jS,distanceRGBA_vert:QS,distanceRGBA_frag:ew,equirect_vert:tw,equirect_frag:nw,linedashed_vert:iw,linedashed_frag:sw,meshbasic_vert:rw,meshbasic_frag:ow,meshlambert_vert:aw,meshlambert_frag:lw,meshmatcap_vert:cw,meshmatcap_frag:uw,meshnormal_vert:hw,meshnormal_frag:dw,meshphong_vert:fw,meshphong_frag:pw,meshphysical_vert:mw,meshphysical_frag:gw,meshtoon_vert:vw,meshtoon_frag:_w,points_vert:yw,points_frag:xw,shadow_vert:Mw,shadow_frag:bw,sprite_vert:Sw,sprite_frag:ww},Ce={common:{diffuse:{value:new Pe(16777215)},opacity:{value:1},map:{value:null},mapTransform:{value:new Ze},alphaMap:{value:null},alphaMapTransform:{value:new Ze},alphaTest:{value:0}},specularmap:{specularMap:{value:null},specularMapTransform:{value:new Ze}},envmap:{envMap:{value:null},envMapRotation:{value:new Ze},flipEnvMap:{value:-1},reflectivity:{value:1},ior:{value:1.5},refractionRatio:{value:.98}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1},aoMapTransform:{value:new Ze}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1},lightMapTransform:{value:new Ze}},bumpmap:{bumpMap:{value:null},bumpMapTransform:{value:new Ze},bumpScale:{value:1}},normalmap:{normalMap:{value:null},normalMapTransform:{value:new Ze},normalScale:{value:new se(1,1)}},displacementmap:{displacementMap:{value:null},displacementMapTransform:{value:new Ze},displacementScale:{value:1},displacementBias:{value:0}},emissivemap:{emissiveMap:{value:null},emissiveMapTransform:{value:new Ze}},metalnessmap:{metalnessMap:{value:null},metalnessMapTransform:{value:new Ze}},roughnessmap:{roughnessMap:{value:null},roughnessMapTransform:{value:new Ze}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:25e-5},fogNear:{value:1},fogFar:{value:2e3},fogColor:{value:new Pe(16777215)}},lights:{ambientLightColor:{value:[]},lightProbe:{value:[]},directionalLights:{value:[],properties:{direction:{},color:{}}},directionalLightShadows:{value:[],properties:{shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},directionalShadowMap:{value:[]},directionalShadowMatrix:{value:[]},spotLights:{value:[],properties:{color:{},position:{},direction:{},distance:{},coneCos:{},penumbraCos:{},decay:{}}},spotLightShadows:{value:[],properties:{shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},spotLightMap:{value:[]},spotShadowMap:{value:[]},spotLightMatrix:{value:[]},pointLights:{value:[],properties:{color:{},position:{},decay:{},distance:{}}},pointLightShadows:{value:[],properties:{shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{},shadowCameraNear:{},shadowCameraFar:{}}},pointShadowMap:{value:[]},pointShadowMatrix:{value:[]},hemisphereLights:{value:[],properties:{direction:{},skyColor:{},groundColor:{}}},rectAreaLights:{value:[],properties:{color:{},position:{},width:{},height:{}}},ltc_1:{value:null},ltc_2:{value:null}},points:{diffuse:{value:new Pe(16777215)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},alphaMap:{value:null},alphaMapTransform:{value:new Ze},alphaTest:{value:0},uvTransform:{value:new Ze}},sprite:{diffuse:{value:new Pe(16777215)},opacity:{value:1},center:{value:new se(.5,.5)},rotation:{value:0},map:{value:null},mapTransform:{value:new Ze},alphaMap:{value:null},alphaMapTransform:{value:new Ze},alphaTest:{value:0}}},Tn={basic:{uniforms:en([Ce.common,Ce.specularmap,Ce.envmap,Ce.aomap,Ce.lightmap,Ce.fog]),vertexShader:nt.meshbasic_vert,fragmentShader:nt.meshbasic_frag},lambert:{uniforms:en([Ce.common,Ce.specularmap,Ce.envmap,Ce.aomap,Ce.lightmap,Ce.emissivemap,Ce.bumpmap,Ce.normalmap,Ce.displacementmap,Ce.fog,Ce.lights,{emissive:{value:new Pe(0)}}]),vertexShader:nt.meshlambert_vert,fragmentShader:nt.meshlambert_frag},phong:{uniforms:en([Ce.common,Ce.specularmap,Ce.envmap,Ce.aomap,Ce.lightmap,Ce.emissivemap,Ce.bumpmap,Ce.normalmap,Ce.displacementmap,Ce.fog,Ce.lights,{emissive:{value:new Pe(0)},specular:{value:new Pe(1118481)},shininess:{value:30}}]),vertexShader:nt.meshphong_vert,fragmentShader:nt.meshphong_frag},standard:{uniforms:en([Ce.common,Ce.envmap,Ce.aomap,Ce.lightmap,Ce.emissivemap,Ce.bumpmap,Ce.normalmap,Ce.displacementmap,Ce.roughnessmap,Ce.metalnessmap,Ce.fog,Ce.lights,{emissive:{value:new Pe(0)},roughness:{value:1},metalness:{value:0},envMapIntensity:{value:1}}]),vertexShader:nt.meshphysical_vert,fragmentShader:nt.meshphysical_frag},toon:{uniforms:en([Ce.common,Ce.aomap,Ce.lightmap,Ce.emissivemap,Ce.bumpmap,Ce.normalmap,Ce.displacementmap,Ce.gradientmap,Ce.fog,Ce.lights,{emissive:{value:new Pe(0)}}]),vertexShader:nt.meshtoon_vert,fragmentShader:nt.meshtoon_frag},matcap:{uniforms:en([Ce.common,Ce.bumpmap,Ce.normalmap,Ce.displacementmap,Ce.fog,{matcap:{value:null}}]),vertexShader:nt.meshmatcap_vert,fragmentShader:nt.meshmatcap_frag},points:{uniforms:en([Ce.points,Ce.fog]),vertexShader:nt.points_vert,fragmentShader:nt.points_frag},dashed:{uniforms:en([Ce.common,Ce.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:nt.linedashed_vert,fragmentShader:nt.linedashed_frag},depth:{uniforms:en([Ce.common,Ce.displacementmap]),vertexShader:nt.depth_vert,fragmentShader:nt.depth_frag},normal:{uniforms:en([Ce.common,Ce.bumpmap,Ce.normalmap,Ce.displacementmap,{opacity:{value:1}}]),vertexShader:nt.meshnormal_vert,fragmentShader:nt.meshnormal_frag},sprite:{uniforms:en([Ce.sprite,Ce.fog]),vertexShader:nt.sprite_vert,fragmentShader:nt.sprite_frag},background:{uniforms:{uvTransform:{value:new Ze},t2D:{value:null},backgroundIntensity:{value:1}},vertexShader:nt.background_vert,fragmentShader:nt.background_frag},backgroundCube:{uniforms:{envMap:{value:null},flipEnvMap:{value:-1},backgroundBlurriness:{value:0},backgroundIntensity:{value:1},backgroundRotation:{value:new Ze}},vertexShader:nt.backgroundCube_vert,fragmentShader:nt.backgroundCube_frag},cube:{uniforms:{tCube:{value:null},tFlip:{value:-1},opacity:{value:1}},vertexShader:nt.cube_vert,fragmentShader:nt.cube_frag},equirect:{uniforms:{tEquirect:{value:null}},vertexShader:nt.equirect_vert,fragmentShader:nt.equirect_frag},distanceRGBA:{uniforms:en([Ce.common,Ce.displacementmap,{referencePosition:{value:new N},nearDistance:{value:1},farDistance:{value:1e3}}]),vertexShader:nt.distanceRGBA_vert,fragmentShader:nt.distanceRGBA_frag},shadow:{uniforms:en([Ce.lights,Ce.fog,{color:{value:new Pe(0)},opacity:{value:1}}]),vertexShader:nt.shadow_vert,fragmentShader:nt.shadow_frag}};Tn.physical={uniforms:en([Tn.standard.uniforms,{clearcoat:{value:0},clearcoatMap:{value:null},clearcoatMapTransform:{value:new Ze},clearcoatNormalMap:{value:null},clearcoatNormalMapTransform:{value:new Ze},clearcoatNormalScale:{value:new se(1,1)},clearcoatRoughness:{value:0},clearcoatRoughnessMap:{value:null},clearcoatRoughnessMapTransform:{value:new Ze},dispersion:{value:0},iridescence:{value:0},iridescenceMap:{value:null},iridescenceMapTransform:{value:new Ze},iridescenceIOR:{value:1.3},iridescenceThicknessMinimum:{value:100},iridescenceThicknessMaximum:{value:400},iridescenceThicknessMap:{value:null},iridescenceThicknessMapTransform:{value:new Ze},sheen:{value:0},sheenColor:{value:new Pe(0)},sheenColorMap:{value:null},sheenColorMapTransform:{value:new Ze},sheenRoughness:{value:1},sheenRoughnessMap:{value:null},sheenRoughnessMapTransform:{value:new Ze},transmission:{value:0},transmissionMap:{value:null},transmissionMapTransform:{value:new Ze},transmissionSamplerSize:{value:new se},transmissionSamplerMap:{value:null},thickness:{value:0},thicknessMap:{value:null},thicknessMapTransform:{value:new Ze},attenuationDistance:{value:0},attenuationColor:{value:new Pe(0)},specularColor:{value:new Pe(1,1,1)},specularColorMap:{value:null},specularColorMapTransform:{value:new Ze},specularIntensity:{value:1},specularIntensityMap:{value:null},specularIntensityMapTransform:{value:new Ze},anisotropyVector:{value:new se},anisotropyMap:{value:null},anisotropyMapTransform:{value:new Ze}}]),vertexShader:nt.meshphysical_vert,fragmentShader:nt.meshphysical_frag};const To={r:0,b:0,g:0},Bi=new _n,Aw=new qe;function Tw(s,e,t,n,i,r,o){const a=new Pe(0);let l=r===!0?0:1,c,u,h=null,d=0,f=null;function g(y){let _=y.isScene===!0?y.background:null;return _&&_.isTexture&&(_=(y.backgroundBlurriness>0?t:e).get(_)),_}function v(y){let _=!1;const x=g(y);x===null?m(a,l):x&&x.isColor&&(m(x,1),_=!0);const A=s.xr.getEnvironmentBlendMode();A==="additive"?n.buffers.color.setClear(0,0,0,1,o):A==="alpha-blend"&&n.buffers.color.setClear(0,0,0,0,o),(s.autoClear||_)&&(n.buffers.depth.setTest(!0),n.buffers.depth.setMask(!0),n.buffers.color.setMask(!0),s.clear(s.autoClearColor,s.autoClearDepth,s.autoClearStencil))}function p(y,_){const x=g(_);x&&(x.isCubeTexture||x.mapping===Ws)?(u===void 0&&(u=new Nt(new cs(1,1,1),new Ln({name:"BackgroundCubeMaterial",uniforms:Hs(Tn.backgroundCube.uniforms),vertexShader:Tn.backgroundCube.vertexShader,fragmentShader:Tn.backgroundCube.fragmentShader,side:nn,depthTest:!1,depthWrite:!1,fog:!1})),u.geometry.deleteAttribute("normal"),u.geometry.deleteAttribute("uv"),u.onBeforeRender=function(A,b,E){this.matrixWorld.copyPosition(E.matrixWorld)},Object.defineProperty(u.material,"envMap",{get:function(){return this.uniforms.envMap.value}}),i.update(u)),Bi.copy(_.backgroundRotation),Bi.x*=-1,Bi.y*=-1,Bi.z*=-1,x.isCubeTexture&&x.isRenderTargetTexture===!1&&(Bi.y*=-1,Bi.z*=-1),u.material.uniforms.envMap.value=x,u.material.uniforms.flipEnvMap.value=x.isCubeTexture&&x.isRenderTargetTexture===!1?-1:1,u.material.uniforms.backgroundBlurriness.value=_.backgroundBlurriness,u.material.uniforms.backgroundIntensity.value=_.backgroundIntensity,u.material.uniforms.backgroundRotation.value.setFromMatrix4(Aw.makeRotationFromEuler(Bi)),u.material.toneMapped=ht.getTransfer(x.colorSpace)!==Mt,(h!==x||d!==x.version||f!==s.toneMapping)&&(u.material.needsUpdate=!0,h=x,d=x.version,f=s.toneMapping),u.layers.enableAll(),y.unshift(u,u.geometry,u.material,0,0,null)):x&&x.isTexture&&(c===void 0&&(c=new Nt(new Xs(2,2),new Ln({name:"BackgroundMaterial",uniforms:Hs(Tn.background.uniforms),vertexShader:Tn.background.vertexShader,fragmentShader:Tn.background.fragmentShader,side:ri,depthTest:!1,depthWrite:!1,fog:!1})),c.geometry.deleteAttribute("normal"),Object.defineProperty(c.material,"map",{get:function(){return this.uniforms.t2D.value}}),i.update(c)),c.material.uniforms.t2D.value=x,c.material.uniforms.backgroundIntensity.value=_.backgroundIntensity,c.material.toneMapped=ht.getTransfer(x.colorSpace)!==Mt,x.matrixAutoUpdate===!0&&x.updateMatrix(),c.material.uniforms.uvTransform.value.copy(x.matrix),(h!==x||d!==x.version||f!==s.toneMapping)&&(c.material.needsUpdate=!0,h=x,d=x.version,f=s.toneMapping),c.layers.enableAll(),y.unshift(c,c.geometry,c.material,0,0,null))}function m(y,_){y.getRGB(To,xp(s)),n.buffers.color.setClear(To.r,To.g,To.b,_,o)}return{getClearColor:function(){return a},setClearColor:function(y,_=1){a.set(y),l=_,m(a,l)},getClearAlpha:function(){return l},setClearAlpha:function(y){l=y,m(a,l)},render:v,addToRenderList:p}}function Ew(s,e){const t=s.getParameter(s.MAX_VERTEX_ATTRIBS),n={},i=d(null);let r=i,o=!1;function a(M,F,V,G,q){let ae=!1;const j=h(G,V,F);r!==j&&(r=j,c(r.object)),ae=f(M,G,V,q),ae&&g(M,G,V,q),q!==null&&e.update(q,s.ELEMENT_ARRAY_BUFFER),(ae||o)&&(o=!1,x(M,F,V,G),q!==null&&s.bindBuffer(s.ELEMENT_ARRAY_BUFFER,e.get(q).buffer))}function l(){return s.createVertexArray()}function c(M){return s.bindVertexArray(M)}function u(M){return s.deleteVertexArray(M)}function h(M,F,V){const G=V.wireframe===!0;let q=n[M.id];q===void 0&&(q={},n[M.id]=q);let ae=q[F.id];ae===void 0&&(ae={},q[F.id]=ae);let j=ae[G];return j===void 0&&(j=d(l()),ae[G]=j),j}function d(M){const F=[],V=[],G=[];for(let q=0;q=0){const be=q[B];let Ae=ae[B];if(Ae===void 0&&(B==="instanceMatrix"&&M.instanceMatrix&&(Ae=M.instanceMatrix),B==="instanceColor"&&M.instanceColor&&(Ae=M.instanceColor)),be===void 0||be.attribute!==Ae||Ae&&be.data!==Ae.data)return!0;j++}return r.attributesNum!==j||r.index!==G}function g(M,F,V,G){const q={},ae=F.attributes;let j=0;const oe=V.getAttributes();for(const B in oe)if(oe[B].location>=0){let be=ae[B];be===void 0&&(B==="instanceMatrix"&&M.instanceMatrix&&(be=M.instanceMatrix),B==="instanceColor"&&M.instanceColor&&(be=M.instanceColor));const Ae={};Ae.attribute=be,be&&be.data&&(Ae.data=be.data),q[B]=Ae,j++}r.attributes=q,r.attributesNum=j,r.index=G}function v(){const M=r.newAttributes;for(let F=0,V=M.length;F=0){let Me=q[oe];if(Me===void 0&&(oe==="instanceMatrix"&&M.instanceMatrix&&(Me=M.instanceMatrix),oe==="instanceColor"&&M.instanceColor&&(Me=M.instanceColor)),Me!==void 0){const be=Me.normalized,Ae=Me.itemSize,ge=e.get(Me);if(ge===void 0)continue;const Be=ge.buffer,U=ge.type,D=ge.bytesPerElement,R=U===s.INT||U===s.UNSIGNED_INT||Me.gpuType===ou;if(Me.isInterleavedBufferAttribute){const T=Me.data,ie=T.stride,he=Me.offset;if(T.isInstancedInterleavedBuffer){for(let J=0;J0&&s.getShaderPrecisionFormat(s.FRAGMENT_SHADER,s.HIGH_FLOAT).precision>0)return"highp";b="mediump"}return b==="mediump"&&s.getShaderPrecisionFormat(s.VERTEX_SHADER,s.MEDIUM_FLOAT).precision>0&&s.getShaderPrecisionFormat(s.FRAGMENT_SHADER,s.MEDIUM_FLOAT).precision>0?"mediump":"lowp"}let c=t.precision!==void 0?t.precision:"highp";const u=l(c);u!==c&&(console.warn("THREE.WebGLRenderer:",c,"not supported, using",u,"instead."),c=u);const h=t.logarithmicDepthBuffer===!0,d=s.getParameter(s.MAX_TEXTURE_IMAGE_UNITS),f=s.getParameter(s.MAX_VERTEX_TEXTURE_IMAGE_UNITS),g=s.getParameter(s.MAX_TEXTURE_SIZE),v=s.getParameter(s.MAX_CUBE_MAP_TEXTURE_SIZE),p=s.getParameter(s.MAX_VERTEX_ATTRIBS),m=s.getParameter(s.MAX_VERTEX_UNIFORM_VECTORS),y=s.getParameter(s.MAX_VARYING_VECTORS),_=s.getParameter(s.MAX_FRAGMENT_UNIFORM_VECTORS),x=f>0,A=s.getParameter(s.MAX_SAMPLES);return{isWebGL2:!0,getMaxAnisotropy:r,getMaxPrecision:l,textureFormatReadable:o,textureTypeReadable:a,precision:c,logarithmicDepthBuffer:h,maxTextures:d,maxVertexTextures:f,maxTextureSize:g,maxCubemapSize:v,maxAttributes:p,maxVertexUniforms:m,maxVaryings:y,maxFragmentUniforms:_,vertexTextures:x,maxSamples:A}}function Rw(s){const e=this;let t=null,n=0,i=!1,r=!1;const o=new Si,a=new Ze,l={value:null,needsUpdate:!1};this.uniform=l,this.numPlanes=0,this.numIntersection=0,this.init=function(h,d){const f=h.length!==0||d||n!==0||i;return i=d,n=h.length,f},this.beginShadows=function(){r=!0,u(null)},this.endShadows=function(){r=!1},this.setGlobalState=function(h,d){t=u(h,d,0)},this.setState=function(h,d,f){const g=h.clippingPlanes,v=h.clipIntersection,p=h.clipShadows,m=s.get(h);if(!i||g===null||g.length===0||r&&!p)r?u(null):c();else{const y=r?0:n,_=y*4;let x=m.clippingState||null;l.value=x,x=u(g,d,_,f);for(let A=0;A!==_;++A)x[A]=t[A];m.clippingState=x,this.numIntersection=v?this.numPlanes:0,this.numPlanes+=y}};function c(){l.value!==t&&(l.value=t,l.needsUpdate=n>0),e.numPlanes=n,e.numIntersection=0}function u(h,d,f,g){const v=h!==null?h.length:0;let p=null;if(v!==0){if(p=l.value,g!==!0||p===null){const m=f+v*4,y=d.matrixWorldInverse;a.getNormalMatrix(y),(p===null||p.length0){const c=new Sp(l.height);return c.fromEquirectangularTexture(s,o),e.set(o,c),o.addEventListener("dispose",i),t(c.texture,o.mapping)}else return null}}return o}function i(o){const a=o.target;a.removeEventListener("dispose",i);const l=e.get(a);l!==void 0&&(e.delete(a),l.dispose())}function r(){e=new WeakMap}return{get:n,dispose:r}}class Da extends qr{constructor(e=-1,t=1,n=1,i=-1,r=.1,o=2e3){super(),this.isOrthographicCamera=!0,this.type="OrthographicCamera",this.zoom=1,this.view=null,this.left=e,this.right=t,this.top=n,this.bottom=i,this.near=r,this.far=o,this.updateProjectionMatrix()}copy(e,t){return super.copy(e,t),this.left=e.left,this.right=e.right,this.top=e.top,this.bottom=e.bottom,this.near=e.near,this.far=e.far,this.zoom=e.zoom,this.view=e.view===null?null:Object.assign({},e.view),this}setViewOffset(e,t,n,i,r,o){this.view===null&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=e,this.view.fullHeight=t,this.view.offsetX=n,this.view.offsetY=i,this.view.width=r,this.view.height=o,this.updateProjectionMatrix()}clearViewOffset(){this.view!==null&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const e=(this.right-this.left)/(2*this.zoom),t=(this.top-this.bottom)/(2*this.zoom),n=(this.right+this.left)/2,i=(this.top+this.bottom)/2;let r=n-e,o=n+e,a=i+t,l=i-t;if(this.view!==null&&this.view.enabled){const c=(this.right-this.left)/this.view.fullWidth/this.zoom,u=(this.top-this.bottom)/this.view.fullHeight/this.zoom;r+=c*this.view.offsetX,o=r+c*this.view.width,a-=u*this.view.offsetY,l=a-u*this.view.height}this.projectionMatrix.makeOrthographic(r,o,a,l,this.near,this.far,this.coordinateSystem),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(e){const t=super.toJSON(e);return t.object.zoom=this.zoom,t.object.left=this.left,t.object.right=this.right,t.object.top=this.top,t.object.bottom=this.bottom,t.object.near=this.near,t.object.far=this.far,this.view!==null&&(t.object.view=Object.assign({},this.view)),t}}const Os=4,bh=[.125,.215,.35,.446,.526,.582],Zi=20,Cl=new Da,Sh=new Pe;let Pl=null,Rl=0,Il=0,Ll=!1;const Yi=(1+Math.sqrt(5))/2,Es=1/Yi,wh=[new N(-Yi,Es,0),new N(Yi,Es,0),new N(-Es,0,Yi),new N(Es,0,Yi),new N(0,Yi,-Es),new N(0,Yi,Es),new N(-1,1,-1),new N(1,1,-1),new N(-1,1,1),new N(1,1,1)];class Dc{constructor(e){this._renderer=e,this._pingPongRenderTarget=null,this._lodMax=0,this._cubeSize=0,this._lodPlanes=[],this._sizeLods=[],this._sigmas=[],this._blurMaterial=null,this._cubemapMaterial=null,this._equirectMaterial=null,this._compileMaterial(this._blurMaterial)}fromScene(e,t=0,n=.1,i=100){Pl=this._renderer.getRenderTarget(),Rl=this._renderer.getActiveCubeFace(),Il=this._renderer.getActiveMipmapLevel(),Ll=this._renderer.xr.enabled,this._renderer.xr.enabled=!1,this._setSize(256);const r=this._allocateTargets();return r.depthBuffer=!0,this._sceneToCubeUV(e,n,i,r),t>0&&this._blur(r,0,0,t),this._applyPMREM(r),this._cleanup(r),r}fromEquirectangular(e,t=null){return this._fromTexture(e,t)}fromCubemap(e,t=null){return this._fromTexture(e,t)}compileCubemapShader(){this._cubemapMaterial===null&&(this._cubemapMaterial=Eh(),this._compileMaterial(this._cubemapMaterial))}compileEquirectangularShader(){this._equirectMaterial===null&&(this._equirectMaterial=Th(),this._compileMaterial(this._equirectMaterial))}dispose(){this._dispose(),this._cubemapMaterial!==null&&this._cubemapMaterial.dispose(),this._equirectMaterial!==null&&this._equirectMaterial.dispose()}_setSize(e){this._lodMax=Math.floor(Math.log2(e)),this._cubeSize=Math.pow(2,this._lodMax)}_dispose(){this._blurMaterial!==null&&this._blurMaterial.dispose(),this._pingPongRenderTarget!==null&&this._pingPongRenderTarget.dispose();for(let e=0;e2?_:0,_,_),u.setRenderTarget(i),v&&u.render(g,a),u.render(e,a)}g.geometry.dispose(),g.material.dispose(),u.toneMapping=d,u.autoClear=h,e.background=p}_textureToCubeUV(e,t){const n=this._renderer,i=e.mapping===oi||e.mapping===Ei;i?(this._cubemapMaterial===null&&(this._cubemapMaterial=Eh()),this._cubemapMaterial.uniforms.flipEnvMap.value=e.isRenderTargetTexture===!1?-1:1):this._equirectMaterial===null&&(this._equirectMaterial=Th());const r=i?this._cubemapMaterial:this._equirectMaterial,o=new Nt(this._lodPlanes[0],r),a=r.uniforms;a.envMap.value=e;const l=this._cubeSize;Eo(t,0,0,3*l,2*l),n.setRenderTarget(t),n.render(o,Cl)}_applyPMREM(e){const t=this._renderer,n=t.autoClear;t.autoClear=!1;const i=this._lodPlanes.length;for(let r=1;rZi&&console.warn(`sigmaRadians, ${r}, is too large and will clip, as it requested ${p} samples when the maximum is set to ${Zi}`);const m=[];let y=0;for(let E=0;E_-Os?i-_+Os:0),b=4*(this._cubeSize-x);Eo(t,A,b,3*x,2*x),l.setRenderTarget(t),l.render(h,Cl)}}function Lw(s){const e=[],t=[],n=[];let i=s;const r=s-Os+1+bh.length;for(let o=0;os-Os?l=bh[o-s+Os-1]:o===0&&(l=0),n.push(l);const c=1/(a-2),u=-c,h=1+c,d=[u,u,h,u,h,h,u,u,h,h,u,h],f=6,g=6,v=3,p=2,m=1,y=new Float32Array(v*g*f),_=new Float32Array(p*g*f),x=new Float32Array(m*g*f);for(let b=0;b2?0:-1,w=[E,I,0,E+2/3,I,0,E+2/3,I+1,0,E,I,0,E+2/3,I+1,0,E,I+1,0];y.set(w,v*g*b),_.set(d,p*g*b);const M=[b,b,b,b,b,b];x.set(M,m*g*b)}const A=new it;A.setAttribute("position",new pt(y,v)),A.setAttribute("uv",new pt(_,p)),A.setAttribute("faceIndex",new pt(x,m)),e.push(A),i>Os&&i--}return{lodPlanes:e,sizeLods:t,sigmas:n}}function Ah(s,e,t){const n=new In(s,e,t);return n.texture.mapping=Ws,n.texture.name="PMREM.cubeUv",n.scissorTest=!0,n}function Eo(s,e,t,n,i){s.viewport.set(e,t,n,i),s.scissor.set(e,t,n,i)}function Nw(s,e,t){const n=new Float32Array(Zi),i=new N(0,1,0);return new Ln({name:"SphericalGaussianBlur",defines:{n:Zi,CUBEUV_TEXEL_WIDTH:1/e,CUBEUV_TEXEL_HEIGHT:1/t,CUBEUV_MAX_MIP:`${s}.0`},uniforms:{envMap:{value:null},samples:{value:1},weights:{value:n},latitudinal:{value:!1},dTheta:{value:0},mipInt:{value:0},poleAxis:{value:i}},vertexShader:xu(),fragmentShader:` - - precision mediump float; - precision mediump int; - - varying vec3 vOutputDirection; - - uniform sampler2D envMap; - uniform int samples; - uniform float weights[ n ]; - uniform bool latitudinal; - uniform float dTheta; - uniform float mipInt; - uniform vec3 poleAxis; - - #define ENVMAP_TYPE_CUBE_UV - #include - - vec3 getSample( float theta, vec3 axis ) { - - float cosTheta = cos( theta ); - // Rodrigues' axis-angle rotation - vec3 sampleDirection = vOutputDirection * cosTheta - + cross( axis, vOutputDirection ) * sin( theta ) - + axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta ); - - return bilinearCubeUV( envMap, sampleDirection, mipInt ); - - } - - void main() { - - vec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection ); - - if ( all( equal( axis, vec3( 0.0 ) ) ) ) { - - axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x ); - - } - - axis = normalize( axis ); - - gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 ); - gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis ); - - for ( int i = 1; i < n; i++ ) { - - if ( i >= samples ) { - - break; - - } - - float theta = dTheta * float( i ); - gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis ); - gl_FragColor.rgb += weights[ i ] * getSample( theta, axis ); - - } - - } - `,blending:ii,depthTest:!1,depthWrite:!1})}function Th(){return new Ln({name:"EquirectangularToCubeUV",uniforms:{envMap:{value:null}},vertexShader:xu(),fragmentShader:` - - precision mediump float; - precision mediump int; - - varying vec3 vOutputDirection; - - uniform sampler2D envMap; - - #include - - void main() { - - vec3 outputDirection = normalize( vOutputDirection ); - vec2 uv = equirectUv( outputDirection ); - - gl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 ); - - } - `,blending:ii,depthTest:!1,depthWrite:!1})}function Eh(){return new Ln({name:"CubemapToCubeUV",uniforms:{envMap:{value:null},flipEnvMap:{value:-1}},vertexShader:xu(),fragmentShader:` - - precision mediump float; - precision mediump int; - - uniform float flipEnvMap; - - varying vec3 vOutputDirection; - - uniform samplerCube envMap; - - void main() { - - gl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) ); - - } - `,blending:ii,depthTest:!1,depthWrite:!1})}function xu(){return` - - precision mediump float; - precision mediump int; - - attribute float faceIndex; - - varying vec3 vOutputDirection; - - // RH coordinate system; PMREM face-indexing convention - vec3 getDirection( vec2 uv, float face ) { - - uv = 2.0 * uv - 1.0; - - vec3 direction = vec3( uv, 1.0 ); - - if ( face == 0.0 ) { - - direction = direction.zyx; // ( 1, v, u ) pos x - - } else if ( face == 1.0 ) { - - direction = direction.xzy; - direction.xz *= -1.0; // ( -u, 1, -v ) pos y - - } else if ( face == 2.0 ) { - - direction.x *= -1.0; // ( -u, v, 1 ) pos z - - } else if ( face == 3.0 ) { - - direction = direction.zyx; - direction.xz *= -1.0; // ( -1, v, -u ) neg x - - } else if ( face == 4.0 ) { - - direction = direction.xzy; - direction.xy *= -1.0; // ( -u, -1, v ) neg y - - } else if ( face == 5.0 ) { - - direction.z *= -1.0; // ( u, v, -1 ) neg z - - } - - return direction; - - } - - void main() { - - vOutputDirection = getDirection( uv, faceIndex ); - gl_Position = vec4( position, 1.0 ); - - } - `}function Dw(s){let e=new WeakMap,t=null;function n(a){if(a&&a.isTexture){const l=a.mapping,c=l===yr||l===xr,u=l===oi||l===Ei;if(c||u){let h=e.get(a);const d=h!==void 0?h.texture.pmremVersion:0;if(a.isRenderTargetTexture&&a.pmremVersion!==d)return t===null&&(t=new Dc(s)),h=c?t.fromEquirectangular(a,h):t.fromCubemap(a,h),h.texture.pmremVersion=a.pmremVersion,e.set(a,h),h.texture;if(h!==void 0)return h.texture;{const f=a.image;return c&&f&&f.height>0||u&&f&&i(f)?(t===null&&(t=new Dc(s)),h=c?t.fromEquirectangular(a):t.fromCubemap(a),h.texture.pmremVersion=a.pmremVersion,e.set(a,h),a.addEventListener("dispose",r),h.texture):null}}}return a}function i(a){let l=0;const c=6;for(let u=0;ue.maxTextureSize&&(A=Math.ceil(x/e.maxTextureSize),x=e.maxTextureSize);const b=new Float32Array(x*A*4*h),E=new La(b,x,A,h);E.type=gn,E.needsUpdate=!0;const I=_*4;for(let M=0;M0)return s;const i=e*t;let r=Ch[i];if(r===void 0&&(r=new Float32Array(i),Ch[i]=r),e!==0){n.toArray(r,0);for(let o=1,a=0;o!==e;++o)a+=t,s[o].toArray(r,a)}return r}function Ft(s,e){if(s.length!==e.length)return!1;for(let t=0,n=s.length;t":" "} ${a}: ${t[o]}`)}return n.join(` -`)}function D1(s){const e=ht.getPrimaries(ht.workingColorSpace),t=ht.getPrimaries(s);let n;switch(e===t?n="":e===Cr&&t===Er?n="LinearDisplayP3ToLinearSRGB":e===Er&&t===Cr&&(n="LinearSRGBToLinearDisplayP3"),s){case ci:case Xr:return[n,"LinearTransferOETF"];case ln:case Ia:return[n,"sRGBTransferOETF"];default:return console.warn("THREE.WebGLProgram: Unsupported color space:",s),[n,"LinearTransferOETF"]}}function Uh(s,e,t){const n=s.getShaderParameter(e,s.COMPILE_STATUS),i=s.getShaderInfoLog(e).trim();if(n&&i==="")return"";const r=/ERROR: 0:(\d+)/.exec(i);if(r){const o=parseInt(r[1]);return t.toUpperCase()+` - -`+i+` - -`+N1(s.getShaderSource(e),o)}else return i}function U1(s,e){const t=D1(e);return`vec4 ${s}( vec4 value ) { return ${t[0]}( ${t[1]}( value ) ); }`}function O1(s,e){let t;switch(e){case Bf:t="Linear";break;case zf:t="Reinhard";break;case Vf:t="OptimizedCineon";break;case Ca:t="ACESFilmic";break;case Gf:t="AgX";break;case Wf:t="Neutral";break;case Hf:t="Custom";break;default:console.warn("THREE.WebGLProgram: Unsupported toneMapping:",e),t="Linear"}return"vec3 "+s+"( vec3 color ) { return "+t+"ToneMapping( color ); }"}function F1(s){return[s.extensionClipCullDistance?"#extension GL_ANGLE_clip_cull_distance : require":"",s.extensionMultiDraw?"#extension GL_ANGLE_multi_draw : require":""].filter(ur).join(` -`)}function k1(s){const e=[];for(const t in s){const n=s[t];n!==!1&&e.push("#define "+t+" "+n)}return e.join(` -`)}function B1(s,e){const t={},n=s.getProgramParameter(e,s.ACTIVE_ATTRIBUTES);for(let i=0;i/gm;function Uc(s){return s.replace(z1,H1)}const V1=new Map;function H1(s,e){let t=nt[e];if(t===void 0){const n=V1.get(e);if(n!==void 0)t=nt[n],console.warn('THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.',e,n);else throw new Error("Can not resolve #include <"+e+">")}return Uc(t)}const G1=/#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g;function kh(s){return s.replace(G1,W1)}function W1(s,e,t,n){let i="";for(let r=parseInt(e);r0&&(p+=` -`),m=["#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,g].filter(ur).join(` -`),m.length>0&&(m+=` -`)):(p=[Bh(t),"#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,g,t.extensionClipCullDistance?"#define USE_CLIP_DISTANCE":"",t.batching?"#define USE_BATCHING":"",t.batchingColor?"#define USE_BATCHING_COLOR":"",t.instancing?"#define USE_INSTANCING":"",t.instancingColor?"#define USE_INSTANCING_COLOR":"",t.instancingMorph?"#define USE_INSTANCING_MORPH":"",t.useFog&&t.fog?"#define USE_FOG":"",t.useFog&&t.fogExp2?"#define FOG_EXP2":"",t.map?"#define USE_MAP":"",t.envMap?"#define USE_ENVMAP":"",t.envMap?"#define "+u:"",t.lightMap?"#define USE_LIGHTMAP":"",t.aoMap?"#define USE_AOMAP":"",t.bumpMap?"#define USE_BUMPMAP":"",t.normalMap?"#define USE_NORMALMAP":"",t.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",t.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",t.displacementMap?"#define USE_DISPLACEMENTMAP":"",t.emissiveMap?"#define USE_EMISSIVEMAP":"",t.anisotropy?"#define USE_ANISOTROPY":"",t.anisotropyMap?"#define USE_ANISOTROPYMAP":"",t.clearcoatMap?"#define USE_CLEARCOATMAP":"",t.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",t.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",t.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",t.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",t.specularMap?"#define USE_SPECULARMAP":"",t.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",t.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",t.roughnessMap?"#define USE_ROUGHNESSMAP":"",t.metalnessMap?"#define USE_METALNESSMAP":"",t.alphaMap?"#define USE_ALPHAMAP":"",t.alphaHash?"#define USE_ALPHAHASH":"",t.transmission?"#define USE_TRANSMISSION":"",t.transmissionMap?"#define USE_TRANSMISSIONMAP":"",t.thicknessMap?"#define USE_THICKNESSMAP":"",t.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",t.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",t.mapUv?"#define MAP_UV "+t.mapUv:"",t.alphaMapUv?"#define ALPHAMAP_UV "+t.alphaMapUv:"",t.lightMapUv?"#define LIGHTMAP_UV "+t.lightMapUv:"",t.aoMapUv?"#define AOMAP_UV "+t.aoMapUv:"",t.emissiveMapUv?"#define EMISSIVEMAP_UV "+t.emissiveMapUv:"",t.bumpMapUv?"#define BUMPMAP_UV "+t.bumpMapUv:"",t.normalMapUv?"#define NORMALMAP_UV "+t.normalMapUv:"",t.displacementMapUv?"#define DISPLACEMENTMAP_UV "+t.displacementMapUv:"",t.metalnessMapUv?"#define METALNESSMAP_UV "+t.metalnessMapUv:"",t.roughnessMapUv?"#define ROUGHNESSMAP_UV "+t.roughnessMapUv:"",t.anisotropyMapUv?"#define ANISOTROPYMAP_UV "+t.anisotropyMapUv:"",t.clearcoatMapUv?"#define CLEARCOATMAP_UV "+t.clearcoatMapUv:"",t.clearcoatNormalMapUv?"#define CLEARCOAT_NORMALMAP_UV "+t.clearcoatNormalMapUv:"",t.clearcoatRoughnessMapUv?"#define CLEARCOAT_ROUGHNESSMAP_UV "+t.clearcoatRoughnessMapUv:"",t.iridescenceMapUv?"#define IRIDESCENCEMAP_UV "+t.iridescenceMapUv:"",t.iridescenceThicknessMapUv?"#define IRIDESCENCE_THICKNESSMAP_UV "+t.iridescenceThicknessMapUv:"",t.sheenColorMapUv?"#define SHEEN_COLORMAP_UV "+t.sheenColorMapUv:"",t.sheenRoughnessMapUv?"#define SHEEN_ROUGHNESSMAP_UV "+t.sheenRoughnessMapUv:"",t.specularMapUv?"#define SPECULARMAP_UV "+t.specularMapUv:"",t.specularColorMapUv?"#define SPECULAR_COLORMAP_UV "+t.specularColorMapUv:"",t.specularIntensityMapUv?"#define SPECULAR_INTENSITYMAP_UV "+t.specularIntensityMapUv:"",t.transmissionMapUv?"#define TRANSMISSIONMAP_UV "+t.transmissionMapUv:"",t.thicknessMapUv?"#define THICKNESSMAP_UV "+t.thicknessMapUv:"",t.vertexTangents&&t.flatShading===!1?"#define USE_TANGENT":"",t.vertexColors?"#define USE_COLOR":"",t.vertexAlphas?"#define USE_COLOR_ALPHA":"",t.vertexUv1s?"#define USE_UV1":"",t.vertexUv2s?"#define USE_UV2":"",t.vertexUv3s?"#define USE_UV3":"",t.pointsUvs?"#define USE_POINTS_UV":"",t.flatShading?"#define FLAT_SHADED":"",t.skinning?"#define USE_SKINNING":"",t.morphTargets?"#define USE_MORPHTARGETS":"",t.morphNormals&&t.flatShading===!1?"#define USE_MORPHNORMALS":"",t.morphColors?"#define USE_MORPHCOLORS":"",t.morphTargetsCount>0?"#define MORPHTARGETS_TEXTURE_STRIDE "+t.morphTextureStride:"",t.morphTargetsCount>0?"#define MORPHTARGETS_COUNT "+t.morphTargetsCount:"",t.doubleSided?"#define DOUBLE_SIDED":"",t.flipSided?"#define FLIP_SIDED":"",t.shadowMapEnabled?"#define USE_SHADOWMAP":"",t.shadowMapEnabled?"#define "+l:"",t.sizeAttenuation?"#define USE_SIZEATTENUATION":"",t.numLightProbes>0?"#define USE_LIGHT_PROBES":"",t.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"","uniform mat4 modelMatrix;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform mat4 viewMatrix;","uniform mat3 normalMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;","#ifdef USE_INSTANCING"," attribute mat4 instanceMatrix;","#endif","#ifdef USE_INSTANCING_COLOR"," attribute vec3 instanceColor;","#endif","#ifdef USE_INSTANCING_MORPH"," uniform sampler2D morphTexture;","#endif","attribute vec3 position;","attribute vec3 normal;","attribute vec2 uv;","#ifdef USE_UV1"," attribute vec2 uv1;","#endif","#ifdef USE_UV2"," attribute vec2 uv2;","#endif","#ifdef USE_UV3"," attribute vec2 uv3;","#endif","#ifdef USE_TANGENT"," attribute vec4 tangent;","#endif","#if defined( USE_COLOR_ALPHA )"," attribute vec4 color;","#elif defined( USE_COLOR )"," attribute vec3 color;","#endif","#ifdef USE_SKINNING"," attribute vec4 skinIndex;"," attribute vec4 skinWeight;","#endif",` -`].filter(ur).join(` -`),m=[Bh(t),"#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,g,t.useFog&&t.fog?"#define USE_FOG":"",t.useFog&&t.fogExp2?"#define FOG_EXP2":"",t.alphaToCoverage?"#define ALPHA_TO_COVERAGE":"",t.map?"#define USE_MAP":"",t.matcap?"#define USE_MATCAP":"",t.envMap?"#define USE_ENVMAP":"",t.envMap?"#define "+c:"",t.envMap?"#define "+u:"",t.envMap?"#define "+h:"",d?"#define CUBEUV_TEXEL_WIDTH "+d.texelWidth:"",d?"#define CUBEUV_TEXEL_HEIGHT "+d.texelHeight:"",d?"#define CUBEUV_MAX_MIP "+d.maxMip+".0":"",t.lightMap?"#define USE_LIGHTMAP":"",t.aoMap?"#define USE_AOMAP":"",t.bumpMap?"#define USE_BUMPMAP":"",t.normalMap?"#define USE_NORMALMAP":"",t.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",t.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",t.emissiveMap?"#define USE_EMISSIVEMAP":"",t.anisotropy?"#define USE_ANISOTROPY":"",t.anisotropyMap?"#define USE_ANISOTROPYMAP":"",t.clearcoat?"#define USE_CLEARCOAT":"",t.clearcoatMap?"#define USE_CLEARCOATMAP":"",t.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",t.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",t.dispersion?"#define USE_DISPERSION":"",t.iridescence?"#define USE_IRIDESCENCE":"",t.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",t.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",t.specularMap?"#define USE_SPECULARMAP":"",t.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",t.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",t.roughnessMap?"#define USE_ROUGHNESSMAP":"",t.metalnessMap?"#define USE_METALNESSMAP":"",t.alphaMap?"#define USE_ALPHAMAP":"",t.alphaTest?"#define USE_ALPHATEST":"",t.alphaHash?"#define USE_ALPHAHASH":"",t.sheen?"#define USE_SHEEN":"",t.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",t.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",t.transmission?"#define USE_TRANSMISSION":"",t.transmissionMap?"#define USE_TRANSMISSIONMAP":"",t.thicknessMap?"#define USE_THICKNESSMAP":"",t.vertexTangents&&t.flatShading===!1?"#define USE_TANGENT":"",t.vertexColors||t.instancingColor||t.batchingColor?"#define USE_COLOR":"",t.vertexAlphas?"#define USE_COLOR_ALPHA":"",t.vertexUv1s?"#define USE_UV1":"",t.vertexUv2s?"#define USE_UV2":"",t.vertexUv3s?"#define USE_UV3":"",t.pointsUvs?"#define USE_POINTS_UV":"",t.gradientMap?"#define USE_GRADIENTMAP":"",t.flatShading?"#define FLAT_SHADED":"",t.doubleSided?"#define DOUBLE_SIDED":"",t.flipSided?"#define FLIP_SIDED":"",t.shadowMapEnabled?"#define USE_SHADOWMAP":"",t.shadowMapEnabled?"#define "+l:"",t.premultipliedAlpha?"#define PREMULTIPLIED_ALPHA":"",t.numLightProbes>0?"#define USE_LIGHT_PROBES":"",t.decodeVideoTexture?"#define DECODE_VIDEO_TEXTURE":"",t.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;",t.toneMapping!==Hn?"#define TONE_MAPPING":"",t.toneMapping!==Hn?nt.tonemapping_pars_fragment:"",t.toneMapping!==Hn?O1("toneMapping",t.toneMapping):"",t.dithering?"#define DITHERING":"",t.opaque?"#define OPAQUE":"",nt.colorspace_pars_fragment,U1("linearToOutputTexel",t.outputColorSpace),t.useDepthPacking?"#define DEPTH_PACKING "+t.depthPacking:"",` -`].filter(ur).join(` -`)),o=Uc(o),o=Oh(o,t),o=Fh(o,t),a=Uc(a),a=Oh(a,t),a=Fh(a,t),o=kh(o),a=kh(a),t.isRawShaderMaterial!==!0&&(y=`#version 300 es -`,p=[f,"#define attribute in","#define varying out","#define texture2D texture"].join(` -`)+` -`+p,m=["#define varying in",t.glslVersion===Nc?"":"layout(location = 0) out highp vec4 pc_fragColor;",t.glslVersion===Nc?"":"#define gl_FragColor pc_fragColor","#define gl_FragDepthEXT gl_FragDepth","#define texture2D texture","#define textureCube texture","#define texture2DProj textureProj","#define texture2DLodEXT textureLod","#define texture2DProjLodEXT textureProjLod","#define textureCubeLodEXT textureLod","#define texture2DGradEXT textureGrad","#define texture2DProjGradEXT textureProjGrad","#define textureCubeGradEXT textureGrad"].join(` -`)+` -`+m);const _=y+p+o,x=y+m+a,A=Dh(i,i.VERTEX_SHADER,_),b=Dh(i,i.FRAGMENT_SHADER,x);i.attachShader(v,A),i.attachShader(v,b),t.index0AttributeName!==void 0?i.bindAttribLocation(v,0,t.index0AttributeName):t.morphTargets===!0&&i.bindAttribLocation(v,0,"position"),i.linkProgram(v);function E(F){if(s.debug.checkShaderErrors){const V=i.getProgramInfoLog(v).trim(),G=i.getShaderInfoLog(A).trim(),q=i.getShaderInfoLog(b).trim();let ae=!0,j=!0;if(i.getProgramParameter(v,i.LINK_STATUS)===!1)if(ae=!1,typeof s.debug.onShaderError=="function")s.debug.onShaderError(i,v,A,b);else{const oe=Uh(i,A,"vertex"),B=Uh(i,b,"fragment");console.error("THREE.WebGLProgram: Shader Error "+i.getError()+" - VALIDATE_STATUS "+i.getProgramParameter(v,i.VALIDATE_STATUS)+` - -Material Name: `+F.name+` -Material Type: `+F.type+` - -Program Info Log: `+V+` -`+oe+` -`+B)}else V!==""?console.warn("THREE.WebGLProgram: Program Info Log:",V):(G===""||q==="")&&(j=!1);j&&(F.diagnostics={runnable:ae,programLog:V,vertexShader:{log:G,prefix:p},fragmentShader:{log:q,prefix:m}})}i.deleteShader(A),i.deleteShader(b),I=new ha(i,v),w=B1(i,v)}let I;this.getUniforms=function(){return I===void 0&&E(this),I};let w;this.getAttributes=function(){return w===void 0&&E(this),w};let M=t.rendererExtensionParallelShaderCompile===!1;return this.isReady=function(){return M===!1&&(M=i.getProgramParameter(v,I1)),M},this.destroy=function(){n.releaseStatesOfProgram(this),i.deleteProgram(v),this.program=void 0},this.type=t.shaderType,this.name=t.shaderName,this.id=L1++,this.cacheKey=e,this.usedTimes=1,this.program=v,this.vertexShader=A,this.fragmentShader=b,this}let K1=0;class j1{constructor(){this.shaderCache=new Map,this.materialCache=new Map}update(e){const t=e.vertexShader,n=e.fragmentShader,i=this._getShaderStage(t),r=this._getShaderStage(n),o=this._getShaderCacheForMaterial(e);return o.has(i)===!1&&(o.add(i),i.usedTimes++),o.has(r)===!1&&(o.add(r),r.usedTimes++),this}remove(e){const t=this.materialCache.get(e);for(const n of t)n.usedTimes--,n.usedTimes===0&&this.shaderCache.delete(n.code);return this.materialCache.delete(e),this}getVertexShaderID(e){return this._getShaderStage(e.vertexShader).id}getFragmentShaderID(e){return this._getShaderStage(e.fragmentShader).id}dispose(){this.shaderCache.clear(),this.materialCache.clear()}_getShaderCacheForMaterial(e){const t=this.materialCache;let n=t.get(e);return n===void 0&&(n=new Set,t.set(e,n)),n}_getShaderStage(e){const t=this.shaderCache;let n=t.get(e);return n===void 0&&(n=new Q1(e),t.set(e,n)),n}}class Q1{constructor(e){this.id=K1++,this.code=e,this.usedTimes=0}}function eA(s,e,t,n,i,r,o){const a=new Na,l=new j1,c=new Set,u=[],h=i.logarithmicDepthBuffer,d=i.vertexTextures;let f=i.precision;const g={MeshDepthMaterial:"depth",MeshDistanceMaterial:"distanceRGBA",MeshNormalMaterial:"normal",MeshBasicMaterial:"basic",MeshLambertMaterial:"lambert",MeshPhongMaterial:"phong",MeshToonMaterial:"toon",MeshStandardMaterial:"physical",MeshPhysicalMaterial:"physical",MeshMatcapMaterial:"matcap",LineBasicMaterial:"basic",LineDashedMaterial:"dashed",PointsMaterial:"points",ShadowMaterial:"shadow",SpriteMaterial:"sprite"};function v(w){return c.add(w),w===0?"uv":`uv${w}`}function p(w,M,F,V,G){const q=V.fog,ae=G.geometry,j=w.isMeshStandardMaterial?V.environment:null,oe=(w.isMeshStandardMaterial?t:e).get(w.envMap||j),B=oe&&oe.mapping===Ws?oe.image.height:null,Me=g[w.type];w.precision!==null&&(f=i.getMaxPrecision(w.precision),f!==w.precision&&console.warn("THREE.WebGLProgram.getParameters:",w.precision,"not supported, using",f,"instead."));const be=ae.morphAttributes.position||ae.morphAttributes.normal||ae.morphAttributes.color,Ae=be!==void 0?be.length:0;let ge=0;ae.morphAttributes.position!==void 0&&(ge=1),ae.morphAttributes.normal!==void 0&&(ge=2),ae.morphAttributes.color!==void 0&&(ge=3);let Be,U,D,R;if(Me){const vt=Tn[Me];Be=vt.vertexShader,U=vt.fragmentShader}else Be=w.vertexShader,U=w.fragmentShader,l.update(w),D=l.getVertexShaderID(w),R=l.getFragmentShaderID(w);const T=s.getRenderTarget(),ie=G.isInstancedMesh===!0,he=G.isBatchedMesh===!0,J=!!w.map,L=!!w.matcap,X=!!oe,K=!!w.aoMap,H=!!w.lightMap,$=!!w.bumpMap,te=!!w.normalMap,le=!!w.displacementMap,k=!!w.emissiveMap,O=!!w.metalnessMap,P=!!w.roughnessMap,S=w.anisotropy>0,Q=w.clearcoat>0,pe=w.dispersion>0,ce=w.iridescence>0,ve=w.sheen>0,Ve=w.transmission>0,Ee=S&&!!w.anisotropyMap,Te=Q&&!!w.clearcoatMap,Qe=Q&&!!w.clearcoatNormalMap,xe=Q&&!!w.clearcoatRoughnessMap,Oe=ce&&!!w.iridescenceMap,st=ce&&!!w.iridescenceThicknessMap,Je=ve&&!!w.sheenColorMap,Re=ve&&!!w.sheenRoughnessMap,rt=!!w.specularMap,at=!!w.specularColorMap,Rt=!!w.specularIntensityMap,z=Ve&&!!w.transmissionMap,Ie=Ve&&!!w.thicknessMap,de=!!w.gradientMap,_e=!!w.alphaMap,we=w.alphaTest>0,et=!!w.alphaHash,ut=!!w.extensions;let It=Hn;w.toneMapped&&(T===null||T.isXRRenderTarget===!0)&&(It=s.toneMapping);const Bt={shaderID:Me,shaderType:w.type,shaderName:w.name,vertexShader:Be,fragmentShader:U,defines:w.defines,customVertexShaderID:D,customFragmentShaderID:R,isRawShaderMaterial:w.isRawShaderMaterial===!0,glslVersion:w.glslVersion,precision:f,batching:he,batchingColor:he&&G._colorsTexture!==null,instancing:ie,instancingColor:ie&&G.instanceColor!==null,instancingMorph:ie&&G.morphTexture!==null,supportsVertexTextures:d,outputColorSpace:T===null?s.outputColorSpace:T.isXRRenderTarget===!0?T.texture.colorSpace:ci,alphaToCoverage:!!w.alphaToCoverage,map:J,matcap:L,envMap:X,envMapMode:X&&oe.mapping,envMapCubeUVHeight:B,aoMap:K,lightMap:H,bumpMap:$,normalMap:te,displacementMap:d&&le,emissiveMap:k,normalMapObjectSpace:te&&w.normalMapType===op,normalMapTangentSpace:te&&w.normalMapType===Ri,metalnessMap:O,roughnessMap:P,anisotropy:S,anisotropyMap:Ee,clearcoat:Q,clearcoatMap:Te,clearcoatNormalMap:Qe,clearcoatRoughnessMap:xe,dispersion:pe,iridescence:ce,iridescenceMap:Oe,iridescenceThicknessMap:st,sheen:ve,sheenColorMap:Je,sheenRoughnessMap:Re,specularMap:rt,specularColorMap:at,specularIntensityMap:Rt,transmission:Ve,transmissionMap:z,thicknessMap:Ie,gradientMap:de,opaque:w.transparent===!1&&w.blending===es&&w.alphaToCoverage===!1,alphaMap:_e,alphaTest:we,alphaHash:et,combine:w.combine,mapUv:J&&v(w.map.channel),aoMapUv:K&&v(w.aoMap.channel),lightMapUv:H&&v(w.lightMap.channel),bumpMapUv:$&&v(w.bumpMap.channel),normalMapUv:te&&v(w.normalMap.channel),displacementMapUv:le&&v(w.displacementMap.channel),emissiveMapUv:k&&v(w.emissiveMap.channel),metalnessMapUv:O&&v(w.metalnessMap.channel),roughnessMapUv:P&&v(w.roughnessMap.channel),anisotropyMapUv:Ee&&v(w.anisotropyMap.channel),clearcoatMapUv:Te&&v(w.clearcoatMap.channel),clearcoatNormalMapUv:Qe&&v(w.clearcoatNormalMap.channel),clearcoatRoughnessMapUv:xe&&v(w.clearcoatRoughnessMap.channel),iridescenceMapUv:Oe&&v(w.iridescenceMap.channel),iridescenceThicknessMapUv:st&&v(w.iridescenceThicknessMap.channel),sheenColorMapUv:Je&&v(w.sheenColorMap.channel),sheenRoughnessMapUv:Re&&v(w.sheenRoughnessMap.channel),specularMapUv:rt&&v(w.specularMap.channel),specularColorMapUv:at&&v(w.specularColorMap.channel),specularIntensityMapUv:Rt&&v(w.specularIntensityMap.channel),transmissionMapUv:z&&v(w.transmissionMap.channel),thicknessMapUv:Ie&&v(w.thicknessMap.channel),alphaMapUv:_e&&v(w.alphaMap.channel),vertexTangents:!!ae.attributes.tangent&&(te||S),vertexColors:w.vertexColors,vertexAlphas:w.vertexColors===!0&&!!ae.attributes.color&&ae.attributes.color.itemSize===4,pointsUvs:G.isPoints===!0&&!!ae.attributes.uv&&(J||_e),fog:!!q,useFog:w.fog===!0,fogExp2:!!q&&q.isFogExp2,flatShading:w.flatShading===!0,sizeAttenuation:w.sizeAttenuation===!0,logarithmicDepthBuffer:h,skinning:G.isSkinnedMesh===!0,morphTargets:ae.morphAttributes.position!==void 0,morphNormals:ae.morphAttributes.normal!==void 0,morphColors:ae.morphAttributes.color!==void 0,morphTargetsCount:Ae,morphTextureStride:ge,numDirLights:M.directional.length,numPointLights:M.point.length,numSpotLights:M.spot.length,numSpotLightMaps:M.spotLightMap.length,numRectAreaLights:M.rectArea.length,numHemiLights:M.hemi.length,numDirLightShadows:M.directionalShadowMap.length,numPointLightShadows:M.pointShadowMap.length,numSpotLightShadows:M.spotShadowMap.length,numSpotLightShadowsWithMaps:M.numSpotLightShadowsWithMaps,numLightProbes:M.numLightProbes,numClippingPlanes:o.numPlanes,numClipIntersection:o.numIntersection,dithering:w.dithering,shadowMapEnabled:s.shadowMap.enabled&&F.length>0,shadowMapType:s.shadowMap.type,toneMapping:It,decodeVideoTexture:J&&w.map.isVideoTexture===!0&&ht.getTransfer(w.map.colorSpace)===Mt,premultipliedAlpha:w.premultipliedAlpha,doubleSided:w.side===En,flipSided:w.side===nn,useDepthPacking:w.depthPacking>=0,depthPacking:w.depthPacking||0,index0AttributeName:w.index0AttributeName,extensionClipCullDistance:ut&&w.extensions.clipCullDistance===!0&&n.has("WEBGL_clip_cull_distance"),extensionMultiDraw:ut&&w.extensions.multiDraw===!0&&n.has("WEBGL_multi_draw"),rendererExtensionParallelShaderCompile:n.has("KHR_parallel_shader_compile"),customProgramCacheKey:w.customProgramCacheKey()};return Bt.vertexUv1s=c.has(1),Bt.vertexUv2s=c.has(2),Bt.vertexUv3s=c.has(3),c.clear(),Bt}function m(w){const M=[];if(w.shaderID?M.push(w.shaderID):(M.push(w.customVertexShaderID),M.push(w.customFragmentShaderID)),w.defines!==void 0)for(const F in w.defines)M.push(F),M.push(w.defines[F]);return w.isRawShaderMaterial===!1&&(y(M,w),_(M,w),M.push(s.outputColorSpace)),M.push(w.customProgramCacheKey),M.join()}function y(w,M){w.push(M.precision),w.push(M.outputColorSpace),w.push(M.envMapMode),w.push(M.envMapCubeUVHeight),w.push(M.mapUv),w.push(M.alphaMapUv),w.push(M.lightMapUv),w.push(M.aoMapUv),w.push(M.bumpMapUv),w.push(M.normalMapUv),w.push(M.displacementMapUv),w.push(M.emissiveMapUv),w.push(M.metalnessMapUv),w.push(M.roughnessMapUv),w.push(M.anisotropyMapUv),w.push(M.clearcoatMapUv),w.push(M.clearcoatNormalMapUv),w.push(M.clearcoatRoughnessMapUv),w.push(M.iridescenceMapUv),w.push(M.iridescenceThicknessMapUv),w.push(M.sheenColorMapUv),w.push(M.sheenRoughnessMapUv),w.push(M.specularMapUv),w.push(M.specularColorMapUv),w.push(M.specularIntensityMapUv),w.push(M.transmissionMapUv),w.push(M.thicknessMapUv),w.push(M.combine),w.push(M.fogExp2),w.push(M.sizeAttenuation),w.push(M.morphTargetsCount),w.push(M.morphAttributeCount),w.push(M.numDirLights),w.push(M.numPointLights),w.push(M.numSpotLights),w.push(M.numSpotLightMaps),w.push(M.numHemiLights),w.push(M.numRectAreaLights),w.push(M.numDirLightShadows),w.push(M.numPointLightShadows),w.push(M.numSpotLightShadows),w.push(M.numSpotLightShadowsWithMaps),w.push(M.numLightProbes),w.push(M.shadowMapType),w.push(M.toneMapping),w.push(M.numClippingPlanes),w.push(M.numClipIntersection),w.push(M.depthPacking)}function _(w,M){a.disableAll(),M.supportsVertexTextures&&a.enable(0),M.instancing&&a.enable(1),M.instancingColor&&a.enable(2),M.instancingMorph&&a.enable(3),M.matcap&&a.enable(4),M.envMap&&a.enable(5),M.normalMapObjectSpace&&a.enable(6),M.normalMapTangentSpace&&a.enable(7),M.clearcoat&&a.enable(8),M.iridescence&&a.enable(9),M.alphaTest&&a.enable(10),M.vertexColors&&a.enable(11),M.vertexAlphas&&a.enable(12),M.vertexUv1s&&a.enable(13),M.vertexUv2s&&a.enable(14),M.vertexUv3s&&a.enable(15),M.vertexTangents&&a.enable(16),M.anisotropy&&a.enable(17),M.alphaHash&&a.enable(18),M.batching&&a.enable(19),M.dispersion&&a.enable(20),M.batchingColor&&a.enable(21),w.push(a.mask),a.disableAll(),M.fog&&a.enable(0),M.useFog&&a.enable(1),M.flatShading&&a.enable(2),M.logarithmicDepthBuffer&&a.enable(3),M.skinning&&a.enable(4),M.morphTargets&&a.enable(5),M.morphNormals&&a.enable(6),M.morphColors&&a.enable(7),M.premultipliedAlpha&&a.enable(8),M.shadowMapEnabled&&a.enable(9),M.doubleSided&&a.enable(10),M.flipSided&&a.enable(11),M.useDepthPacking&&a.enable(12),M.dithering&&a.enable(13),M.transmission&&a.enable(14),M.sheen&&a.enable(15),M.opaque&&a.enable(16),M.pointsUvs&&a.enable(17),M.decodeVideoTexture&&a.enable(18),M.alphaToCoverage&&a.enable(19),w.push(a.mask)}function x(w){const M=g[w.type];let F;if(M){const V=Tn[M];F=Mp.clone(V.uniforms)}else F=w.uniforms;return F}function A(w,M){let F;for(let V=0,G=u.length;V0?n.push(m):f.transparent===!0?i.push(m):t.push(m)}function l(h,d,f,g,v,p){const m=o(h,d,f,g,v,p);f.transmission>0?n.unshift(m):f.transparent===!0?i.unshift(m):t.unshift(m)}function c(h,d){t.length>1&&t.sort(h||nA),n.length>1&&n.sort(d||zh),i.length>1&&i.sort(d||zh)}function u(){for(let h=e,d=s.length;h=r.length?(o=new Vh,r.push(o)):o=r[i],o}function t(){s=new WeakMap}return{get:e,dispose:t}}function sA(){const s={};return{get:function(e){if(s[e.id]!==void 0)return s[e.id];let t;switch(e.type){case"DirectionalLight":t={direction:new N,color:new Pe};break;case"SpotLight":t={position:new N,direction:new N,color:new Pe,distance:0,coneCos:0,penumbraCos:0,decay:0};break;case"PointLight":t={position:new N,color:new Pe,distance:0,decay:0};break;case"HemisphereLight":t={direction:new N,skyColor:new Pe,groundColor:new Pe};break;case"RectAreaLight":t={color:new Pe,position:new N,halfWidth:new N,halfHeight:new N};break}return s[e.id]=t,t}}}function rA(){const s={};return{get:function(e){if(s[e.id]!==void 0)return s[e.id];let t;switch(e.type){case"DirectionalLight":t={shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new se};break;case"SpotLight":t={shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new se};break;case"PointLight":t={shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new se,shadowCameraNear:1,shadowCameraFar:1e3};break}return s[e.id]=t,t}}}let oA=0;function aA(s,e){return(e.castShadow?2:0)-(s.castShadow?2:0)+(e.map?1:0)-(s.map?1:0)}function lA(s){const e=new sA,t=rA(),n={version:0,hash:{directionalLength:-1,pointLength:-1,spotLength:-1,rectAreaLength:-1,hemiLength:-1,numDirectionalShadows:-1,numPointShadows:-1,numSpotShadows:-1,numSpotMaps:-1,numLightProbes:-1},ambient:[0,0,0],probe:[],directional:[],directionalShadow:[],directionalShadowMap:[],directionalShadowMatrix:[],spot:[],spotLightMap:[],spotShadow:[],spotShadowMap:[],spotLightMatrix:[],rectArea:[],rectAreaLTC1:null,rectAreaLTC2:null,point:[],pointShadow:[],pointShadowMap:[],pointShadowMatrix:[],hemi:[],numSpotLightShadowsWithMaps:0,numLightProbes:0};for(let c=0;c<9;c++)n.probe.push(new N);const i=new N,r=new qe,o=new qe;function a(c){let u=0,h=0,d=0;for(let w=0;w<9;w++)n.probe[w].set(0,0,0);let f=0,g=0,v=0,p=0,m=0,y=0,_=0,x=0,A=0,b=0,E=0;c.sort(aA);for(let w=0,M=c.length;w0&&(s.has("OES_texture_float_linear")===!0?(n.rectAreaLTC1=Ce.LTC_FLOAT_1,n.rectAreaLTC2=Ce.LTC_FLOAT_2):(n.rectAreaLTC1=Ce.LTC_HALF_1,n.rectAreaLTC2=Ce.LTC_HALF_2)),n.ambient[0]=u,n.ambient[1]=h,n.ambient[2]=d;const I=n.hash;(I.directionalLength!==f||I.pointLength!==g||I.spotLength!==v||I.rectAreaLength!==p||I.hemiLength!==m||I.numDirectionalShadows!==y||I.numPointShadows!==_||I.numSpotShadows!==x||I.numSpotMaps!==A||I.numLightProbes!==E)&&(n.directional.length=f,n.spot.length=v,n.rectArea.length=p,n.point.length=g,n.hemi.length=m,n.directionalShadow.length=y,n.directionalShadowMap.length=y,n.pointShadow.length=_,n.pointShadowMap.length=_,n.spotShadow.length=x,n.spotShadowMap.length=x,n.directionalShadowMatrix.length=y,n.pointShadowMatrix.length=_,n.spotLightMatrix.length=x+A-b,n.spotLightMap.length=A,n.numSpotLightShadowsWithMaps=b,n.numLightProbes=E,I.directionalLength=f,I.pointLength=g,I.spotLength=v,I.rectAreaLength=p,I.hemiLength=m,I.numDirectionalShadows=y,I.numPointShadows=_,I.numSpotShadows=x,I.numSpotMaps=A,I.numLightProbes=E,n.version=oA++)}function l(c,u){let h=0,d=0,f=0,g=0,v=0;const p=u.matrixWorldInverse;for(let m=0,y=c.length;m=o.length?(a=new Hh(s),o.push(a)):a=o[r],a}function n(){e=new WeakMap}return{get:t,dispose:n}}class bu extends Kt{constructor(e){super(),this.isMeshDepthMaterial=!0,this.type="MeshDepthMaterial",this.depthPacking=sp,this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.setValues(e)}copy(e){return super.copy(e),this.depthPacking=e.depthPacking,this.map=e.map,this.alphaMap=e.alphaMap,this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this}}class Su extends Kt{constructor(e){super(),this.isMeshDistanceMaterial=!0,this.type="MeshDistanceMaterial",this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.setValues(e)}copy(e){return super.copy(e),this.map=e.map,this.alphaMap=e.alphaMap,this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this}}const uA=`void main() { - gl_Position = vec4( position, 1.0 ); -}`,hA=`uniform sampler2D shadow_pass; -uniform vec2 resolution; -uniform float radius; -#include -void main() { - const float samples = float( VSM_SAMPLES ); - float mean = 0.0; - float squared_mean = 0.0; - float uvStride = samples <= 1.0 ? 0.0 : 2.0 / ( samples - 1.0 ); - float uvStart = samples <= 1.0 ? 0.0 : - 1.0; - for ( float i = 0.0; i < samples; i ++ ) { - float uvOffset = uvStart + i * uvStride; - #ifdef HORIZONTAL_PASS - vec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( uvOffset, 0.0 ) * radius ) / resolution ) ); - mean += distribution.x; - squared_mean += distribution.y * distribution.y + distribution.x * distribution.x; - #else - float depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, uvOffset ) * radius ) / resolution ) ); - mean += depth; - squared_mean += depth * depth; - #endif - } - mean = mean / samples; - squared_mean = squared_mean / samples; - float std_dev = sqrt( squared_mean - mean * mean ); - gl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) ); -}`;function dA(s,e,t){let n=new Zr;const i=new se,r=new se,o=new gt,a=new bu({depthPacking:rp}),l=new Su,c={},u=t.maxTextureSize,h={[ri]:nn,[nn]:ri,[En]:En},d=new Ln({defines:{VSM_SAMPLES:8},uniforms:{shadow_pass:{value:null},resolution:{value:new se},radius:{value:4}},vertexShader:uA,fragmentShader:hA}),f=d.clone();f.defines.HORIZONTAL_PASS=1;const g=new it;g.setAttribute("position",new pt(new Float32Array([-1,-1,.5,3,-1,.5,-1,3,.5]),3));const v=new Nt(g,d),p=this;this.enabled=!1,this.autoUpdate=!0,this.needsUpdate=!1,this.type=iu;let m=this.type;this.render=function(b,E,I){if(p.enabled===!1||p.autoUpdate===!1&&p.needsUpdate===!1||b.length===0)return;const w=s.getRenderTarget(),M=s.getActiveCubeFace(),F=s.getActiveMipmapLevel(),V=s.state;V.setBlending(ii),V.buffers.color.setClear(1,1,1,1),V.buffers.depth.setTest(!0),V.setScissorTest(!1);const G=m!==kn&&this.type===kn,q=m===kn&&this.type!==kn;for(let ae=0,j=b.length;aeu||i.y>u)&&(i.x>u&&(r.x=Math.floor(u/Me.x),i.x=r.x*Me.x,B.mapSize.x=r.x),i.y>u&&(r.y=Math.floor(u/Me.y),i.y=r.y*Me.y,B.mapSize.y=r.y)),B.map===null||G===!0||q===!0){const Ae=this.type!==kn?{minFilter:Gt,magFilter:Gt}:{};B.map!==null&&B.map.dispose(),B.map=new In(i.x,i.y,Ae),B.map.texture.name=oe.name+".shadowMap",B.camera.updateProjectionMatrix()}s.setRenderTarget(B.map),s.clear();const be=B.getViewportCount();for(let Ae=0;Ae0||E.map&&E.alphaTest>0){const V=M.uuid,G=E.uuid;let q=c[V];q===void 0&&(q={},c[V]=q);let ae=q[G];ae===void 0&&(ae=M.clone(),q[G]=ae,E.addEventListener("dispose",A)),M=ae}if(M.visible=E.visible,M.wireframe=E.wireframe,w===kn?M.side=E.shadowSide!==null?E.shadowSide:E.side:M.side=E.shadowSide!==null?E.shadowSide:h[E.side],M.alphaMap=E.alphaMap,M.alphaTest=E.alphaTest,M.map=E.map,M.clipShadows=E.clipShadows,M.clippingPlanes=E.clippingPlanes,M.clipIntersection=E.clipIntersection,M.displacementMap=E.displacementMap,M.displacementScale=E.displacementScale,M.displacementBias=E.displacementBias,M.wireframeLinewidth=E.wireframeLinewidth,M.linewidth=E.linewidth,I.isPointLight===!0&&M.isMeshDistanceMaterial===!0){const V=s.properties.get(M);V.light=I}return M}function x(b,E,I,w,M){if(b.visible===!1)return;if(b.layers.test(E.layers)&&(b.isMesh||b.isLine||b.isPoints)&&(b.castShadow||b.receiveShadow&&M===kn)&&(!b.frustumCulled||n.intersectsObject(b))){b.modelViewMatrix.multiplyMatrices(I.matrixWorldInverse,b.matrixWorld);const G=e.update(b),q=b.material;if(Array.isArray(q)){const ae=G.groups;for(let j=0,oe=ae.length;j=1):oe.indexOf("OpenGL ES")!==-1&&(j=parseFloat(/^OpenGL ES (\d)/.exec(oe)[1]),ae=j>=2);let B=null,Me={};const be=s.getParameter(s.SCISSOR_BOX),Ae=s.getParameter(s.VIEWPORT),ge=new gt().fromArray(be),Be=new gt().fromArray(Ae);function U(z,Ie,de,_e){const we=new Uint8Array(4),et=s.createTexture();s.bindTexture(z,et),s.texParameteri(z,s.TEXTURE_MIN_FILTER,s.NEAREST),s.texParameteri(z,s.TEXTURE_MAG_FILTER,s.NEAREST);for(let ut=0;ut"u"?!1:/OculusBrowser/g.test(navigator.userAgent),c=new se,u=new WeakMap;let h;const d=new WeakMap;let f=!1;try{f=typeof OffscreenCanvas<"u"&&new OffscreenCanvas(1,1).getContext("2d")!==null}catch{}function g(P,S){return f?new OffscreenCanvas(P,S):Ir("canvas")}function v(P,S,Q){let pe=1;const ce=O(P);if((ce.width>Q||ce.height>Q)&&(pe=Q/Math.max(ce.width,ce.height)),pe<1)if(typeof HTMLImageElement<"u"&&P instanceof HTMLImageElement||typeof HTMLCanvasElement<"u"&&P instanceof HTMLCanvasElement||typeof ImageBitmap<"u"&&P instanceof ImageBitmap||typeof VideoFrame<"u"&&P instanceof VideoFrame){const ve=Math.floor(pe*ce.width),Ve=Math.floor(pe*ce.height);h===void 0&&(h=g(ve,Ve));const Ee=S?g(ve,Ve):h;return Ee.width=ve,Ee.height=Ve,Ee.getContext("2d").drawImage(P,0,0,ve,Ve),console.warn("THREE.WebGLRenderer: Texture has been resized from ("+ce.width+"x"+ce.height+") to ("+ve+"x"+Ve+")."),Ee}else return"data"in P&&console.warn("THREE.WebGLRenderer: Image in DataTexture is too big ("+ce.width+"x"+ce.height+")."),P;return P}function p(P){return P.generateMipmaps&&P.minFilter!==Gt&&P.minFilter!==Ot}function m(P){s.generateMipmap(P)}function y(P,S,Q,pe,ce=!1){if(P!==null){if(s[P]!==void 0)return s[P];console.warn("THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format '"+P+"'")}let ve=S;if(S===s.RED&&(Q===s.FLOAT&&(ve=s.R32F),Q===s.HALF_FLOAT&&(ve=s.R16F),Q===s.UNSIGNED_BYTE&&(ve=s.R8)),S===s.RED_INTEGER&&(Q===s.UNSIGNED_BYTE&&(ve=s.R8UI),Q===s.UNSIGNED_SHORT&&(ve=s.R16UI),Q===s.UNSIGNED_INT&&(ve=s.R32UI),Q===s.BYTE&&(ve=s.R8I),Q===s.SHORT&&(ve=s.R16I),Q===s.INT&&(ve=s.R32I)),S===s.RG&&(Q===s.FLOAT&&(ve=s.RG32F),Q===s.HALF_FLOAT&&(ve=s.RG16F),Q===s.UNSIGNED_BYTE&&(ve=s.RG8)),S===s.RG_INTEGER&&(Q===s.UNSIGNED_BYTE&&(ve=s.RG8UI),Q===s.UNSIGNED_SHORT&&(ve=s.RG16UI),Q===s.UNSIGNED_INT&&(ve=s.RG32UI),Q===s.BYTE&&(ve=s.RG8I),Q===s.SHORT&&(ve=s.RG16I),Q===s.INT&&(ve=s.RG32I)),S===s.RGB&&Q===s.UNSIGNED_INT_5_9_9_9_REV&&(ve=s.RGB9_E5),S===s.RGBA){const Ve=ce?Tr:ht.getTransfer(pe);Q===s.FLOAT&&(ve=s.RGBA32F),Q===s.HALF_FLOAT&&(ve=s.RGBA16F),Q===s.UNSIGNED_BYTE&&(ve=Ve===Mt?s.SRGB8_ALPHA8:s.RGBA8),Q===s.UNSIGNED_SHORT_4_4_4_4&&(ve=s.RGBA4),Q===s.UNSIGNED_SHORT_5_5_5_1&&(ve=s.RGB5_A1)}return(ve===s.R16F||ve===s.R32F||ve===s.RG16F||ve===s.RG32F||ve===s.RGBA16F||ve===s.RGBA32F)&&e.get("EXT_color_buffer_float"),ve}function _(P,S){let Q;return P?S===null||S===ss||S===rs?Q=s.DEPTH24_STENCIL8:S===gn?Q=s.DEPTH32F_STENCIL8:S===Sr&&(Q=s.DEPTH24_STENCIL8,console.warn("DepthTexture: 16 bit depth attachment is not supported with stencil. Using 24-bit attachment.")):S===null||S===ss||S===rs?Q=s.DEPTH_COMPONENT24:S===gn?Q=s.DEPTH_COMPONENT32F:S===Sr&&(Q=s.DEPTH_COMPONENT16),Q}function x(P,S){return p(P)===!0||P.isFramebufferTexture&&P.minFilter!==Gt&&P.minFilter!==Ot?Math.log2(Math.max(S.width,S.height))+1:P.mipmaps!==void 0&&P.mipmaps.length>0?P.mipmaps.length:P.isCompressedTexture&&Array.isArray(P.image)?S.mipmaps.length:1}function A(P){const S=P.target;S.removeEventListener("dispose",A),E(S),S.isVideoTexture&&u.delete(S)}function b(P){const S=P.target;S.removeEventListener("dispose",b),w(S)}function E(P){const S=n.get(P);if(S.__webglInit===void 0)return;const Q=P.source,pe=d.get(Q);if(pe){const ce=pe[S.__cacheKey];ce.usedTimes--,ce.usedTimes===0&&I(P),Object.keys(pe).length===0&&d.delete(Q)}n.remove(P)}function I(P){const S=n.get(P);s.deleteTexture(S.__webglTexture);const Q=P.source,pe=d.get(Q);delete pe[S.__cacheKey],o.memory.textures--}function w(P){const S=n.get(P);if(P.depthTexture&&P.depthTexture.dispose(),P.isWebGLCubeRenderTarget)for(let pe=0;pe<6;pe++){if(Array.isArray(S.__webglFramebuffer[pe]))for(let ce=0;ce=i.maxTextures&&console.warn("THREE.WebGLTextures: Trying to use "+P+" texture units while this GPU supports only "+i.maxTextures),M+=1,P}function G(P){const S=[];return S.push(P.wrapS),S.push(P.wrapT),S.push(P.wrapR||0),S.push(P.magFilter),S.push(P.minFilter),S.push(P.anisotropy),S.push(P.internalFormat),S.push(P.format),S.push(P.type),S.push(P.generateMipmaps),S.push(P.premultiplyAlpha),S.push(P.flipY),S.push(P.unpackAlignment),S.push(P.colorSpace),S.join()}function q(P,S){const Q=n.get(P);if(P.isVideoTexture&&le(P),P.isRenderTargetTexture===!1&&P.version>0&&Q.__version!==P.version){const pe=P.image;if(pe===null)console.warn("THREE.WebGLRenderer: Texture marked for update but no image data found.");else if(pe.complete===!1)console.warn("THREE.WebGLRenderer: Texture marked for update but image is incomplete");else{Be(Q,P,S);return}}t.bindTexture(s.TEXTURE_2D,Q.__webglTexture,s.TEXTURE0+S)}function ae(P,S){const Q=n.get(P);if(P.version>0&&Q.__version!==P.version){Be(Q,P,S);return}t.bindTexture(s.TEXTURE_2D_ARRAY,Q.__webglTexture,s.TEXTURE0+S)}function j(P,S){const Q=n.get(P);if(P.version>0&&Q.__version!==P.version){Be(Q,P,S);return}t.bindTexture(s.TEXTURE_3D,Q.__webglTexture,s.TEXTURE0+S)}function oe(P,S){const Q=n.get(P);if(P.version>0&&Q.__version!==P.version){U(Q,P,S);return}t.bindTexture(s.TEXTURE_CUBE_MAP,Q.__webglTexture,s.TEXTURE0+S)}const B={[Mr]:s.REPEAT,[Mn]:s.CLAMP_TO_EDGE,[br]:s.MIRRORED_REPEAT},Me={[Gt]:s.NEAREST,[ru]:s.NEAREST_MIPMAP_NEAREST,[Ds]:s.NEAREST_MIPMAP_LINEAR,[Ot]:s.LINEAR,[hr]:s.LINEAR_MIPMAP_NEAREST,[Bn]:s.LINEAR_MIPMAP_LINEAR},be={[ap]:s.NEVER,[fp]:s.ALWAYS,[lp]:s.LESS,[pu]:s.LEQUAL,[cp]:s.EQUAL,[dp]:s.GEQUAL,[up]:s.GREATER,[hp]:s.NOTEQUAL};function Ae(P,S){if(S.type===gn&&e.has("OES_texture_float_linear")===!1&&(S.magFilter===Ot||S.magFilter===hr||S.magFilter===Ds||S.magFilter===Bn||S.minFilter===Ot||S.minFilter===hr||S.minFilter===Ds||S.minFilter===Bn)&&console.warn("THREE.WebGLRenderer: Unable to use linear filtering with floating point textures. OES_texture_float_linear not supported on this device."),s.texParameteri(P,s.TEXTURE_WRAP_S,B[S.wrapS]),s.texParameteri(P,s.TEXTURE_WRAP_T,B[S.wrapT]),(P===s.TEXTURE_3D||P===s.TEXTURE_2D_ARRAY)&&s.texParameteri(P,s.TEXTURE_WRAP_R,B[S.wrapR]),s.texParameteri(P,s.TEXTURE_MAG_FILTER,Me[S.magFilter]),s.texParameteri(P,s.TEXTURE_MIN_FILTER,Me[S.minFilter]),S.compareFunction&&(s.texParameteri(P,s.TEXTURE_COMPARE_MODE,s.COMPARE_REF_TO_TEXTURE),s.texParameteri(P,s.TEXTURE_COMPARE_FUNC,be[S.compareFunction])),e.has("EXT_texture_filter_anisotropic")===!0){if(S.magFilter===Gt||S.minFilter!==Ds&&S.minFilter!==Bn||S.type===gn&&e.has("OES_texture_float_linear")===!1)return;if(S.anisotropy>1||n.get(S).__currentAnisotropy){const Q=e.get("EXT_texture_filter_anisotropic");s.texParameterf(P,Q.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(S.anisotropy,i.getMaxAnisotropy())),n.get(S).__currentAnisotropy=S.anisotropy}}}function ge(P,S){let Q=!1;P.__webglInit===void 0&&(P.__webglInit=!0,S.addEventListener("dispose",A));const pe=S.source;let ce=d.get(pe);ce===void 0&&(ce={},d.set(pe,ce));const ve=G(S);if(ve!==P.__cacheKey){ce[ve]===void 0&&(ce[ve]={texture:s.createTexture(),usedTimes:0},o.memory.textures++,Q=!0),ce[ve].usedTimes++;const Ve=ce[P.__cacheKey];Ve!==void 0&&(ce[P.__cacheKey].usedTimes--,Ve.usedTimes===0&&I(S)),P.__cacheKey=ve,P.__webglTexture=ce[ve].texture}return Q}function Be(P,S,Q){let pe=s.TEXTURE_2D;(S.isDataArrayTexture||S.isCompressedArrayTexture)&&(pe=s.TEXTURE_2D_ARRAY),S.isData3DTexture&&(pe=s.TEXTURE_3D);const ce=ge(P,S),ve=S.source;t.bindTexture(pe,P.__webglTexture,s.TEXTURE0+Q);const Ve=n.get(ve);if(ve.version!==Ve.__version||ce===!0){t.activeTexture(s.TEXTURE0+Q);const Ee=ht.getPrimaries(ht.workingColorSpace),Te=S.colorSpace===ei?null:ht.getPrimaries(S.colorSpace),Qe=S.colorSpace===ei||Ee===Te?s.NONE:s.BROWSER_DEFAULT_WEBGL;s.pixelStorei(s.UNPACK_FLIP_Y_WEBGL,S.flipY),s.pixelStorei(s.UNPACK_PREMULTIPLY_ALPHA_WEBGL,S.premultiplyAlpha),s.pixelStorei(s.UNPACK_ALIGNMENT,S.unpackAlignment),s.pixelStorei(s.UNPACK_COLORSPACE_CONVERSION_WEBGL,Qe);let xe=v(S.image,!1,i.maxTextureSize);xe=k(S,xe);const Oe=r.convert(S.format,S.colorSpace),st=r.convert(S.type);let Je=y(S.internalFormat,Oe,st,S.colorSpace,S.isVideoTexture);Ae(pe,S);let Re;const rt=S.mipmaps,at=S.isVideoTexture!==!0,Rt=Ve.__version===void 0||ce===!0,z=ve.dataReady,Ie=x(S,xe);if(S.isDepthTexture)Je=_(S.format===os,S.type),Rt&&(at?t.texStorage2D(s.TEXTURE_2D,1,Je,xe.width,xe.height):t.texImage2D(s.TEXTURE_2D,0,Je,xe.width,xe.height,0,Oe,st,null));else if(S.isDataTexture)if(rt.length>0){at&&Rt&&t.texStorage2D(s.TEXTURE_2D,Ie,Je,rt[0].width,rt[0].height);for(let de=0,_e=rt.length;de<_e;de++)Re=rt[de],at?z&&t.texSubImage2D(s.TEXTURE_2D,de,0,0,Re.width,Re.height,Oe,st,Re.data):t.texImage2D(s.TEXTURE_2D,de,Je,Re.width,Re.height,0,Oe,st,Re.data);S.generateMipmaps=!1}else at?(Rt&&t.texStorage2D(s.TEXTURE_2D,Ie,Je,xe.width,xe.height),z&&t.texSubImage2D(s.TEXTURE_2D,0,0,0,xe.width,xe.height,Oe,st,xe.data)):t.texImage2D(s.TEXTURE_2D,0,Je,xe.width,xe.height,0,Oe,st,xe.data);else if(S.isCompressedTexture)if(S.isCompressedArrayTexture){at&&Rt&&t.texStorage3D(s.TEXTURE_2D_ARRAY,Ie,Je,rt[0].width,rt[0].height,xe.depth);for(let de=0,_e=rt.length;de<_e;de++)if(Re=rt[de],S.format!==un)if(Oe!==null)if(at){if(z)if(S.layerUpdates.size>0){for(const we of S.layerUpdates){const et=Re.width*Re.height;t.compressedTexSubImage3D(s.TEXTURE_2D_ARRAY,de,0,0,we,Re.width,Re.height,1,Oe,Re.data.slice(et*we,et*(we+1)),0,0)}S.clearLayerUpdates()}else t.compressedTexSubImage3D(s.TEXTURE_2D_ARRAY,de,0,0,0,Re.width,Re.height,xe.depth,Oe,Re.data,0,0)}else t.compressedTexImage3D(s.TEXTURE_2D_ARRAY,de,Je,Re.width,Re.height,xe.depth,0,Re.data,0,0);else console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()");else at?z&&t.texSubImage3D(s.TEXTURE_2D_ARRAY,de,0,0,0,Re.width,Re.height,xe.depth,Oe,st,Re.data):t.texImage3D(s.TEXTURE_2D_ARRAY,de,Je,Re.width,Re.height,xe.depth,0,Oe,st,Re.data)}else{at&&Rt&&t.texStorage2D(s.TEXTURE_2D,Ie,Je,rt[0].width,rt[0].height);for(let de=0,_e=rt.length;de<_e;de++)Re=rt[de],S.format!==un?Oe!==null?at?z&&t.compressedTexSubImage2D(s.TEXTURE_2D,de,0,0,Re.width,Re.height,Oe,Re.data):t.compressedTexImage2D(s.TEXTURE_2D,de,Je,Re.width,Re.height,0,Re.data):console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()"):at?z&&t.texSubImage2D(s.TEXTURE_2D,de,0,0,Re.width,Re.height,Oe,st,Re.data):t.texImage2D(s.TEXTURE_2D,de,Je,Re.width,Re.height,0,Oe,st,Re.data)}else if(S.isDataArrayTexture)if(at){if(Rt&&t.texStorage3D(s.TEXTURE_2D_ARRAY,Ie,Je,xe.width,xe.height,xe.depth),z)if(S.layerUpdates.size>0){let de;switch(st){case s.UNSIGNED_BYTE:switch(Oe){case s.ALPHA:de=1;break;case s.LUMINANCE:de=1;break;case s.LUMINANCE_ALPHA:de=2;break;case s.RGB:de=3;break;case s.RGBA:de=4;break;default:throw new Error(`Unknown texel size for format ${Oe}.`)}break;case s.UNSIGNED_SHORT_4_4_4_4:case s.UNSIGNED_SHORT_5_5_5_1:case s.UNSIGNED_SHORT_5_6_5:de=1;break;default:throw new Error(`Unknown texel size for type ${st}.`)}const _e=xe.width*xe.height*de;for(const we of S.layerUpdates)t.texSubImage3D(s.TEXTURE_2D_ARRAY,0,0,0,we,xe.width,xe.height,1,Oe,st,xe.data.slice(_e*we,_e*(we+1)));S.clearLayerUpdates()}else t.texSubImage3D(s.TEXTURE_2D_ARRAY,0,0,0,0,xe.width,xe.height,xe.depth,Oe,st,xe.data)}else t.texImage3D(s.TEXTURE_2D_ARRAY,0,Je,xe.width,xe.height,xe.depth,0,Oe,st,xe.data);else if(S.isData3DTexture)at?(Rt&&t.texStorage3D(s.TEXTURE_3D,Ie,Je,xe.width,xe.height,xe.depth),z&&t.texSubImage3D(s.TEXTURE_3D,0,0,0,0,xe.width,xe.height,xe.depth,Oe,st,xe.data)):t.texImage3D(s.TEXTURE_3D,0,Je,xe.width,xe.height,xe.depth,0,Oe,st,xe.data);else if(S.isFramebufferTexture){if(Rt)if(at)t.texStorage2D(s.TEXTURE_2D,Ie,Je,xe.width,xe.height);else{let de=xe.width,_e=xe.height;for(let we=0;we>=1,_e>>=1}}else if(rt.length>0){if(at&&Rt){const de=O(rt[0]);t.texStorage2D(s.TEXTURE_2D,Ie,Je,de.width,de.height)}for(let de=0,_e=rt.length;de<_e;de++)Re=rt[de],at?z&&t.texSubImage2D(s.TEXTURE_2D,de,0,0,Oe,st,Re):t.texImage2D(s.TEXTURE_2D,de,Je,Oe,st,Re);S.generateMipmaps=!1}else if(at){if(Rt){const de=O(xe);t.texStorage2D(s.TEXTURE_2D,Ie,Je,de.width,de.height)}z&&t.texSubImage2D(s.TEXTURE_2D,0,0,0,Oe,st,xe)}else t.texImage2D(s.TEXTURE_2D,0,Je,Oe,st,xe);p(S)&&m(pe),Ve.__version=ve.version,S.onUpdate&&S.onUpdate(S)}P.__version=S.version}function U(P,S,Q){if(S.image.length!==6)return;const pe=ge(P,S),ce=S.source;t.bindTexture(s.TEXTURE_CUBE_MAP,P.__webglTexture,s.TEXTURE0+Q);const ve=n.get(ce);if(ce.version!==ve.__version||pe===!0){t.activeTexture(s.TEXTURE0+Q);const Ve=ht.getPrimaries(ht.workingColorSpace),Ee=S.colorSpace===ei?null:ht.getPrimaries(S.colorSpace),Te=S.colorSpace===ei||Ve===Ee?s.NONE:s.BROWSER_DEFAULT_WEBGL;s.pixelStorei(s.UNPACK_FLIP_Y_WEBGL,S.flipY),s.pixelStorei(s.UNPACK_PREMULTIPLY_ALPHA_WEBGL,S.premultiplyAlpha),s.pixelStorei(s.UNPACK_ALIGNMENT,S.unpackAlignment),s.pixelStorei(s.UNPACK_COLORSPACE_CONVERSION_WEBGL,Te);const Qe=S.isCompressedTexture||S.image[0].isCompressedTexture,xe=S.image[0]&&S.image[0].isDataTexture,Oe=[];for(let _e=0;_e<6;_e++)!Qe&&!xe?Oe[_e]=v(S.image[_e],!0,i.maxCubemapSize):Oe[_e]=xe?S.image[_e].image:S.image[_e],Oe[_e]=k(S,Oe[_e]);const st=Oe[0],Je=r.convert(S.format,S.colorSpace),Re=r.convert(S.type),rt=y(S.internalFormat,Je,Re,S.colorSpace),at=S.isVideoTexture!==!0,Rt=ve.__version===void 0||pe===!0,z=ce.dataReady;let Ie=x(S,st);Ae(s.TEXTURE_CUBE_MAP,S);let de;if(Qe){at&&Rt&&t.texStorage2D(s.TEXTURE_CUBE_MAP,Ie,rt,st.width,st.height);for(let _e=0;_e<6;_e++){de=Oe[_e].mipmaps;for(let we=0;we0&&Ie++;const _e=O(Oe[0]);t.texStorage2D(s.TEXTURE_CUBE_MAP,Ie,rt,_e.width,_e.height)}for(let _e=0;_e<6;_e++)if(xe){at?z&&t.texSubImage2D(s.TEXTURE_CUBE_MAP_POSITIVE_X+_e,0,0,0,Oe[_e].width,Oe[_e].height,Je,Re,Oe[_e].data):t.texImage2D(s.TEXTURE_CUBE_MAP_POSITIVE_X+_e,0,rt,Oe[_e].width,Oe[_e].height,0,Je,Re,Oe[_e].data);for(let we=0;we>ve),Oe=Math.max(1,S.height>>ve);ce===s.TEXTURE_3D||ce===s.TEXTURE_2D_ARRAY?t.texImage3D(ce,ve,Te,xe,Oe,S.depth,0,Ve,Ee,null):t.texImage2D(ce,ve,Te,xe,Oe,0,Ve,Ee,null)}t.bindFramebuffer(s.FRAMEBUFFER,P),te(S)?a.framebufferTexture2DMultisampleEXT(s.FRAMEBUFFER,pe,ce,n.get(Q).__webglTexture,0,$(S)):(ce===s.TEXTURE_2D||ce>=s.TEXTURE_CUBE_MAP_POSITIVE_X&&ce<=s.TEXTURE_CUBE_MAP_NEGATIVE_Z)&&s.framebufferTexture2D(s.FRAMEBUFFER,pe,ce,n.get(Q).__webglTexture,ve),t.bindFramebuffer(s.FRAMEBUFFER,null)}function R(P,S,Q){if(s.bindRenderbuffer(s.RENDERBUFFER,P),S.depthBuffer){const pe=S.depthTexture,ce=pe&&pe.isDepthTexture?pe.type:null,ve=_(S.stencilBuffer,ce),Ve=S.stencilBuffer?s.DEPTH_STENCIL_ATTACHMENT:s.DEPTH_ATTACHMENT,Ee=$(S);te(S)?a.renderbufferStorageMultisampleEXT(s.RENDERBUFFER,Ee,ve,S.width,S.height):Q?s.renderbufferStorageMultisample(s.RENDERBUFFER,Ee,ve,S.width,S.height):s.renderbufferStorage(s.RENDERBUFFER,ve,S.width,S.height),s.framebufferRenderbuffer(s.FRAMEBUFFER,Ve,s.RENDERBUFFER,P)}else{const pe=S.textures;for(let ce=0;ce1;if(Ve||(pe.__webglTexture===void 0&&(pe.__webglTexture=s.createTexture()),pe.__version=S.version,o.memory.textures++),ve){Q.__webglFramebuffer=[];for(let Ee=0;Ee<6;Ee++)if(S.mipmaps&&S.mipmaps.length>0){Q.__webglFramebuffer[Ee]=[];for(let Te=0;Te0){Q.__webglFramebuffer=[];for(let Ee=0;Ee0&&te(P)===!1){Q.__webglMultisampledFramebuffer=s.createFramebuffer(),Q.__webglColorRenderbuffer=[],t.bindFramebuffer(s.FRAMEBUFFER,Q.__webglMultisampledFramebuffer);for(let Ee=0;Ee0)for(let Te=0;Te0)for(let Te=0;Te0){if(te(P)===!1){const S=P.textures,Q=P.width,pe=P.height;let ce=s.COLOR_BUFFER_BIT;const ve=P.stencilBuffer?s.DEPTH_STENCIL_ATTACHMENT:s.DEPTH_ATTACHMENT,Ve=n.get(P),Ee=S.length>1;if(Ee)for(let Te=0;Te0&&e.has("WEBGL_multisampled_render_to_texture")===!0&&S.__useRenderToTexture!==!1}function le(P){const S=o.render.frame;u.get(P)!==S&&(u.set(P,S),P.update())}function k(P,S){const Q=P.colorSpace,pe=P.format,ce=P.type;return P.isCompressedTexture===!0||P.isVideoTexture===!0||Q!==ci&&Q!==ei&&(ht.getTransfer(Q)===Mt?(pe!==un||ce!==ai)&&console.warn("THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType."):console.error("THREE.WebGLTextures: Unsupported texture color space:",Q)),S}function O(P){return typeof HTMLImageElement<"u"&&P instanceof HTMLImageElement?(c.width=P.naturalWidth||P.width,c.height=P.naturalHeight||P.height):typeof VideoFrame<"u"&&P instanceof VideoFrame?(c.width=P.displayWidth,c.height=P.displayHeight):(c.width=P.width,c.height=P.height),c}this.allocateTextureUnit=V,this.resetTextureUnits=F,this.setTexture2D=q,this.setTexture2DArray=ae,this.setTexture3D=j,this.setTextureCube=oe,this.rebindTextures=he,this.setupRenderTarget=J,this.updateRenderTargetMipmap=L,this.updateMultisampleRenderTarget=H,this.setupDepthRenderbuffer=ie,this.setupFrameBufferTexture=D,this.useMultisampledRTT=te}function Rp(s,e){function t(n,i=ei){let r;const o=ht.getTransfer(i);if(n===ai)return s.UNSIGNED_BYTE;if(n===au)return s.UNSIGNED_SHORT_4_4_4_4;if(n===lu)return s.UNSIGNED_SHORT_5_5_5_1;if(n===Yf)return s.UNSIGNED_INT_5_9_9_9_REV;if(n===Xf)return s.BYTE;if(n===qf)return s.SHORT;if(n===Sr)return s.UNSIGNED_SHORT;if(n===ou)return s.INT;if(n===ss)return s.UNSIGNED_INT;if(n===gn)return s.FLOAT;if(n===$r)return s.HALF_FLOAT;if(n===Zf)return s.ALPHA;if(n===Jf)return s.RGB;if(n===un)return s.RGBA;if(n===Kf)return s.LUMINANCE;if(n===jf)return s.LUMINANCE_ALPHA;if(n===ts)return s.DEPTH_COMPONENT;if(n===os)return s.DEPTH_STENCIL;if(n===cu)return s.RED;if(n===uu)return s.RED_INTEGER;if(n===Qf)return s.RG;if(n===hu)return s.RG_INTEGER;if(n===du)return s.RGBA_INTEGER;if(n===ra||n===oa||n===aa||n===la)if(o===Mt)if(r=e.get("WEBGL_compressed_texture_s3tc_srgb"),r!==null){if(n===ra)return r.COMPRESSED_SRGB_S3TC_DXT1_EXT;if(n===oa)return r.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;if(n===aa)return r.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;if(n===la)return r.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT}else return null;else if(r=e.get("WEBGL_compressed_texture_s3tc"),r!==null){if(n===ra)return r.COMPRESSED_RGB_S3TC_DXT1_EXT;if(n===oa)return r.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(n===aa)return r.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(n===la)return r.COMPRESSED_RGBA_S3TC_DXT5_EXT}else return null;if(n===oc||n===ac||n===lc||n===cc)if(r=e.get("WEBGL_compressed_texture_pvrtc"),r!==null){if(n===oc)return r.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(n===ac)return r.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(n===lc)return r.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;if(n===cc)return r.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}else return null;if(n===uc||n===hc||n===dc)if(r=e.get("WEBGL_compressed_texture_etc"),r!==null){if(n===uc||n===hc)return o===Mt?r.COMPRESSED_SRGB8_ETC2:r.COMPRESSED_RGB8_ETC2;if(n===dc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:r.COMPRESSED_RGBA8_ETC2_EAC}else return null;if(n===fc||n===pc||n===mc||n===gc||n===vc||n===_c||n===yc||n===xc||n===Mc||n===bc||n===Sc||n===wc||n===Ac||n===Tc)if(r=e.get("WEBGL_compressed_texture_astc"),r!==null){if(n===fc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:r.COMPRESSED_RGBA_ASTC_4x4_KHR;if(n===pc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:r.COMPRESSED_RGBA_ASTC_5x4_KHR;if(n===mc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:r.COMPRESSED_RGBA_ASTC_5x5_KHR;if(n===gc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:r.COMPRESSED_RGBA_ASTC_6x5_KHR;if(n===vc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:r.COMPRESSED_RGBA_ASTC_6x6_KHR;if(n===_c)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:r.COMPRESSED_RGBA_ASTC_8x5_KHR;if(n===yc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:r.COMPRESSED_RGBA_ASTC_8x6_KHR;if(n===xc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:r.COMPRESSED_RGBA_ASTC_8x8_KHR;if(n===Mc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:r.COMPRESSED_RGBA_ASTC_10x5_KHR;if(n===bc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:r.COMPRESSED_RGBA_ASTC_10x6_KHR;if(n===Sc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:r.COMPRESSED_RGBA_ASTC_10x8_KHR;if(n===wc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:r.COMPRESSED_RGBA_ASTC_10x10_KHR;if(n===Ac)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:r.COMPRESSED_RGBA_ASTC_12x10_KHR;if(n===Tc)return o===Mt?r.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:r.COMPRESSED_RGBA_ASTC_12x12_KHR}else return null;if(n===ca||n===Ec||n===Cc)if(r=e.get("EXT_texture_compression_bptc"),r!==null){if(n===ca)return o===Mt?r.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT:r.COMPRESSED_RGBA_BPTC_UNORM_EXT;if(n===Ec)return r.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT;if(n===Cc)return r.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT}else return null;if(n===ep||n===Pc||n===Rc||n===Ic)if(r=e.get("EXT_texture_compression_rgtc"),r!==null){if(n===ca)return r.COMPRESSED_RED_RGTC1_EXT;if(n===Pc)return r.COMPRESSED_SIGNED_RED_RGTC1_EXT;if(n===Rc)return r.COMPRESSED_RED_GREEN_RGTC2_EXT;if(n===Ic)return r.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT}else return null;return n===rs?s.UNSIGNED_INT_24_8:s[n]!==void 0?s[n]:null}return{convert:t}}class Ip extends Ut{constructor(e=[]){super(),this.isArrayCamera=!0,this.cameras=e}}class Fs extends ct{constructor(){super(),this.isGroup=!0,this.type="Group"}}const mA={type:"move"};class Dl{constructor(){this._targetRay=null,this._grip=null,this._hand=null}getHandSpace(){return this._hand===null&&(this._hand=new Fs,this._hand.matrixAutoUpdate=!1,this._hand.visible=!1,this._hand.joints={},this._hand.inputState={pinching:!1}),this._hand}getTargetRaySpace(){return this._targetRay===null&&(this._targetRay=new Fs,this._targetRay.matrixAutoUpdate=!1,this._targetRay.visible=!1,this._targetRay.hasLinearVelocity=!1,this._targetRay.linearVelocity=new N,this._targetRay.hasAngularVelocity=!1,this._targetRay.angularVelocity=new N),this._targetRay}getGripSpace(){return this._grip===null&&(this._grip=new Fs,this._grip.matrixAutoUpdate=!1,this._grip.visible=!1,this._grip.hasLinearVelocity=!1,this._grip.linearVelocity=new N,this._grip.hasAngularVelocity=!1,this._grip.angularVelocity=new N),this._grip}dispatchEvent(e){return this._targetRay!==null&&this._targetRay.dispatchEvent(e),this._grip!==null&&this._grip.dispatchEvent(e),this._hand!==null&&this._hand.dispatchEvent(e),this}connect(e){if(e&&e.hand){const t=this._hand;if(t)for(const n of e.hand.values())this._getHandJoint(t,n)}return this.dispatchEvent({type:"connected",data:e}),this}disconnect(e){return this.dispatchEvent({type:"disconnected",data:e}),this._targetRay!==null&&(this._targetRay.visible=!1),this._grip!==null&&(this._grip.visible=!1),this._hand!==null&&(this._hand.visible=!1),this}update(e,t,n){let i=null,r=null,o=null;const a=this._targetRay,l=this._grip,c=this._hand;if(e&&t.session.visibilityState!=="visible-blurred"){if(c&&e.hand){o=!0;for(const v of e.hand.values()){const p=t.getJointPose(v,n),m=this._getHandJoint(c,v);p!==null&&(m.matrix.fromArray(p.transform.matrix),m.matrix.decompose(m.position,m.rotation,m.scale),m.matrixWorldNeedsUpdate=!0,m.jointRadius=p.radius),m.visible=p!==null}const u=c.joints["index-finger-tip"],h=c.joints["thumb-tip"],d=u.position.distanceTo(h.position),f=.02,g=.005;c.inputState.pinching&&d>f+g?(c.inputState.pinching=!1,this.dispatchEvent({type:"pinchend",handedness:e.handedness,target:this})):!c.inputState.pinching&&d<=f-g&&(c.inputState.pinching=!0,this.dispatchEvent({type:"pinchstart",handedness:e.handedness,target:this}))}else l!==null&&e.gripSpace&&(r=t.getPose(e.gripSpace,n),r!==null&&(l.matrix.fromArray(r.transform.matrix),l.matrix.decompose(l.position,l.rotation,l.scale),l.matrixWorldNeedsUpdate=!0,r.linearVelocity?(l.hasLinearVelocity=!0,l.linearVelocity.copy(r.linearVelocity)):l.hasLinearVelocity=!1,r.angularVelocity?(l.hasAngularVelocity=!0,l.angularVelocity.copy(r.angularVelocity)):l.hasAngularVelocity=!1));a!==null&&(i=t.getPose(e.targetRaySpace,n),i===null&&r!==null&&(i=r),i!==null&&(a.matrix.fromArray(i.transform.matrix),a.matrix.decompose(a.position,a.rotation,a.scale),a.matrixWorldNeedsUpdate=!0,i.linearVelocity?(a.hasLinearVelocity=!0,a.linearVelocity.copy(i.linearVelocity)):a.hasLinearVelocity=!1,i.angularVelocity?(a.hasAngularVelocity=!0,a.angularVelocity.copy(i.angularVelocity)):a.hasAngularVelocity=!1,this.dispatchEvent(mA)))}return a!==null&&(a.visible=i!==null),l!==null&&(l.visible=r!==null),c!==null&&(c.visible=o!==null),this}_getHandJoint(e,t){if(e.joints[t.jointName]===void 0){const n=new Fs;n.matrixAutoUpdate=!1,n.visible=!1,e.joints[t.jointName]=n,e.add(n)}return e.joints[t.jointName]}}const gA=` -void main() { - - gl_Position = vec4( position, 1.0 ); - -}`,vA=` -uniform sampler2DArray depthColor; -uniform float depthWidth; -uniform float depthHeight; - -void main() { - - vec2 coord = vec2( gl_FragCoord.x / depthWidth, gl_FragCoord.y / depthHeight ); - - if ( coord.x >= 1.0 ) { - - gl_FragDepth = texture( depthColor, vec3( coord.x - 1.0, coord.y, 1 ) ).r; - - } else { - - gl_FragDepth = texture( depthColor, vec3( coord.x, coord.y, 0 ) ).r; - - } - -}`;class _A{constructor(){this.texture=null,this.mesh=null,this.depthNear=0,this.depthFar=0}init(e,t,n){if(this.texture===null){const i=new Pt,r=e.properties.get(i);r.__webglTexture=t.texture,(t.depthNear!=n.depthNear||t.depthFar!=n.depthFar)&&(this.depthNear=t.depthNear,this.depthFar=t.depthFar),this.texture=i}}getMesh(e){if(this.texture!==null&&this.mesh===null){const t=e.cameras[0].viewport,n=new Ln({vertexShader:gA,fragmentShader:vA,uniforms:{depthColor:{value:this.texture},depthWidth:{value:t.z},depthHeight:{value:t.w}}});this.mesh=new Nt(new Xs(20,20),n)}return this.mesh}reset(){this.texture=null,this.mesh=null}}class yA extends ui{constructor(e,t){super();const n=this;let i=null,r=1,o=null,a="local-floor",l=1,c=null,u=null,h=null,d=null,f=null,g=null;const v=new _A,p=t.getContextAttributes();let m=null,y=null;const _=[],x=[],A=new se;let b=null;const E=new Ut;E.layers.enable(1),E.viewport=new gt;const I=new Ut;I.layers.enable(2),I.viewport=new gt;const w=[E,I],M=new Ip;M.layers.enable(1),M.layers.enable(2);let F=null,V=null;this.cameraAutoUpdate=!0,this.enabled=!1,this.isPresenting=!1,this.getController=function(U){let D=_[U];return D===void 0&&(D=new Dl,_[U]=D),D.getTargetRaySpace()},this.getControllerGrip=function(U){let D=_[U];return D===void 0&&(D=new Dl,_[U]=D),D.getGripSpace()},this.getHand=function(U){let D=_[U];return D===void 0&&(D=new Dl,_[U]=D),D.getHandSpace()};function G(U){const D=x.indexOf(U.inputSource);if(D===-1)return;const R=_[D];R!==void 0&&(R.update(U.inputSource,U.frame,c||o),R.dispatchEvent({type:U.type,data:U.inputSource}))}function q(){i.removeEventListener("select",G),i.removeEventListener("selectstart",G),i.removeEventListener("selectend",G),i.removeEventListener("squeeze",G),i.removeEventListener("squeezestart",G),i.removeEventListener("squeezeend",G),i.removeEventListener("end",q),i.removeEventListener("inputsourceschange",ae);for(let U=0;U<_.length;U++){const D=x[U];D!==null&&(x[U]=null,_[U].disconnect(D))}F=null,V=null,v.reset(),e.setRenderTarget(m),f=null,d=null,h=null,i=null,y=null,Be.stop(),n.isPresenting=!1,e.setPixelRatio(b),e.setSize(A.width,A.height,!1),n.dispatchEvent({type:"sessionend"})}this.setFramebufferScaleFactor=function(U){r=U,n.isPresenting===!0&&console.warn("THREE.WebXRManager: Cannot change framebuffer scale while presenting.")},this.setReferenceSpaceType=function(U){a=U,n.isPresenting===!0&&console.warn("THREE.WebXRManager: Cannot change reference space type while presenting.")},this.getReferenceSpace=function(){return c||o},this.setReferenceSpace=function(U){c=U},this.getBaseLayer=function(){return d!==null?d:f},this.getBinding=function(){return h},this.getFrame=function(){return g},this.getSession=function(){return i},this.setSession=async function(U){if(i=U,i!==null){if(m=e.getRenderTarget(),i.addEventListener("select",G),i.addEventListener("selectstart",G),i.addEventListener("selectend",G),i.addEventListener("squeeze",G),i.addEventListener("squeezestart",G),i.addEventListener("squeezeend",G),i.addEventListener("end",q),i.addEventListener("inputsourceschange",ae),p.xrCompatible!==!0&&await t.makeXRCompatible(),b=e.getPixelRatio(),e.getSize(A),i.renderState.layers===void 0){const D={antialias:p.antialias,alpha:!0,depth:p.depth,stencil:p.stencil,framebufferScaleFactor:r};f=new XRWebGLLayer(i,t,D),i.updateRenderState({baseLayer:f}),e.setPixelRatio(1),e.setSize(f.framebufferWidth,f.framebufferHeight,!1),y=new In(f.framebufferWidth,f.framebufferHeight,{format:un,type:ai,colorSpace:e.outputColorSpace,stencilBuffer:p.stencil})}else{let D=null,R=null,T=null;p.depth&&(T=p.stencil?t.DEPTH24_STENCIL8:t.DEPTH_COMPONENT24,D=p.stencil?os:ts,R=p.stencil?rs:ss);const ie={colorFormat:t.RGBA8,depthFormat:T,scaleFactor:r};h=new XRWebGLBinding(i,t),d=h.createProjectionLayer(ie),i.updateRenderState({layers:[d]}),e.setPixelRatio(1),e.setSize(d.textureWidth,d.textureHeight,!1),y=new In(d.textureWidth,d.textureHeight,{format:un,type:ai,depthTexture:new Mu(d.textureWidth,d.textureHeight,R,void 0,void 0,void 0,void 0,void 0,void 0,D),stencilBuffer:p.stencil,colorSpace:e.outputColorSpace,samples:p.antialias?4:0,resolveDepthBuffer:d.ignoreDepthValues===!1})}y.isXRRenderTarget=!0,this.setFoveation(l),c=null,o=await i.requestReferenceSpace(a),Be.setContext(i),Be.start(),n.isPresenting=!0,n.dispatchEvent({type:"sessionstart"})}},this.getEnvironmentBlendMode=function(){if(i!==null)return i.environmentBlendMode};function ae(U){for(let D=0;D=0&&(x[T]=null,_[T].disconnect(R))}for(let D=0;D=x.length){x.push(R),T=he;break}else if(x[he]===null){x[he]=R,T=he;break}if(T===-1)break}const ie=_[T];ie&&ie.connect(R)}}const j=new N,oe=new N;function B(U,D,R){j.setFromMatrixPosition(D.matrixWorld),oe.setFromMatrixPosition(R.matrixWorld);const T=j.distanceTo(oe),ie=D.projectionMatrix.elements,he=R.projectionMatrix.elements,J=ie[14]/(ie[10]-1),L=ie[14]/(ie[10]+1),X=(ie[9]+1)/ie[5],K=(ie[9]-1)/ie[5],H=(ie[8]-1)/ie[0],$=(he[8]+1)/he[0],te=J*H,le=J*$,k=T/(-H+$),O=k*-H;D.matrixWorld.decompose(U.position,U.quaternion,U.scale),U.translateX(O),U.translateZ(k),U.matrixWorld.compose(U.position,U.quaternion,U.scale),U.matrixWorldInverse.copy(U.matrixWorld).invert();const P=J+k,S=L+k,Q=te-O,pe=le+(T-O),ce=X*L/S*P,ve=K*L/S*P;U.projectionMatrix.makePerspective(Q,pe,ce,ve,P,S),U.projectionMatrixInverse.copy(U.projectionMatrix).invert()}function Me(U,D){D===null?U.matrixWorld.copy(U.matrix):U.matrixWorld.multiplyMatrices(D.matrixWorld,U.matrix),U.matrixWorldInverse.copy(U.matrixWorld).invert()}this.updateCamera=function(U){if(i===null)return;v.texture!==null&&(U.near=v.depthNear,U.far=v.depthFar),M.near=I.near=E.near=U.near,M.far=I.far=E.far=U.far,(F!==M.near||V!==M.far)&&(i.updateRenderState({depthNear:M.near,depthFar:M.far}),F=M.near,V=M.far,E.near=F,E.far=V,I.near=F,I.far=V,E.updateProjectionMatrix(),I.updateProjectionMatrix(),U.updateProjectionMatrix());const D=U.parent,R=M.cameras;Me(M,D);for(let T=0;T0&&(p.alphaTest.value=m.alphaTest);const y=e.get(m),_=y.envMap,x=y.envMapRotation;_&&(p.envMap.value=_,zi.copy(x),zi.x*=-1,zi.y*=-1,zi.z*=-1,_.isCubeTexture&&_.isRenderTargetTexture===!1&&(zi.y*=-1,zi.z*=-1),p.envMapRotation.value.setFromMatrix4(xA.makeRotationFromEuler(zi)),p.flipEnvMap.value=_.isCubeTexture&&_.isRenderTargetTexture===!1?-1:1,p.reflectivity.value=m.reflectivity,p.ior.value=m.ior,p.refractionRatio.value=m.refractionRatio),m.lightMap&&(p.lightMap.value=m.lightMap,p.lightMapIntensity.value=m.lightMapIntensity,t(m.lightMap,p.lightMapTransform)),m.aoMap&&(p.aoMap.value=m.aoMap,p.aoMapIntensity.value=m.aoMapIntensity,t(m.aoMap,p.aoMapTransform))}function o(p,m){p.diffuse.value.copy(m.color),p.opacity.value=m.opacity,m.map&&(p.map.value=m.map,t(m.map,p.mapTransform))}function a(p,m){p.dashSize.value=m.dashSize,p.totalSize.value=m.dashSize+m.gapSize,p.scale.value=m.scale}function l(p,m,y,_){p.diffuse.value.copy(m.color),p.opacity.value=m.opacity,p.size.value=m.size*y,p.scale.value=_*.5,m.map&&(p.map.value=m.map,t(m.map,p.uvTransform)),m.alphaMap&&(p.alphaMap.value=m.alphaMap,t(m.alphaMap,p.alphaMapTransform)),m.alphaTest>0&&(p.alphaTest.value=m.alphaTest)}function c(p,m){p.diffuse.value.copy(m.color),p.opacity.value=m.opacity,p.rotation.value=m.rotation,m.map&&(p.map.value=m.map,t(m.map,p.mapTransform)),m.alphaMap&&(p.alphaMap.value=m.alphaMap,t(m.alphaMap,p.alphaMapTransform)),m.alphaTest>0&&(p.alphaTest.value=m.alphaTest)}function u(p,m){p.specular.value.copy(m.specular),p.shininess.value=Math.max(m.shininess,1e-4)}function h(p,m){m.gradientMap&&(p.gradientMap.value=m.gradientMap)}function d(p,m){p.metalness.value=m.metalness,m.metalnessMap&&(p.metalnessMap.value=m.metalnessMap,t(m.metalnessMap,p.metalnessMapTransform)),p.roughness.value=m.roughness,m.roughnessMap&&(p.roughnessMap.value=m.roughnessMap,t(m.roughnessMap,p.roughnessMapTransform)),m.envMap&&(p.envMapIntensity.value=m.envMapIntensity)}function f(p,m,y){p.ior.value=m.ior,m.sheen>0&&(p.sheenColor.value.copy(m.sheenColor).multiplyScalar(m.sheen),p.sheenRoughness.value=m.sheenRoughness,m.sheenColorMap&&(p.sheenColorMap.value=m.sheenColorMap,t(m.sheenColorMap,p.sheenColorMapTransform)),m.sheenRoughnessMap&&(p.sheenRoughnessMap.value=m.sheenRoughnessMap,t(m.sheenRoughnessMap,p.sheenRoughnessMapTransform))),m.clearcoat>0&&(p.clearcoat.value=m.clearcoat,p.clearcoatRoughness.value=m.clearcoatRoughness,m.clearcoatMap&&(p.clearcoatMap.value=m.clearcoatMap,t(m.clearcoatMap,p.clearcoatMapTransform)),m.clearcoatRoughnessMap&&(p.clearcoatRoughnessMap.value=m.clearcoatRoughnessMap,t(m.clearcoatRoughnessMap,p.clearcoatRoughnessMapTransform)),m.clearcoatNormalMap&&(p.clearcoatNormalMap.value=m.clearcoatNormalMap,t(m.clearcoatNormalMap,p.clearcoatNormalMapTransform),p.clearcoatNormalScale.value.copy(m.clearcoatNormalScale),m.side===nn&&p.clearcoatNormalScale.value.negate())),m.dispersion>0&&(p.dispersion.value=m.dispersion),m.iridescence>0&&(p.iridescence.value=m.iridescence,p.iridescenceIOR.value=m.iridescenceIOR,p.iridescenceThicknessMinimum.value=m.iridescenceThicknessRange[0],p.iridescenceThicknessMaximum.value=m.iridescenceThicknessRange[1],m.iridescenceMap&&(p.iridescenceMap.value=m.iridescenceMap,t(m.iridescenceMap,p.iridescenceMapTransform)),m.iridescenceThicknessMap&&(p.iridescenceThicknessMap.value=m.iridescenceThicknessMap,t(m.iridescenceThicknessMap,p.iridescenceThicknessMapTransform))),m.transmission>0&&(p.transmission.value=m.transmission,p.transmissionSamplerMap.value=y.texture,p.transmissionSamplerSize.value.set(y.width,y.height),m.transmissionMap&&(p.transmissionMap.value=m.transmissionMap,t(m.transmissionMap,p.transmissionMapTransform)),p.thickness.value=m.thickness,m.thicknessMap&&(p.thicknessMap.value=m.thicknessMap,t(m.thicknessMap,p.thicknessMapTransform)),p.attenuationDistance.value=m.attenuationDistance,p.attenuationColor.value.copy(m.attenuationColor)),m.anisotropy>0&&(p.anisotropyVector.value.set(m.anisotropy*Math.cos(m.anisotropyRotation),m.anisotropy*Math.sin(m.anisotropyRotation)),m.anisotropyMap&&(p.anisotropyMap.value=m.anisotropyMap,t(m.anisotropyMap,p.anisotropyMapTransform))),p.specularIntensity.value=m.specularIntensity,p.specularColor.value.copy(m.specularColor),m.specularColorMap&&(p.specularColorMap.value=m.specularColorMap,t(m.specularColorMap,p.specularColorMapTransform)),m.specularIntensityMap&&(p.specularIntensityMap.value=m.specularIntensityMap,t(m.specularIntensityMap,p.specularIntensityMapTransform))}function g(p,m){m.matcap&&(p.matcap.value=m.matcap)}function v(p,m){const y=e.get(m).light;p.referencePosition.value.setFromMatrixPosition(y.matrixWorld),p.nearDistance.value=y.shadow.camera.near,p.farDistance.value=y.shadow.camera.far}return{refreshFogUniforms:n,refreshMaterialUniforms:i}}function bA(s,e,t,n){let i={},r={},o=[];const a=s.getParameter(s.MAX_UNIFORM_BUFFER_BINDINGS);function l(y,_){const x=_.program;n.uniformBlockBinding(y,x)}function c(y,_){let x=i[y.id];x===void 0&&(g(y),x=u(y),i[y.id]=x,y.addEventListener("dispose",p));const A=_.program;n.updateUBOMapping(y,A);const b=e.render.frame;r[y.id]!==b&&(d(y),r[y.id]=b)}function u(y){const _=h();y.__bindingPointIndex=_;const x=s.createBuffer(),A=y.__size,b=y.usage;return s.bindBuffer(s.UNIFORM_BUFFER,x),s.bufferData(s.UNIFORM_BUFFER,A,b),s.bindBuffer(s.UNIFORM_BUFFER,null),s.bindBufferBase(s.UNIFORM_BUFFER,_,x),x}function h(){for(let y=0;y0&&(x+=A-b),y.__size=x,y.__cache={},this}function v(y){const _={boundary:0,storage:0};return typeof y=="number"||typeof y=="boolean"?(_.boundary=4,_.storage=4):y.isVector2?(_.boundary=8,_.storage=8):y.isVector3||y.isColor?(_.boundary=16,_.storage=12):y.isVector4?(_.boundary=16,_.storage=16):y.isMatrix3?(_.boundary=48,_.storage=48):y.isMatrix4?(_.boundary=64,_.storage=64):y.isTexture?console.warn("THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group."):console.warn("THREE.WebGLRenderer: Unsupported uniform value type.",y),_}function p(y){const _=y.target;_.removeEventListener("dispose",p);const x=o.indexOf(_.__bindingPointIndex);o.splice(x,1),s.deleteBuffer(i[_.id]),delete i[_.id],delete r[_.id]}function m(){for(const y in i)s.deleteBuffer(i[y]);o=[],i={},r={}}return{bind:l,update:c,dispose:m}}class da{constructor(e={}){const{canvas:t=gp(),context:n=null,depth:i=!0,stencil:r=!1,alpha:o=!1,antialias:a=!1,premultipliedAlpha:l=!0,preserveDrawingBuffer:c=!1,powerPreference:u="default",failIfMajorPerformanceCaveat:h=!1}=e;this.isWebGLRenderer=!0;let d;if(n!==null){if(typeof WebGLRenderingContext<"u"&&n instanceof WebGLRenderingContext)throw new Error("THREE.WebGLRenderer: WebGL 1 is not supported since r163.");d=n.getContextAttributes().alpha}else d=o;const f=new Uint32Array(4),g=new Int32Array(4);let v=null,p=null;const m=[],y=[];this.domElement=t,this.debug={checkShaderErrors:!0,onShaderError:null},this.autoClear=!0,this.autoClearColor=!0,this.autoClearDepth=!0,this.autoClearStencil=!0,this.sortObjects=!0,this.clippingPlanes=[],this.localClippingEnabled=!1,this._outputColorSpace=ln,this.toneMapping=Hn,this.toneMappingExposure=1;const _=this;let x=!1,A=0,b=0,E=null,I=-1,w=null;const M=new gt,F=new gt;let V=null;const G=new Pe(0);let q=0,ae=t.width,j=t.height,oe=1,B=null,Me=null;const be=new gt(0,0,ae,j),Ae=new gt(0,0,ae,j);let ge=!1;const Be=new Zr;let U=!1,D=!1;const R=new qe,T=new N,ie={background:null,fog:null,environment:null,overrideMaterial:null,isScene:!0};let he=!1;function J(){return E===null?oe:1}let L=n;function X(C,W){return t.getContext(C,W)}try{const C={alpha:!0,depth:i,stencil:r,antialias:a,premultipliedAlpha:l,preserveDrawingBuffer:c,powerPreference:u,failIfMajorPerformanceCaveat:h};if("setAttribute"in t&&t.setAttribute("data-engine",`three.js r${Gr}`),t.addEventListener("webglcontextlost",Ie,!1),t.addEventListener("webglcontextrestored",de,!1),t.addEventListener("webglcontextcreationerror",_e,!1),L===null){const W="webgl2";if(L=X(W,C),L===null)throw X(W)?new Error("Error creating WebGL context with your selected attributes."):new Error("Error creating WebGL context.")}}catch(C){throw console.error("THREE.WebGLRenderer: "+C.message),C}let K,H,$,te,le,k,O,P,S,Q,pe,ce,ve,Ve,Ee,Te,Qe,xe,Oe,st,Je,Re,rt,at;function Rt(){K=new Uw(L),K.init(),Re=new Rp(L,K),H=new Pw(L,K,e,Re),$=new fA(L),te=new kw(L),le=new tA,k=new pA(L,K,$,le,H,Re,te),O=new Iw(_),P=new Dw(_),S=new $M(L),rt=new Ew(L,S),Q=new Ow(L,S,te,rt),pe=new zw(L,Q,S,te),Oe=new Bw(L,H,k),Te=new Rw(le),ce=new eA(_,O,P,K,H,rt,Te),ve=new MA(_,le),Ve=new iA,Ee=new cA(K),xe=new Tw(_,O,P,$,pe,d,l),Qe=new dA(_,pe,H),at=new bA(L,te,H,$),st=new Cw(L,K,te),Je=new Fw(L,K,te),te.programs=ce.programs,_.capabilities=H,_.extensions=K,_.properties=le,_.renderLists=Ve,_.shadowMap=Qe,_.state=$,_.info=te}Rt();const z=new yA(_,L);this.xr=z,this.getContext=function(){return L},this.getContextAttributes=function(){return L.getContextAttributes()},this.forceContextLoss=function(){const C=K.get("WEBGL_lose_context");C&&C.loseContext()},this.forceContextRestore=function(){const C=K.get("WEBGL_lose_context");C&&C.restoreContext()},this.getPixelRatio=function(){return oe},this.setPixelRatio=function(C){C!==void 0&&(oe=C,this.setSize(ae,j,!1))},this.getSize=function(C){return C.set(ae,j)},this.setSize=function(C,W,ne=!0){if(z.isPresenting){console.warn("THREE.WebGLRenderer: Can't change size while VR device is presenting.");return}ae=C,j=W,t.width=Math.floor(C*oe),t.height=Math.floor(W*oe),ne===!0&&(t.style.width=C+"px",t.style.height=W+"px"),this.setViewport(0,0,C,W)},this.getDrawingBufferSize=function(C){return C.set(ae*oe,j*oe).floor()},this.setDrawingBufferSize=function(C,W,ne){ae=C,j=W,oe=ne,t.width=Math.floor(C*ne),t.height=Math.floor(W*ne),this.setViewport(0,0,C,W)},this.getCurrentViewport=function(C){return C.copy(M)},this.getViewport=function(C){return C.copy(be)},this.setViewport=function(C,W,ne,re){C.isVector4?be.set(C.x,C.y,C.z,C.w):be.set(C,W,ne,re),$.viewport(M.copy(be).multiplyScalar(oe).round())},this.getScissor=function(C){return C.copy(Ae)},this.setScissor=function(C,W,ne,re){C.isVector4?Ae.set(C.x,C.y,C.z,C.w):Ae.set(C,W,ne,re),$.scissor(F.copy(Ae).multiplyScalar(oe).round())},this.getScissorTest=function(){return ge},this.setScissorTest=function(C){$.setScissorTest(ge=C)},this.setOpaqueSort=function(C){B=C},this.setTransparentSort=function(C){Me=C},this.getClearColor=function(C){return C.copy(xe.getClearColor())},this.setClearColor=function(){xe.setClearColor.apply(xe,arguments)},this.getClearAlpha=function(){return xe.getClearAlpha()},this.setClearAlpha=function(){xe.setClearAlpha.apply(xe,arguments)},this.clear=function(C=!0,W=!0,ne=!0){let re=0;if(C){let Z=!1;if(E!==null){const Se=E.texture.format;Z=Se===du||Se===hu||Se===uu}if(Z){const Se=E.texture.type,Le=Se===ai||Se===ss||Se===Sr||Se===rs||Se===au||Se===lu,Fe=xe.getClearColor(),He=xe.getClearAlpha(),Ke=Fe.r,je=Fe.g,Xe=Fe.b;Le?(f[0]=Ke,f[1]=je,f[2]=Xe,f[3]=He,L.clearBufferuiv(L.COLOR,0,f)):(g[0]=Ke,g[1]=je,g[2]=Xe,g[3]=He,L.clearBufferiv(L.COLOR,0,g))}else re|=L.COLOR_BUFFER_BIT}W&&(re|=L.DEPTH_BUFFER_BIT),ne&&(re|=L.STENCIL_BUFFER_BIT,this.state.buffers.stencil.setMask(4294967295)),L.clear(re)},this.clearColor=function(){this.clear(!0,!1,!1)},this.clearDepth=function(){this.clear(!1,!0,!1)},this.clearStencil=function(){this.clear(!1,!1,!0)},this.dispose=function(){t.removeEventListener("webglcontextlost",Ie,!1),t.removeEventListener("webglcontextrestored",de,!1),t.removeEventListener("webglcontextcreationerror",_e,!1),Ve.dispose(),Ee.dispose(),le.dispose(),O.dispose(),P.dispose(),pe.dispose(),rt.dispose(),at.dispose(),ce.dispose(),z.dispose(),z.removeEventListener("sessionstart",On),z.removeEventListener("sessionend",Fn),Ni.stop()};function Ie(C){C.preventDefault(),console.log("THREE.WebGLRenderer: Context Lost."),x=!0}function de(){console.log("THREE.WebGLRenderer: Context Restored."),x=!1;const C=te.autoReset,W=Qe.enabled,ne=Qe.autoUpdate,re=Qe.needsUpdate,Z=Qe.type;Rt(),te.autoReset=C,Qe.enabled=W,Qe.autoUpdate=ne,Qe.needsUpdate=re,Qe.type=Z}function _e(C){console.error("THREE.WebGLRenderer: A WebGL context could not be created. Reason: ",C.statusMessage)}function we(C){const W=C.target;W.removeEventListener("dispose",we),et(W)}function et(C){ut(C),le.remove(C)}function ut(C){const W=le.get(C).programs;W!==void 0&&(W.forEach(function(ne){ce.releaseProgram(ne)}),C.isShaderMaterial&&ce.releaseShaderCache(C))}this.renderBufferDirect=function(C,W,ne,re,Z,Se){W===null&&(W=ie);const Le=Z.isMesh&&Z.matrixWorld.determinant()<0,Fe=Fm(C,W,ne,re,Z);$.setMaterial(re,Le);let He=ne.index,Ke=1;if(re.wireframe===!0){if(He=Q.getWireframeAttribute(ne),He===void 0)return;Ke=2}const je=ne.drawRange,Xe=ne.attributes.position;let dt=je.start*Ke,At=(je.start+je.count)*Ke;Se!==null&&(dt=Math.max(dt,Se.start*Ke),At=Math.min(At,(Se.start+Se.count)*Ke)),He!==null?(dt=Math.max(dt,0),At=Math.min(At,He.count)):Xe!=null&&(dt=Math.max(dt,0),At=Math.min(At,Xe.count));const Tt=At-dt;if(Tt<0||Tt===1/0)return;rt.setup(Z,re,Fe,ne,He);let dn,mt=st;if(He!==null&&(dn=S.get(He),mt=Je,mt.setIndex(dn)),Z.isMesh)re.wireframe===!0?($.setLineWidth(re.wireframeLinewidth*J()),mt.setMode(L.LINES)):mt.setMode(L.TRIANGLES);else if(Z.isLine){let We=re.linewidth;We===void 0&&(We=1),$.setLineWidth(We*J()),Z.isLineSegments?mt.setMode(L.LINES):Z.isLineLoop?mt.setMode(L.LINE_LOOP):mt.setMode(L.LINE_STRIP)}else Z.isPoints?mt.setMode(L.POINTS):Z.isSprite&&mt.setMode(L.TRIANGLES);if(Z.isBatchedMesh)Z._multiDrawInstances!==null?mt.renderMultiDrawInstances(Z._multiDrawStarts,Z._multiDrawCounts,Z._multiDrawCount,Z._multiDrawInstances):mt.renderMultiDraw(Z._multiDrawStarts,Z._multiDrawCounts,Z._multiDrawCount);else if(Z.isInstancedMesh)mt.renderInstances(dt,Tt,Z.count);else if(ne.isInstancedBufferGeometry){const We=ne._maxInstanceCount!==void 0?ne._maxInstanceCount:1/0,jt=Math.min(ne.instanceCount,We);mt.renderInstances(dt,Tt,jt)}else mt.render(dt,Tt)};function It(C,W,ne){C.transparent===!0&&C.side===En&&C.forceSinglePass===!1?(C.side=nn,C.needsUpdate=!0,so(C,W,ne),C.side=ri,C.needsUpdate=!0,so(C,W,ne),C.side=En):so(C,W,ne)}this.compile=function(C,W,ne=null){ne===null&&(ne=C),p=Ee.get(ne),p.init(W),y.push(p),ne.traverseVisible(function(Z){Z.isLight&&Z.layers.test(W.layers)&&(p.pushLight(Z),Z.castShadow&&p.pushShadow(Z))}),C!==ne&&C.traverseVisible(function(Z){Z.isLight&&Z.layers.test(W.layers)&&(p.pushLight(Z),Z.castShadow&&p.pushShadow(Z))}),p.setupLights();const re=new Set;return C.traverse(function(Z){const Se=Z.material;if(Se)if(Array.isArray(Se))for(let Le=0;Le{function Se(){if(re.forEach(function(Le){le.get(Le).currentProgram.isReady()&&re.delete(Le)}),re.size===0){Z(C);return}setTimeout(Se,10)}K.get("KHR_parallel_shader_compile")!==null?Se():setTimeout(Se,10)})};let Bt=null;function vt(C){Bt&&Bt(C)}function On(){Ni.stop()}function Fn(){Ni.start()}const Ni=new wp;Ni.setAnimationLoop(vt),typeof self<"u"&&Ni.setContext(self),this.setAnimationLoop=function(C){Bt=C,z.setAnimationLoop(C),C===null?Ni.stop():Ni.start()},z.addEventListener("sessionstart",On),z.addEventListener("sessionend",Fn),this.render=function(C,W){if(W!==void 0&&W.isCamera!==!0){console.error("THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.");return}if(x===!0)return;if(C.matrixWorldAutoUpdate===!0&&C.updateMatrixWorld(),W.parent===null&&W.matrixWorldAutoUpdate===!0&&W.updateMatrixWorld(),z.enabled===!0&&z.isPresenting===!0&&(z.cameraAutoUpdate===!0&&z.updateCamera(W),W=z.getCamera()),C.isScene===!0&&C.onBeforeRender(_,C,W,E),p=Ee.get(C,y.length),p.init(W),y.push(p),R.multiplyMatrices(W.projectionMatrix,W.matrixWorldInverse),Be.setFromProjectionMatrix(R),D=this.localClippingEnabled,U=Te.init(this.clippingPlanes,D),v=Ve.get(C,m.length),v.init(),m.push(v),z.enabled===!0&&z.isPresenting===!0){const Se=_.xr.getDepthSensingMesh();Se!==null&&rl(Se,W,-1/0,_.sortObjects)}rl(C,W,0,_.sortObjects),v.finish(),_.sortObjects===!0&&v.sort(B,Me),he=z.enabled===!1||z.isPresenting===!1||z.hasDepthSensing()===!1,he&&xe.addToRenderList(v,C),this.info.render.frame++,U===!0&&Te.beginShadows();const ne=p.state.shadowsArray;Qe.render(ne,C,W),U===!0&&Te.endShadows(),this.info.autoReset===!0&&this.info.reset();const re=v.opaque,Z=v.transmissive;if(p.setupLights(),W.isArrayCamera){const Se=W.cameras;if(Z.length>0)for(let Le=0,Fe=Se.length;Le0&&Zu(re,Z,C,W),he&&xe.render(C),Yu(v,C,W);E!==null&&(k.updateMultisampleRenderTarget(E),k.updateRenderTargetMipmap(E)),C.isScene===!0&&C.onAfterRender(_,C,W),rt.resetDefaultState(),I=-1,w=null,y.pop(),y.length>0?(p=y[y.length-1],U===!0&&Te.setGlobalState(_.clippingPlanes,p.state.camera)):p=null,m.pop(),m.length>0?v=m[m.length-1]:v=null};function rl(C,W,ne,re){if(C.visible===!1)return;if(C.layers.test(W.layers)){if(C.isGroup)ne=C.renderOrder;else if(C.isLOD)C.autoUpdate===!0&&C.update(W);else if(C.isLight)p.pushLight(C),C.castShadow&&p.pushShadow(C);else if(C.isSprite){if(!C.frustumCulled||Be.intersectsSprite(C)){re&&T.setFromMatrixPosition(C.matrixWorld).applyMatrix4(R);const Le=pe.update(C),Fe=C.material;Fe.visible&&v.push(C,Le,Fe,ne,T.z,null)}}else if((C.isMesh||C.isLine||C.isPoints)&&(!C.frustumCulled||Be.intersectsObject(C))){const Le=pe.update(C),Fe=C.material;if(re&&(C.boundingSphere!==void 0?(C.boundingSphere===null&&C.computeBoundingSphere(),T.copy(C.boundingSphere.center)):(Le.boundingSphere===null&&Le.computeBoundingSphere(),T.copy(Le.boundingSphere.center)),T.applyMatrix4(C.matrixWorld).applyMatrix4(R)),Array.isArray(Fe)){const He=Le.groups;for(let Ke=0,je=He.length;Ke0&&io(Z,W,ne),Se.length>0&&io(Se,W,ne),Le.length>0&&io(Le,W,ne),$.buffers.depth.setTest(!0),$.buffers.depth.setMask(!0),$.buffers.color.setMask(!0),$.setPolygonOffset(!1)}function Zu(C,W,ne,re){if((ne.isScene===!0?ne.overrideMaterial:null)!==null)return;p.state.transmissionRenderTarget[re.id]===void 0&&(p.state.transmissionRenderTarget[re.id]=new In(1,1,{generateMipmaps:!0,type:K.has("EXT_color_buffer_half_float")||K.has("EXT_color_buffer_float")?$r:ai,minFilter:Bn,samples:4,stencilBuffer:r,resolveDepthBuffer:!1,resolveStencilBuffer:!1,colorSpace:ht.workingColorSpace}));const Se=p.state.transmissionRenderTarget[re.id],Le=re.viewport||M;Se.setSize(Le.z,Le.w);const Fe=_.getRenderTarget();_.setRenderTarget(Se),_.getClearColor(G),q=_.getClearAlpha(),q<1&&_.setClearColor(16777215,.5),he?xe.render(ne):_.clear();const He=_.toneMapping;_.toneMapping=Hn;const Ke=re.viewport;if(re.viewport!==void 0&&(re.viewport=void 0),p.setupLightsView(re),U===!0&&Te.setGlobalState(_.clippingPlanes,re),io(C,ne,re),k.updateMultisampleRenderTarget(Se),k.updateRenderTargetMipmap(Se),K.has("WEBGL_multisampled_render_to_texture")===!1){let je=!1;for(let Xe=0,dt=W.length;Xe0),Xe=!!ne.morphAttributes.position,dt=!!ne.morphAttributes.normal,At=!!ne.morphAttributes.color;let Tt=Hn;re.toneMapped&&(E===null||E.isXRRenderTarget===!0)&&(Tt=_.toneMapping);const dn=ne.morphAttributes.position||ne.morphAttributes.normal||ne.morphAttributes.color,mt=dn!==void 0?dn.length:0,We=le.get(re),jt=p.state.lights;if(U===!0&&(D===!0||C!==w)){const yn=C===w&&re.id===I;Te.setState(re,C,yn)}let _t=!1;re.version===We.__version?(We.needsLights&&We.lightsStateVersion!==jt.state.version||We.outputColorSpace!==Fe||Z.isBatchedMesh&&We.batching===!1||!Z.isBatchedMesh&&We.batching===!0||Z.isBatchedMesh&&We.batchingColor===!0&&Z.colorTexture===null||Z.isBatchedMesh&&We.batchingColor===!1&&Z.colorTexture!==null||Z.isInstancedMesh&&We.instancing===!1||!Z.isInstancedMesh&&We.instancing===!0||Z.isSkinnedMesh&&We.skinning===!1||!Z.isSkinnedMesh&&We.skinning===!0||Z.isInstancedMesh&&We.instancingColor===!0&&Z.instanceColor===null||Z.isInstancedMesh&&We.instancingColor===!1&&Z.instanceColor!==null||Z.isInstancedMesh&&We.instancingMorph===!0&&Z.morphTexture===null||Z.isInstancedMesh&&We.instancingMorph===!1&&Z.morphTexture!==null||We.envMap!==He||re.fog===!0&&We.fog!==Se||We.numClippingPlanes!==void 0&&(We.numClippingPlanes!==Te.numPlanes||We.numIntersection!==Te.numIntersection)||We.vertexAlphas!==Ke||We.vertexTangents!==je||We.morphTargets!==Xe||We.morphNormals!==dt||We.morphColors!==At||We.toneMapping!==Tt||We.morphTargetsCount!==mt)&&(_t=!0):(_t=!0,We.__version=re.version);let qn=We.currentProgram;_t===!0&&(qn=so(re,W,Z));let ro=!1,Di=!1,ol=!1;const zt=qn.getUniforms(),fi=We.uniforms;if($.useProgram(qn.program)&&(ro=!0,Di=!0,ol=!0),re.id!==I&&(I=re.id,Di=!0),ro||w!==C){zt.setValue(L,"projectionMatrix",C.projectionMatrix),zt.setValue(L,"viewMatrix",C.matrixWorldInverse);const yn=zt.map.cameraPosition;yn!==void 0&&yn.setValue(L,T.setFromMatrixPosition(C.matrixWorld)),H.logarithmicDepthBuffer&&zt.setValue(L,"logDepthBufFC",2/(Math.log(C.far+1)/Math.LN2)),(re.isMeshPhongMaterial||re.isMeshToonMaterial||re.isMeshLambertMaterial||re.isMeshBasicMaterial||re.isMeshStandardMaterial||re.isShaderMaterial)&&zt.setValue(L,"isOrthographic",C.isOrthographicCamera===!0),w!==C&&(w=C,Di=!0,ol=!0)}if(Z.isSkinnedMesh){zt.setOptional(L,Z,"bindMatrix"),zt.setOptional(L,Z,"bindMatrixInverse");const yn=Z.skeleton;yn&&(yn.boneTexture===null&&yn.computeBoneTexture(),zt.setValue(L,"boneTexture",yn.boneTexture,k))}Z.isBatchedMesh&&(zt.setOptional(L,Z,"batchingTexture"),zt.setValue(L,"batchingTexture",Z._matricesTexture,k),zt.setOptional(L,Z,"batchingColorTexture"),Z._colorsTexture!==null&&zt.setValue(L,"batchingColorTexture",Z._colorsTexture,k));const al=ne.morphAttributes;if((al.position!==void 0||al.normal!==void 0||al.color!==void 0)&&Oe.update(Z,ne,qn),(Di||We.receiveShadow!==Z.receiveShadow)&&(We.receiveShadow=Z.receiveShadow,zt.setValue(L,"receiveShadow",Z.receiveShadow)),re.isMeshGouraudMaterial&&re.envMap!==null&&(fi.envMap.value=He,fi.flipEnvMap.value=He.isCubeTexture&&He.isRenderTargetTexture===!1?-1:1),re.isMeshStandardMaterial&&re.envMap===null&&W.environment!==null&&(fi.envMapIntensity.value=W.environmentIntensity),Di&&(zt.setValue(L,"toneMappingExposure",_.toneMappingExposure),We.needsLights&&km(fi,ol),Se&&re.fog===!0&&ve.refreshFogUniforms(fi,Se),ve.refreshMaterialUniforms(fi,re,oe,j,p.state.transmissionRenderTarget[C.id]),ha.upload(L,Ku(We),fi,k)),re.isShaderMaterial&&re.uniformsNeedUpdate===!0&&(ha.upload(L,Ku(We),fi,k),re.uniformsNeedUpdate=!1),re.isSpriteMaterial&&zt.setValue(L,"center",Z.center),zt.setValue(L,"modelViewMatrix",Z.modelViewMatrix),zt.setValue(L,"normalMatrix",Z.normalMatrix),zt.setValue(L,"modelMatrix",Z.matrixWorld),re.isShaderMaterial||re.isRawShaderMaterial){const yn=re.uniformsGroups;for(let ll=0,zm=yn.length;ll0&&k.useMultisampledRTT(C)===!1?Z=le.get(C).__webglMultisampledFramebuffer:Array.isArray(je)?Z=je[ne]:Z=je,M.copy(C.viewport),F.copy(C.scissor),V=C.scissorTest}else M.copy(be).multiplyScalar(oe).floor(),F.copy(Ae).multiplyScalar(oe).floor(),V=ge;if($.bindFramebuffer(L.FRAMEBUFFER,Z)&&re&&$.drawBuffers(C,Z),$.viewport(M),$.scissor(F),$.setScissorTest(V),Se){const He=le.get(C.texture);L.framebufferTexture2D(L.FRAMEBUFFER,L.COLOR_ATTACHMENT0,L.TEXTURE_CUBE_MAP_POSITIVE_X+W,He.__webglTexture,ne)}else if(Le){const He=le.get(C.texture),Ke=W||0;L.framebufferTextureLayer(L.FRAMEBUFFER,L.COLOR_ATTACHMENT0,He.__webglTexture,ne||0,Ke)}I=-1},this.readRenderTargetPixels=function(C,W,ne,re,Z,Se,Le){if(!(C&&C.isWebGLRenderTarget)){console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");return}let Fe=le.get(C).__webglFramebuffer;if(C.isWebGLCubeRenderTarget&&Le!==void 0&&(Fe=Fe[Le]),Fe){$.bindFramebuffer(L.FRAMEBUFFER,Fe);try{const He=C.texture,Ke=He.format,je=He.type;if(!H.textureFormatReadable(Ke)){console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.");return}if(!H.textureTypeReadable(je)){console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.");return}W>=0&&W<=C.width-re&&ne>=0&&ne<=C.height-Z&&L.readPixels(W,ne,re,Z,Re.convert(Ke),Re.convert(je),Se)}finally{const He=E!==null?le.get(E).__webglFramebuffer:null;$.bindFramebuffer(L.FRAMEBUFFER,He)}}},this.readRenderTargetPixelsAsync=async function(C,W,ne,re,Z,Se,Le){if(!(C&&C.isWebGLRenderTarget))throw new Error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");let Fe=le.get(C).__webglFramebuffer;if(C.isWebGLCubeRenderTarget&&Le!==void 0&&(Fe=Fe[Le]),Fe){$.bindFramebuffer(L.FRAMEBUFFER,Fe);try{const He=C.texture,Ke=He.format,je=He.type;if(!H.textureFormatReadable(Ke))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.");if(!H.textureTypeReadable(je))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.");if(W>=0&&W<=C.width-re&&ne>=0&&ne<=C.height-Z){const Xe=L.createBuffer();L.bindBuffer(L.PIXEL_PACK_BUFFER,Xe),L.bufferData(L.PIXEL_PACK_BUFFER,Se.byteLength,L.STREAM_READ),L.readPixels(W,ne,re,Z,Re.convert(Ke),Re.convert(je),0),L.flush();const dt=L.fenceSync(L.SYNC_GPU_COMMANDS_COMPLETE,0);await gM(L,dt,4);try{L.bindBuffer(L.PIXEL_PACK_BUFFER,Xe),L.getBufferSubData(L.PIXEL_PACK_BUFFER,0,Se)}finally{L.deleteBuffer(Xe),L.deleteSync(dt)}return Se}}finally{const He=E!==null?le.get(E).__webglFramebuffer:null;$.bindFramebuffer(L.FRAMEBUFFER,He)}}},this.copyFramebufferToTexture=function(C,W=null,ne=0){C.isTexture!==!0&&(console.warn("WebGLRenderer: copyFramebufferToTexture function signature has changed."),W=arguments[0]||null,C=arguments[1]);const re=Math.pow(2,-ne),Z=Math.floor(C.image.width*re),Se=Math.floor(C.image.height*re),Le=W!==null?W.x:0,Fe=W!==null?W.y:0;k.setTexture2D(C,0),L.copyTexSubImage2D(L.TEXTURE_2D,ne,0,0,Le,Fe,Z,Se),$.unbindTexture()},this.copyTextureToTexture=function(C,W,ne=null,re=null,Z=0){C.isTexture!==!0&&(console.warn("WebGLRenderer: copyTextureToTexture function signature has changed."),re=arguments[0]||null,C=arguments[1],W=arguments[2],Z=arguments[3]||0,ne=null);let Se,Le,Fe,He,Ke,je;ne!==null?(Se=ne.max.x-ne.min.x,Le=ne.max.y-ne.min.y,Fe=ne.min.x,He=ne.min.y):(Se=C.image.width,Le=C.image.height,Fe=0,He=0),re!==null?(Ke=re.x,je=re.y):(Ke=0,je=0);const Xe=Re.convert(W.format),dt=Re.convert(W.type);k.setTexture2D(W,0),L.pixelStorei(L.UNPACK_FLIP_Y_WEBGL,W.flipY),L.pixelStorei(L.UNPACK_PREMULTIPLY_ALPHA_WEBGL,W.premultiplyAlpha),L.pixelStorei(L.UNPACK_ALIGNMENT,W.unpackAlignment);const At=L.getParameter(L.UNPACK_ROW_LENGTH),Tt=L.getParameter(L.UNPACK_IMAGE_HEIGHT),dn=L.getParameter(L.UNPACK_SKIP_PIXELS),mt=L.getParameter(L.UNPACK_SKIP_ROWS),We=L.getParameter(L.UNPACK_SKIP_IMAGES),jt=C.isCompressedTexture?C.mipmaps[Z]:C.image;L.pixelStorei(L.UNPACK_ROW_LENGTH,jt.width),L.pixelStorei(L.UNPACK_IMAGE_HEIGHT,jt.height),L.pixelStorei(L.UNPACK_SKIP_PIXELS,Fe),L.pixelStorei(L.UNPACK_SKIP_ROWS,He),C.isDataTexture?L.texSubImage2D(L.TEXTURE_2D,Z,Ke,je,Se,Le,Xe,dt,jt.data):C.isCompressedTexture?L.compressedTexSubImage2D(L.TEXTURE_2D,Z,Ke,je,jt.width,jt.height,Xe,jt.data):L.texSubImage2D(L.TEXTURE_2D,Z,Ke,je,Xe,dt,jt),L.pixelStorei(L.UNPACK_ROW_LENGTH,At),L.pixelStorei(L.UNPACK_IMAGE_HEIGHT,Tt),L.pixelStorei(L.UNPACK_SKIP_PIXELS,dn),L.pixelStorei(L.UNPACK_SKIP_ROWS,mt),L.pixelStorei(L.UNPACK_SKIP_IMAGES,We),Z===0&&W.generateMipmaps&&L.generateMipmap(L.TEXTURE_2D),$.unbindTexture()},this.copyTextureToTexture3D=function(C,W,ne=null,re=null,Z=0){C.isTexture!==!0&&(console.warn("WebGLRenderer: copyTextureToTexture3D function signature has changed."),ne=arguments[0]||null,re=arguments[1]||null,C=arguments[2],W=arguments[3],Z=arguments[4]||0);let Se,Le,Fe,He,Ke,je,Xe,dt,At;const Tt=C.isCompressedTexture?C.mipmaps[Z]:C.image;ne!==null?(Se=ne.max.x-ne.min.x,Le=ne.max.y-ne.min.y,Fe=ne.max.z-ne.min.z,He=ne.min.x,Ke=ne.min.y,je=ne.min.z):(Se=Tt.width,Le=Tt.height,Fe=Tt.depth,He=0,Ke=0,je=0),re!==null?(Xe=re.x,dt=re.y,At=re.z):(Xe=0,dt=0,At=0);const dn=Re.convert(W.format),mt=Re.convert(W.type);let We;if(W.isData3DTexture)k.setTexture3D(W,0),We=L.TEXTURE_3D;else if(W.isDataArrayTexture||W.isCompressedArrayTexture)k.setTexture2DArray(W,0),We=L.TEXTURE_2D_ARRAY;else{console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.");return}L.pixelStorei(L.UNPACK_FLIP_Y_WEBGL,W.flipY),L.pixelStorei(L.UNPACK_PREMULTIPLY_ALPHA_WEBGL,W.premultiplyAlpha),L.pixelStorei(L.UNPACK_ALIGNMENT,W.unpackAlignment);const jt=L.getParameter(L.UNPACK_ROW_LENGTH),_t=L.getParameter(L.UNPACK_IMAGE_HEIGHT),qn=L.getParameter(L.UNPACK_SKIP_PIXELS),ro=L.getParameter(L.UNPACK_SKIP_ROWS),Di=L.getParameter(L.UNPACK_SKIP_IMAGES);L.pixelStorei(L.UNPACK_ROW_LENGTH,Tt.width),L.pixelStorei(L.UNPACK_IMAGE_HEIGHT,Tt.height),L.pixelStorei(L.UNPACK_SKIP_PIXELS,He),L.pixelStorei(L.UNPACK_SKIP_ROWS,Ke),L.pixelStorei(L.UNPACK_SKIP_IMAGES,je),C.isDataTexture||C.isData3DTexture?L.texSubImage3D(We,Z,Xe,dt,At,Se,Le,Fe,dn,mt,Tt.data):W.isCompressedArrayTexture?L.compressedTexSubImage3D(We,Z,Xe,dt,At,Se,Le,Fe,dn,Tt.data):L.texSubImage3D(We,Z,Xe,dt,At,Se,Le,Fe,dn,mt,Tt),L.pixelStorei(L.UNPACK_ROW_LENGTH,jt),L.pixelStorei(L.UNPACK_IMAGE_HEIGHT,_t),L.pixelStorei(L.UNPACK_SKIP_PIXELS,qn),L.pixelStorei(L.UNPACK_SKIP_ROWS,ro),L.pixelStorei(L.UNPACK_SKIP_IMAGES,Di),Z===0&&W.generateMipmaps&&L.generateMipmap(We),$.unbindTexture()},this.initRenderTarget=function(C){le.get(C).__webglFramebuffer===void 0&&k.setupRenderTarget(C)},this.initTexture=function(C){C.isCubeTexture?k.setTextureCube(C,0):C.isData3DTexture?k.setTexture3D(C,0):C.isDataArrayTexture||C.isCompressedArrayTexture?k.setTexture2DArray(C,0):k.setTexture2D(C,0),$.unbindTexture()},this.resetState=function(){A=0,b=0,E=null,$.reset(),rt.reset()},typeof __THREE_DEVTOOLS__<"u"&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}get coordinateSystem(){return zn}get outputColorSpace(){return this._outputColorSpace}set outputColorSpace(e){this._outputColorSpace=e;const t=this.getContext();t.drawingBufferColorSpace=e===Ia?"display-p3":"srgb",t.unpackColorSpace=ht.workingColorSpace===Xr?"display-p3":"srgb"}}class Oa{constructor(e,t=25e-5){this.isFogExp2=!0,this.name="",this.color=new Pe(e),this.density=t}clone(){return new Oa(this.color,this.density)}toJSON(){return{type:"FogExp2",name:this.name,color:this.color.getHex(),density:this.density}}}class Fa{constructor(e,t=1,n=1e3){this.isFog=!0,this.name="",this.color=new Pe(e),this.near=t,this.far=n}clone(){return new Fa(this.color,this.near,this.far)}toJSON(){return{type:"Fog",name:this.name,color:this.color.getHex(),near:this.near,far:this.far}}}class ka extends ct{constructor(){super(),this.isScene=!0,this.type="Scene",this.background=null,this.environment=null,this.fog=null,this.backgroundBlurriness=0,this.backgroundIntensity=1,this.backgroundRotation=new _n,this.environmentIntensity=1,this.environmentRotation=new _n,this.overrideMaterial=null,typeof __THREE_DEVTOOLS__<"u"&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}copy(e,t){return super.copy(e,t),e.background!==null&&(this.background=e.background.clone()),e.environment!==null&&(this.environment=e.environment.clone()),e.fog!==null&&(this.fog=e.fog.clone()),this.backgroundBlurriness=e.backgroundBlurriness,this.backgroundIntensity=e.backgroundIntensity,this.backgroundRotation.copy(e.backgroundRotation),this.environmentIntensity=e.environmentIntensity,this.environmentRotation.copy(e.environmentRotation),e.overrideMaterial!==null&&(this.overrideMaterial=e.overrideMaterial.clone()),this.matrixAutoUpdate=e.matrixAutoUpdate,this}toJSON(e){const t=super.toJSON(e);return this.fog!==null&&(t.object.fog=this.fog.toJSON()),this.backgroundBlurriness>0&&(t.object.backgroundBlurriness=this.backgroundBlurriness),this.backgroundIntensity!==1&&(t.object.backgroundIntensity=this.backgroundIntensity),t.object.backgroundRotation=this.backgroundRotation.toArray(),this.environmentIntensity!==1&&(t.object.environmentIntensity=this.environmentIntensity),t.object.environmentRotation=this.environmentRotation.toArray(),t}}class Ba{constructor(e,t){this.isInterleavedBuffer=!0,this.array=e,this.stride=t,this.count=e!==void 0?e.length/t:0,this.usage=Pr,this._updateRange={offset:0,count:-1},this.updateRanges=[],this.version=0,this.uuid=vn()}onUploadCallback(){}set needsUpdate(e){e===!0&&this.version++}get updateRange(){return gu("THREE.InterleavedBuffer: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead."),this._updateRange}setUsage(e){return this.usage=e,this}addUpdateRange(e,t){this.updateRanges.push({start:e,count:t})}clearUpdateRanges(){this.updateRanges.length=0}copy(e){return this.array=new e.array.constructor(e.array),this.count=e.count,this.stride=e.stride,this.usage=e.usage,this}copyAt(e,t,n){e*=this.stride,n*=t.stride;for(let i=0,r=this.stride;ie.far||t.push({distance:l,point:Qs.clone(),uv:mn.getInterpolation(Qs,Co,tr,Po,Gh,Ul,Wh,new se),face:null,object:this})}copy(e,t){return super.copy(e,t),e.center!==void 0&&this.center.copy(e.center),this.material=e.material,this}}function Ro(s,e,t,n,i,r){Is.subVectors(s,t).addScalar(.5).multiply(n),i!==void 0?(er.x=r*Is.x-i*Is.y,er.y=i*Is.x+r*Is.y):er.copy(Is),s.copy(e),s.x+=er.x,s.y+=er.y,s.applyMatrix4(Lp)}const Io=new N,$h=new N;class Dp extends ct{constructor(){super(),this._currentLevel=0,this.type="LOD",Object.defineProperties(this,{levels:{enumerable:!0,value:[]},isLOD:{value:!0}}),this.autoUpdate=!0}copy(e){super.copy(e,!1);const t=e.levels;for(let n=0,i=t.length;n0){let n,i;for(n=1,i=t.length;n0){Io.setFromMatrixPosition(this.matrixWorld);const i=e.ray.origin.distanceTo(Io);this.getObjectForDistance(i).raycast(e,t)}}update(e){const t=this.levels;if(t.length>1){Io.setFromMatrixPosition(e.matrixWorld),$h.setFromMatrixPosition(this.matrixWorld);const n=Io.distanceTo($h)/e.zoom;t[0].object.visible=!0;let i,r;for(i=1,r=t.length;i=o)t[i-1].object.visible=!1,t[i].object.visible=!0;else break}for(this._currentLevel=i-1;i=n.length&&n.push({start:-1,count:-1,z:-1});const r=n[this.index];i.push(r),this.index++,r.start=e.start,r.count=e.count,r.z=t}reset(){this.list.length=0,this.index=0}}const Ns="batchId",xi=new qe,kl=new qe,PA=new qe,RA=new Pe(1,1,1),ed=new qe,Bl=new Zr,Do=new sn,Vi=new Zt,sr=new N,td=new N,IA=new N,zl=new CA,Yt=new Nt,Uo=[];function LA(s,e,t=0){const n=e.itemSize;if(s.isInterleavedBufferAttribute||s.array.constructor!==e.array.constructor){const i=s.count;for(let r=0;r65536?new Uint32Array(r):new Uint16Array(r);t.setIndex(new pt(a,1))}const o=i>65536?new Uint32Array(n):new Uint16Array(n);t.setAttribute(Ns,new pt(o,1)),this._geometryInitialized=!0}}_validateGeometry(e){if(e.getAttribute(Ns))throw new Error(`BatchedMesh: Geometry cannot use attribute "${Ns}"`);const t=this.geometry;if(!!e.getIndex()!=!!t.getIndex())throw new Error('BatchedMesh: All geometries must consistently have "index".');for(const n in t.attributes){if(n===Ns)continue;if(!e.hasAttribute(n))throw new Error(`BatchedMesh: Added geometry missing "${n}". All geometries must have consistent attributes.`);const i=e.getAttribute(n),r=t.getAttribute(n);if(i.itemSize!==r.itemSize||i.normalized!==r.normalized)throw new Error("BatchedMesh: All attributes must have a consistent itemSize and normalized value.")}}setCustomSort(e){return this.customSort=e,this}computeBoundingBox(){this.boundingBox===null&&(this.boundingBox=new sn);const e=this._geometryCount,t=this.boundingBox,n=this._active;t.makeEmpty();for(let i=0;i=this._maxGeometryCount)throw new Error("BatchedMesh: Maximum geometry count reached.");const i={vertexStart:-1,vertexCount:-1,indexStart:-1,indexCount:-1};let r=null;const o=this._reservedRanges,a=this._drawRanges,l=this._bounds;this._geometryCount!==0&&(r=o[o.length-1]),t===-1?i.vertexCount=e.getAttribute("position").count:i.vertexCount=t,r===null?i.vertexStart=0:i.vertexStart=r.vertexStart+r.vertexCount;const c=e.getIndex(),u=c!==null;if(u&&(n===-1?i.indexCount=c.count:i.indexCount=n,r===null?i.indexStart=0:i.indexStart=r.indexStart+r.indexCount),i.indexStart!==-1&&i.indexStart+i.indexCount>this._maxIndexCount||i.vertexStart+i.vertexCount>this._maxVertexCount)throw new Error("BatchedMesh: Reserved space request exceeds the maximum buffer size.");const h=this._visibility,d=this._active,f=this._matricesTexture,g=this._matricesTexture.image.data,v=this._colorsTexture;h.push(!0),d.push(!0);const p=this._geometryCount;this._geometryCount++,PA.toArray(g,p*16),f.needsUpdate=!0,v!==null&&(RA.toArray(v.image.data,p*4),v.needsUpdate=!0),o.push(i),a.push({start:u?i.indexStart:i.vertexStart,count:-1}),l.push({boxInitialized:!1,box:new sn,sphereInitialized:!1,sphere:new Zt});const m=this.geometry.getAttribute(Ns);for(let y=0;y=this._geometryCount)throw new Error("BatchedMesh: Maximum geometry count reached.");this._validateGeometry(t);const n=this.geometry,i=n.getIndex()!==null,r=n.getIndex(),o=t.getIndex(),a=this._reservedRanges[e];if(i&&o.count>a.indexCount||t.attributes.position.count>a.vertexCount)throw new Error("BatchedMesh: Reserved space not large enough for provided geometry.");const l=a.vertexStart,c=a.vertexCount;for(const f in n.attributes){if(f===Ns)continue;const g=t.getAttribute(f),v=n.getAttribute(f);LA(g,v,l);const p=g.itemSize;for(let m=g.count,y=c;m=t.length||t[e]===!1?this:(t[e]=!1,this._visibilityChanged=!0,this)}getInstanceCountAt(e){return this._multiDrawInstances===null?null:this._multiDrawInstances[e]}setInstanceCountAt(e,t){return this._multiDrawInstances===null&&(this._multiDrawInstances=new Int32Array(this._maxGeometryCount).fill(1)),this._multiDrawInstances[e]=t,e}getBoundingBoxAt(e,t){if(this._active[e]===!1)return null;const i=this._bounds[e],r=i.box,o=this.geometry;if(i.boxInitialized===!1){r.makeEmpty();const a=o.index,l=o.attributes.position,c=this._drawRanges[e];for(let u=c.start,h=c.start+c.count;u=o||n[e]===!1?this:(t.toArray(r,e*16),i.needsUpdate=!0,this)}getMatrixAt(e,t){const n=this._active,i=this._matricesTexture.image.data,r=this._geometryCount;return e>=r||n[e]===!1?null:t.fromArray(i,e*16)}setColorAt(e,t){this._colorsTexture===null&&this._initColorsTexture();const n=this._active,i=this._colorsTexture,r=this._colorsTexture.image.data,o=this._geometryCount;return e>=o||n[e]===!1?this:(t.toArray(r,e*4),i.needsUpdate=!0,this)}getColorAt(e,t){const n=this._active,i=this._colorsTexture.image.data,r=this._geometryCount;return e>=r||n[e]===!1?null:t.fromArray(i,e*4)}setVisibleAt(e,t){const n=this._visibility,i=this._active,r=this._geometryCount;return e>=r||i[e]===!1||n[e]===t?this:(n[e]=t,this._visibilityChanged=!0,this)}getVisibleAt(e){const t=this._visibility,n=this._active,i=this._geometryCount;return e>=i||n[e]===!1?!1:t[e]}raycast(e,t){const n=this._visibility,i=this._active,r=this._drawRanges,o=this._geometryCount,a=this.matrixWorld,l=this.geometry;Yt.material=this.material,Yt.geometry.index=l.index,Yt.geometry.attributes=l.attributes,Yt.geometry.boundingBox===null&&(Yt.geometry.boundingBox=new sn),Yt.geometry.boundingSphere===null&&(Yt.geometry.boundingSphere=new Zt);for(let c=0;c({...t})),this._reservedRanges=e._reservedRanges.map(t=>({...t})),this._visibility=e._visibility.slice(),this._active=e._active.slice(),this._bounds=e._bounds.map(t=>({boxInitialized:t.boxInitialized,box:t.box.clone(),sphereInitialized:t.sphereInitialized,sphere:t.sphere.clone()})),this._maxGeometryCount=e._maxGeometryCount,this._maxVertexCount=e._maxVertexCount,this._maxIndexCount=e._maxIndexCount,this._geometryInitialized=e._geometryInitialized,this._geometryCount=e._geometryCount,this._multiDrawCounts=e._multiDrawCounts.slice(),this._multiDrawStarts=e._multiDrawStarts.slice(),this._matricesTexture=e._matricesTexture.clone(),this._matricesTexture.image.data=this._matricesTexture.image.slice(),this._colorsTexture!==null&&(this._colorsTexture=e._colorsTexture.clone(),this._colorsTexture.image.data=this._colorsTexture.image.slice()),this}dispose(){return this.geometry.dispose(),this._matricesTexture.dispose(),this._matricesTexture=null,this._colorsTexture!==null&&(this._colorsTexture.dispose(),this._colorsTexture=null),this}onBeforeRender(e,t,n,i,r){if(!this._visibilityChanged&&!this.perObjectFrustumCulled&&!this.sortObjects)return;const o=i.getIndex(),a=o===null?1:o.array.BYTES_PER_ELEMENT,l=this._active,c=this._visibility,u=this._multiDrawStarts,h=this._multiDrawCounts,d=this._drawRanges,f=this.perObjectFrustumCulled;f&&(ed.multiplyMatrices(n.projectionMatrix,n.matrixWorldInverse).multiply(this.matrixWorld),Bl.setFromProjectionMatrix(ed,e.coordinateSystem));let g=0;if(this.sortObjects){kl.copy(this.matrixWorld).invert(),sr.setFromMatrixPosition(n.matrixWorld).applyMatrix4(kl),td.set(0,0,-1).transformDirection(n.matrixWorld).transformDirection(kl);for(let m=0,y=c.length;m0){const i=t[n[0]];if(i!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let r=0,o=i.length;rn)return;Vl.applyMatrix4(s.matrixWorld);const l=e.ray.origin.distanceTo(Vl);if(!(le.far))return{distance:l,point:id.clone().applyMatrix4(s.matrixWorld),index:i,face:null,faceIndex:null,object:s}}const sd=new N,rd=new N;class Xn extends Ci{constructor(e,t){super(e,t),this.isLineSegments=!0,this.type="LineSegments"}computeLineDistances(){const e=this.geometry;if(e.index===null){const t=e.attributes.position,n=[];for(let i=0,r=t.count;i0){const i=t[n[0]];if(i!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let r=0,o=i.length;ri.far)return;r.push({distance:c,distanceToRay:Math.sqrt(a),point:l,index:e,face:null,object:o})}}class NA extends Pt{constructor(e,t,n,i,r,o,a,l,c){super(e,t,n,i,r,o,a,l,c),this.isVideoTexture=!0,this.minFilter=o!==void 0?o:Ot,this.magFilter=r!==void 0?r:Ot,this.generateMipmaps=!1;const u=this;function h(){u.needsUpdate=!0,e.requestVideoFrameCallback(h)}"requestVideoFrameCallback"in e&&e.requestVideoFrameCallback(h)}clone(){return new this.constructor(this.image).copy(this)}update(){const e=this.image;"requestVideoFrameCallback"in e===!1&&e.readyState>=e.HAVE_CURRENT_DATA&&(this.needsUpdate=!0)}}class DA extends Pt{constructor(e,t){super({width:e,height:t}),this.isFramebufferTexture=!0,this.magFilter=Gt,this.minFilter=Gt,this.generateMipmaps=!1,this.needsUpdate=!0}}class Va extends Pt{constructor(e,t,n,i,r,o,a,l,c,u,h,d){super(null,o,a,l,c,u,i,r,h,d),this.isCompressedTexture=!0,this.image={width:t,height:n},this.mipmaps=e,this.flipY=!1,this.generateMipmaps=!1}}class UA extends Va{constructor(e,t,n,i,r,o){super(e,t,n,r,o),this.isCompressedArrayTexture=!0,this.image.depth=i,this.wrapR=Mn,this.layerUpdates=new Set}addLayerUpdates(e){this.layerUpdates.add(e)}clearLayerUpdates(){this.layerUpdates.clear()}}class OA extends Va{constructor(e,t,n){super(void 0,e[0].width,e[0].height,t,n,oi),this.isCompressedCubeTexture=!0,this.isCubeTexture=!0,this.image=e}}class FA extends Pt{constructor(e,t,n,i,r,o,a,l,c){super(e,t,n,i,r,o,a,l,c),this.isCanvasTexture=!0,this.needsUpdate=!0}}class Dn{constructor(){this.type="Curve",this.arcLengthDivisions=200}getPoint(){return console.warn("THREE.Curve: .getPoint() not implemented."),null}getPointAt(e,t){const n=this.getUtoTmapping(e);return this.getPoint(n,t)}getPoints(e=5){const t=[];for(let n=0;n<=e;n++)t.push(this.getPoint(n/e));return t}getSpacedPoints(e=5){const t=[];for(let n=0;n<=e;n++)t.push(this.getPointAt(n/e));return t}getLength(){const e=this.getLengths();return e[e.length-1]}getLengths(e=this.arcLengthDivisions){if(this.cacheArcLengths&&this.cacheArcLengths.length===e+1&&!this.needsUpdate)return this.cacheArcLengths;this.needsUpdate=!1;const t=[];let n,i=this.getPoint(0),r=0;t.push(0);for(let o=1;o<=e;o++)n=this.getPoint(o/e),r+=n.distanceTo(i),t.push(r),i=n;return this.cacheArcLengths=t,t}updateArcLengths(){this.needsUpdate=!0,this.getLengths()}getUtoTmapping(e,t){const n=this.getLengths();let i=0;const r=n.length;let o;t?o=t:o=e*n[r-1];let a=0,l=r-1,c;for(;a<=l;)if(i=Math.floor(a+(l-a)/2),c=n[i]-o,c<0)a=i+1;else if(c>0)l=i-1;else{l=i;break}if(i=l,n[i]===o)return i/(r-1);const u=n[i],d=n[i+1]-u,f=(o-u)/d;return(i+f)/(r-1)}getTangent(e,t){let i=e-1e-4,r=e+1e-4;i<0&&(i=0),r>1&&(r=1);const o=this.getPoint(i),a=this.getPoint(r),l=t||(o.isVector2?new se:new N);return l.copy(a).sub(o).normalize(),l}getTangentAt(e,t){const n=this.getUtoTmapping(e);return this.getTangent(n,t)}computeFrenetFrames(e,t){const n=new N,i=[],r=[],o=[],a=new N,l=new qe;for(let f=0;f<=e;f++){const g=f/e;i[f]=this.getTangentAt(g,new N)}r[0]=new N,o[0]=new N;let c=Number.MAX_VALUE;const u=Math.abs(i[0].x),h=Math.abs(i[0].y),d=Math.abs(i[0].z);u<=c&&(c=u,n.set(1,0,0)),h<=c&&(c=h,n.set(0,1,0)),d<=c&&n.set(0,0,1),a.crossVectors(i[0],n).normalize(),r[0].crossVectors(i[0],a),o[0].crossVectors(i[0],r[0]);for(let f=1;f<=e;f++){if(r[f]=r[f-1].clone(),o[f]=o[f-1].clone(),a.crossVectors(i[f-1],i[f]),a.length()>Number.EPSILON){a.normalize();const g=Math.acos(Ct(i[f-1].dot(i[f]),-1,1));r[f].applyMatrix4(l.makeRotationAxis(a,g))}o[f].crossVectors(i[f],r[f])}if(t===!0){let f=Math.acos(Ct(r[0].dot(r[e]),-1,1));f/=e,i[0].dot(a.crossVectors(r[0],r[e]))>0&&(f=-f);for(let g=1;g<=e;g++)r[g].applyMatrix4(l.makeRotationAxis(i[g],f*g)),o[g].crossVectors(i[g],r[g])}return{tangents:i,normals:r,binormals:o}}clone(){return new this.constructor().copy(this)}copy(e){return this.arcLengthDivisions=e.arcLengthDivisions,this}toJSON(){const e={metadata:{version:4.6,type:"Curve",generator:"Curve.toJSON"}};return e.arcLengthDivisions=this.arcLengthDivisions,e.type=this.type,e}fromJSON(e){return this.arcLengthDivisions=e.arcLengthDivisions,this}}class Ha extends Dn{constructor(e=0,t=0,n=1,i=1,r=0,o=Math.PI*2,a=!1,l=0){super(),this.isEllipseCurve=!0,this.type="EllipseCurve",this.aX=e,this.aY=t,this.xRadius=n,this.yRadius=i,this.aStartAngle=r,this.aEndAngle=o,this.aClockwise=a,this.aRotation=l}getPoint(e,t=new se){const n=t,i=Math.PI*2;let r=this.aEndAngle-this.aStartAngle;const o=Math.abs(r)i;)r-=i;r0?0:(Math.floor(Math.abs(a)/r)+1)*r:l===0&&a===r-1&&(a=r-2,l=1);let c,u;this.closed||a>0?c=i[(a-1)%r]:(zo.subVectors(i[0],i[1]).add(i[0]),c=zo);const h=i[a%r],d=i[(a+1)%r];if(this.closed||a+2i.length-2?i.length-1:o+1],h=i[o>i.length-3?i.length-1:o+2];return n.set(ld(a,l.x,c.x,u.x,h.x),ld(a,l.y,c.y,u.y,h.y)),n}copy(e){super.copy(e),this.points=[];for(let t=0,n=e.points.length;t=n){const o=i[r]-n,a=this.curves[r],l=a.getLength(),c=l===0?0:1-o/l;return a.getPointAt(c,t)}r++}return null}getLength(){const e=this.getCurveLengths();return e[e.length-1]}updateArcLengths(){this.needsUpdate=!0,this.cacheLengths=null,this.getCurveLengths()}getCurveLengths(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths;const e=[];let t=0;for(let n=0,i=this.curves.length;n1&&!t[t.length-1].equals(t[0])&&t.push(t[0]),t}copy(e){super.copy(e),this.curves=[];for(let t=0,n=e.curves.length;t0){const h=c.getPoint(0);h.equals(this.currentPoint)||this.lineTo(h.x,h.y)}this.curves.push(c);const u=c.getPoint(1);return this.currentPoint.copy(u),this}copy(e){return super.copy(e),this.currentPoint.copy(e.currentPoint),this}toJSON(){const e=super.toJSON();return e.currentPoint=this.currentPoint.toArray(),e}fromJSON(e){return super.fromJSON(e),this.currentPoint.fromArray(e.currentPoint),this}}class Jr extends it{constructor(e=[new se(0,-.5),new se(.5,0),new se(0,.5)],t=12,n=0,i=Math.PI*2){super(),this.type="LatheGeometry",this.parameters={points:e,segments:t,phiStart:n,phiLength:i},t=Math.floor(t),i=Ct(i,0,Math.PI*2);const r=[],o=[],a=[],l=[],c=[],u=1/t,h=new N,d=new se,f=new N,g=new N,v=new N;let p=0,m=0;for(let y=0;y<=e.length-1;y++)switch(y){case 0:p=e[y+1].x-e[y].x,m=e[y+1].y-e[y].y,f.x=m*1,f.y=-p,f.z=m*0,v.copy(f),f.normalize(),l.push(f.x,f.y,f.z);break;case e.length-1:l.push(v.x,v.y,v.z);break;default:p=e[y+1].x-e[y].x,m=e[y+1].y-e[y].y,f.x=m*1,f.y=-p,f.z=m*0,g.copy(f),f.x+=v.x,f.y+=v.y,f.z+=v.z,f.normalize(),l.push(f.x,f.y,f.z),v.copy(g)}for(let y=0;y<=t;y++){const _=n+y*u*i,x=Math.sin(_),A=Math.cos(_);for(let b=0;b<=e.length-1;b++){h.x=e[b].x*x,h.y=e[b].y,h.z=e[b].x*A,o.push(h.x,h.y,h.z),d.x=y/t,d.y=b/(e.length-1),a.push(d.x,d.y);const E=l[3*b+0]*x,I=l[3*b+1],w=l[3*b+0]*A;c.push(E,I,w)}}for(let y=0;y0&&_(!0),t>0&&_(!1)),this.setIndex(u),this.setAttribute("position",new Ne(h,3)),this.setAttribute("normal",new Ne(d,3)),this.setAttribute("uv",new Ne(f,2));function y(){const x=new N,A=new N;let b=0;const E=(t-e)/n;for(let I=0;I<=r;I++){const w=[],M=I/r,F=M*(t-e)+e;for(let V=0;V<=i;V++){const G=V/i,q=G*l+a,ae=Math.sin(q),j=Math.cos(q);A.x=F*ae,A.y=-M*n+p,A.z=F*j,h.push(A.x,A.y,A.z),x.set(ae,E,j).normalize(),d.push(x.x,x.y,x.z),f.push(G,1-M),w.push(g++)}v.push(w)}for(let I=0;I.9&&E<.1&&(_<.2&&(o[y+0]+=1),x<.2&&(o[y+2]+=1),A<.2&&(o[y+4]+=1))}}function d(y){r.push(y.x,y.y,y.z)}function f(y,_){const x=y*3;_.x=e[x+0],_.y=e[x+1],_.z=e[x+2]}function g(){const y=new N,_=new N,x=new N,A=new N,b=new se,E=new se,I=new se;for(let w=0,M=0;w80*t){a=c=s[0],l=u=s[1];for(let g=t;gc&&(c=h),d>u&&(u=d);f=Math.max(c-a,u-l),f=f!==0?32767/f:0}return Lr(r,o,t,a,l,f,0),o}};function Xp(s,e,t,n,i){let r,o;if(i===aT(s,e,t,n)>0)for(r=e;r=e;r-=n)o=cd(r,s[r],s[r+1],o);return o&&qa(o,o.next)&&(Dr(o),o=o.next),o}function ls(s,e){if(!s)return s;e||(e=s);let t=s,n;do if(n=!1,!t.steiner&&(qa(t,t.next)||St(t.prev,t,t.next)===0)){if(Dr(t),t=e=t.prev,t===t.next)break;n=!0}else t=t.next;while(n||t!==e);return e}function Lr(s,e,t,n,i,r,o){if(!s)return;!o&&r&&tT(s,n,i,r);let a=s,l,c;for(;s.prev!==s.next;){if(l=s.prev,c=s.next,r?qA(s,n,i,r):XA(s)){e.push(l.i/t|0),e.push(s.i/t|0),e.push(c.i/t|0),Dr(s),s=c.next,a=c.next;continue}if(s=c,s===a){o?o===1?(s=YA(ls(s),e,t),Lr(s,e,t,n,i,r,2)):o===2&&ZA(s,e,t,n,i,r):Lr(ls(s),e,t,n,i,r,1);break}}}function XA(s){const e=s.prev,t=s,n=s.next;if(St(e,t,n)>=0)return!1;const i=e.x,r=t.x,o=n.x,a=e.y,l=t.y,c=n.y,u=ir?i>o?i:o:r>o?r:o,f=a>l?a>c?a:c:l>c?l:c;let g=n.next;for(;g!==e;){if(g.x>=u&&g.x<=d&&g.y>=h&&g.y<=f&&ks(i,a,r,l,o,c,g.x,g.y)&&St(g.prev,g,g.next)>=0)return!1;g=g.next}return!0}function qA(s,e,t,n){const i=s.prev,r=s,o=s.next;if(St(i,r,o)>=0)return!1;const a=i.x,l=r.x,c=o.x,u=i.y,h=r.y,d=o.y,f=al?a>c?a:c:l>c?l:c,p=u>h?u>d?u:d:h>d?h:d,m=Fc(f,g,e,t,n),y=Fc(v,p,e,t,n);let _=s.prevZ,x=s.nextZ;for(;_&&_.z>=m&&x&&x.z<=y;){if(_.x>=f&&_.x<=v&&_.y>=g&&_.y<=p&&_!==i&&_!==o&&ks(a,u,l,h,c,d,_.x,_.y)&&St(_.prev,_,_.next)>=0||(_=_.prevZ,x.x>=f&&x.x<=v&&x.y>=g&&x.y<=p&&x!==i&&x!==o&&ks(a,u,l,h,c,d,x.x,x.y)&&St(x.prev,x,x.next)>=0))return!1;x=x.nextZ}for(;_&&_.z>=m;){if(_.x>=f&&_.x<=v&&_.y>=g&&_.y<=p&&_!==i&&_!==o&&ks(a,u,l,h,c,d,_.x,_.y)&&St(_.prev,_,_.next)>=0)return!1;_=_.prevZ}for(;x&&x.z<=y;){if(x.x>=f&&x.x<=v&&x.y>=g&&x.y<=p&&x!==i&&x!==o&&ks(a,u,l,h,c,d,x.x,x.y)&&St(x.prev,x,x.next)>=0)return!1;x=x.nextZ}return!0}function YA(s,e,t){let n=s;do{const i=n.prev,r=n.next.next;!qa(i,r)&&qp(i,n,n.next,r)&&Nr(i,r)&&Nr(r,i)&&(e.push(i.i/t|0),e.push(n.i/t|0),e.push(r.i/t|0),Dr(n),Dr(n.next),n=s=r),n=n.next}while(n!==s);return ls(n)}function ZA(s,e,t,n,i,r){let o=s;do{let a=o.next.next;for(;a!==o.prev;){if(o.i!==a.i&&sT(o,a)){let l=Yp(o,a);o=ls(o,o.next),l=ls(l,l.next),Lr(o,e,t,n,i,r,0),Lr(l,e,t,n,i,r,0);return}a=a.next}o=o.next}while(o!==s)}function JA(s,e,t,n){const i=[];let r,o,a,l,c;for(r=0,o=e.length;r=t.next.y&&t.next.y!==t.y){const d=t.x+(o-t.y)*(t.next.x-t.x)/(t.next.y-t.y);if(d<=r&&d>n&&(n=d,i=t.x=t.x&&t.x>=l&&r!==t.x&&ks(oi.x||t.x===i.x&&eT(i,t)))&&(i=t,u=h)),t=t.next;while(t!==a);return i}function eT(s,e){return St(s.prev,s,e.prev)<0&&St(e.next,s,s.next)<0}function tT(s,e,t,n){let i=s;do i.z===0&&(i.z=Fc(i.x,i.y,e,t,n)),i.prevZ=i.prev,i.nextZ=i.next,i=i.next;while(i!==s);i.prevZ.nextZ=null,i.prevZ=null,nT(i)}function nT(s){let e,t,n,i,r,o,a,l,c=1;do{for(t=s,s=null,r=null,o=0;t;){for(o++,n=t,a=0,e=0;e0||l>0&&n;)a!==0&&(l===0||!n||t.z<=n.z)?(i=t,t=t.nextZ,a--):(i=n,n=n.nextZ,l--),r?r.nextZ=i:s=i,i.prevZ=r,r=i;t=n}r.nextZ=null,c*=2}while(o>1);return s}function Fc(s,e,t,n,i){return s=(s-t)*i|0,e=(e-n)*i|0,s=(s|s<<8)&16711935,s=(s|s<<4)&252645135,s=(s|s<<2)&858993459,s=(s|s<<1)&1431655765,e=(e|e<<8)&16711935,e=(e|e<<4)&252645135,e=(e|e<<2)&858993459,e=(e|e<<1)&1431655765,s|e<<1}function iT(s){let e=s,t=s;do(e.x=(s-o)*(r-a)&&(s-o)*(n-a)>=(t-o)*(e-a)&&(t-o)*(r-a)>=(i-o)*(n-a)}function sT(s,e){return s.next.i!==e.i&&s.prev.i!==e.i&&!rT(s,e)&&(Nr(s,e)&&Nr(e,s)&&oT(s,e)&&(St(s.prev,s,e.prev)||St(s,e.prev,e))||qa(s,e)&&St(s.prev,s,s.next)>0&&St(e.prev,e,e.next)>0)}function St(s,e,t){return(e.y-s.y)*(t.x-e.x)-(e.x-s.x)*(t.y-e.y)}function qa(s,e){return s.x===e.x&&s.y===e.y}function qp(s,e,t,n){const i=$o(St(s,e,t)),r=$o(St(s,e,n)),o=$o(St(t,n,s)),a=$o(St(t,n,e));return!!(i!==r&&o!==a||i===0&&Wo(s,t,e)||r===0&&Wo(s,n,e)||o===0&&Wo(t,s,n)||a===0&&Wo(t,e,n))}function Wo(s,e,t){return e.x<=Math.max(s.x,t.x)&&e.x>=Math.min(s.x,t.x)&&e.y<=Math.max(s.y,t.y)&&e.y>=Math.min(s.y,t.y)}function $o(s){return s>0?1:s<0?-1:0}function rT(s,e){let t=s;do{if(t.i!==s.i&&t.next.i!==s.i&&t.i!==e.i&&t.next.i!==e.i&&qp(t,t.next,s,e))return!0;t=t.next}while(t!==s);return!1}function Nr(s,e){return St(s.prev,s,s.next)<0?St(s,e,s.next)>=0&&St(s,s.prev,e)>=0:St(s,e,s.prev)<0||St(s,s.next,e)<0}function oT(s,e){let t=s,n=!1;const i=(s.x+e.x)/2,r=(s.y+e.y)/2;do t.y>r!=t.next.y>r&&t.next.y!==t.y&&i<(t.next.x-t.x)*(r-t.y)/(t.next.y-t.y)+t.x&&(n=!n),t=t.next;while(t!==s);return n}function Yp(s,e){const t=new kc(s.i,s.x,s.y),n=new kc(e.i,e.x,e.y),i=s.next,r=e.prev;return s.next=e,e.prev=s,t.next=i,i.prev=t,n.next=t,t.prev=n,r.next=n,n.prev=r,n}function cd(s,e,t,n){const i=new kc(s,e,t);return n?(i.next=n.next,i.prev=n,n.next.prev=i,n.next=i):(i.prev=i,i.next=i),i}function Dr(s){s.next.prev=s.prev,s.prev.next=s.next,s.prevZ&&(s.prevZ.nextZ=s.nextZ),s.nextZ&&(s.nextZ.prevZ=s.prevZ)}function kc(s,e,t){this.i=s,this.x=e,this.y=t,this.prev=null,this.next=null,this.z=0,this.prevZ=null,this.nextZ=null,this.steiner=!1}function aT(s,e,t,n){let i=0;for(let r=e,o=t-n;r2&&s[e-1].equals(s[0])&&s.pop()}function hd(s,e){for(let t=0;tNumber.EPSILON){const ce=Math.sqrt(Q),ve=Math.sqrt(P*P+S*S),Ve=K.x-O/ce,Ee=K.y+k/ce,Te=H.x-S/ve,Qe=H.y+P/ve,xe=((Te-Ve)*S-(Qe-Ee)*P)/(k*S-O*P);$=Ve+k*xe-X.x,te=Ee+O*xe-X.y;const Oe=$*$+te*te;if(Oe<=2)return new se($,te);le=Math.sqrt(Oe/2)}else{let ce=!1;k>Number.EPSILON?P>Number.EPSILON&&(ce=!0):k<-Number.EPSILON?P<-Number.EPSILON&&(ce=!0):Math.sign(O)===Math.sign(S)&&(ce=!0),ce?($=-O,te=k,le=Math.sqrt(Q)):($=k,te=O,le=Math.sqrt(Q/2))}return new se($/le,te/le)}const Me=[];for(let X=0,K=q.length,H=K-1,$=X+1;X=0;X--){const K=X/p,H=f*Math.cos(K*Math.PI/2),$=g*Math.sin(K*Math.PI/2)+v;for(let te=0,le=q.length;te=0;){const $=H;let te=H-1;te<0&&(te=X.length-1);for(let le=0,k=u+p*2;le0)&&f.push(_,x,b),(m!==n-1||l0!=e>0&&this.version++,this._anisotropy=e}get clearcoat(){return this._clearcoat}set clearcoat(e){this._clearcoat>0!=e>0&&this.version++,this._clearcoat=e}get iridescence(){return this._iridescence}set iridescence(e){this._iridescence>0!=e>0&&this.version++,this._iridescence=e}get dispersion(){return this._dispersion}set dispersion(e){this._dispersion>0!=e>0&&this.version++,this._dispersion=e}get sheen(){return this._sheen}set sheen(e){this._sheen>0!=e>0&&this.version++,this._sheen=e}get transmission(){return this._transmission}set transmission(e){this._transmission>0!=e>0&&this.version++,this._transmission=e}copy(e){return super.copy(e),this.defines={STANDARD:"",PHYSICAL:""},this.anisotropy=e.anisotropy,this.anisotropyRotation=e.anisotropyRotation,this.anisotropyMap=e.anisotropyMap,this.clearcoat=e.clearcoat,this.clearcoatMap=e.clearcoatMap,this.clearcoatRoughness=e.clearcoatRoughness,this.clearcoatRoughnessMap=e.clearcoatRoughnessMap,this.clearcoatNormalMap=e.clearcoatNormalMap,this.clearcoatNormalScale.copy(e.clearcoatNormalScale),this.dispersion=e.dispersion,this.ior=e.ior,this.iridescence=e.iridescence,this.iridescenceMap=e.iridescenceMap,this.iridescenceIOR=e.iridescenceIOR,this.iridescenceThicknessRange=[...e.iridescenceThicknessRange],this.iridescenceThicknessMap=e.iridescenceThicknessMap,this.sheen=e.sheen,this.sheenColor.copy(e.sheenColor),this.sheenColorMap=e.sheenColorMap,this.sheenRoughness=e.sheenRoughness,this.sheenRoughnessMap=e.sheenRoughnessMap,this.transmission=e.transmission,this.transmissionMap=e.transmissionMap,this.thickness=e.thickness,this.thicknessMap=e.thicknessMap,this.attenuationDistance=e.attenuationDistance,this.attenuationColor.copy(e.attenuationColor),this.specularIntensity=e.specularIntensity,this.specularIntensityMap=e.specularIntensityMap,this.specularColor.copy(e.specularColor),this.specularColorMap=e.specularColorMap,this}}class Qp extends Kt{constructor(e){super(),this.isMeshPhongMaterial=!0,this.type="MeshPhongMaterial",this.color=new Pe(16777215),this.specular=new Pe(1118481),this.shininess=30,this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Pe(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=Ri,this.normalScale=new se(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new _n,this.combine=Wr,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.specular.copy(e.specular),this.shininess=e.shininess,this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.envMapRotation.copy(e.envMapRotation),this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.flatShading=e.flatShading,this.fog=e.fog,this}}class em extends Kt{constructor(e){super(),this.isMeshToonMaterial=!0,this.defines={TOON:""},this.type="MeshToonMaterial",this.color=new Pe(16777215),this.map=null,this.gradientMap=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Pe(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=Ri,this.normalScale=new se(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.gradientMap=e.gradientMap,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.alphaMap=e.alphaMap,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.fog=e.fog,this}}class tm extends Kt{constructor(e){super(),this.isMeshNormalMaterial=!0,this.type="MeshNormalMaterial",this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=Ri,this.normalScale=new se(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.flatShading=!1,this.setValues(e)}copy(e){return super.copy(e),this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.flatShading=e.flatShading,this}}class nm extends Kt{constructor(e){super(),this.isMeshLambertMaterial=!0,this.type="MeshLambertMaterial",this.color=new Pe(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Pe(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=Ri,this.normalScale=new se(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new _n,this.combine=Wr,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.envMapRotation.copy(e.envMapRotation),this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.flatShading=e.flatShading,this.fog=e.fog,this}}class im extends Kt{constructor(e){super(),this.isMeshMatcapMaterial=!0,this.defines={MATCAP:""},this.type="MeshMatcapMaterial",this.color=new Pe(16777215),this.matcap=null,this.map=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=Ri,this.normalScale=new se(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.flatShading=!1,this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.defines={MATCAP:""},this.color.copy(e.color),this.matcap=e.matcap,this.map=e.map,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.alphaMap=e.alphaMap,this.flatShading=e.flatShading,this.fog=e.fog,this}}class sm extends rn{constructor(e){super(),this.isLineDashedMaterial=!0,this.type="LineDashedMaterial",this.scale=1,this.dashSize=3,this.gapSize=1,this.setValues(e)}copy(e){return super.copy(e),this.scale=e.scale,this.dashSize=e.dashSize,this.gapSize=e.gapSize,this}}function Qi(s,e,t){return!s||!t&&s.constructor===e?s:typeof e.BYTES_PER_ELEMENT=="number"?new e(s):Array.prototype.slice.call(s)}function rm(s){return ArrayBuffer.isView(s)&&!(s instanceof DataView)}function om(s){function e(i,r){return s[i]-s[r]}const t=s.length,n=new Array(t);for(let i=0;i!==t;++i)n[i]=i;return n.sort(e),n}function Bc(s,e,t){const n=s.length,i=new s.constructor(n);for(let r=0,o=0;o!==n;++r){const a=t[r]*e;for(let l=0;l!==e;++l)i[o++]=s[a+l]}return i}function Du(s,e,t,n){let i=1,r=s[0];for(;r!==void 0&&r[n]===void 0;)r=s[i++];if(r===void 0)return;let o=r[n];if(o!==void 0)if(Array.isArray(o))do o=r[n],o!==void 0&&(e.push(r.time),t.push.apply(t,o)),r=s[i++];while(r!==void 0);else if(o.toArray!==void 0)do o=r[n],o!==void 0&&(e.push(r.time),o.toArray(t,t.length)),r=s[i++];while(r!==void 0);else do o=r[n],o!==void 0&&(e.push(r.time),t.push(o)),r=s[i++];while(r!==void 0)}function hT(s,e,t,n,i=30){const r=s.clone();r.name=e;const o=[];for(let l=0;l=n)){h.push(c.times[f]);for(let v=0;vr.tracks[l].times[0]&&(a=r.tracks[l].times[0]);for(let l=0;l=a.times[g]){const m=g*h+u,y=m+h-u;v=a.values.slice(m,y)}else{const m=a.createInterpolant(),y=u,_=h-u;m.evaluate(r),v=m.resultBuffer.slice(y,_)}l==="quaternion"&&new hn().fromArray(v).normalize().conjugate().toArray(v);const p=c.times.length;for(let m=0;m=r)){const a=t[1];e=r)break t}o=n,n=0;break n}break e}for(;n>>1;et;)--o;if(++o,r!==0||o!==i){r>=o&&(o=Math.max(o,1),r=o-1);const a=this.getValueSize();this.times=n.slice(r,o),this.values=this.values.slice(r*a,o*a)}return this}validate(){let e=!0;const t=this.getValueSize();t-Math.floor(t)!==0&&(console.error("THREE.KeyframeTrack: Invalid value size in track.",this),e=!1);const n=this.times,i=this.values,r=n.length;r===0&&(console.error("THREE.KeyframeTrack: Track is empty.",this),e=!1);let o=null;for(let a=0;a!==r;a++){const l=n[a];if(typeof l=="number"&&isNaN(l)){console.error("THREE.KeyframeTrack: Time is not a valid number.",this,a,l),e=!1;break}if(o!==null&&o>l){console.error("THREE.KeyframeTrack: Out of order keys.",this,a,l,o),e=!1;break}o=l}if(i!==void 0&&rm(i))for(let a=0,l=i.length;a!==l;++a){const c=i[a];if(isNaN(c)){console.error("THREE.KeyframeTrack: Value is not a valid number.",this,a,c),e=!1;break}}return e}optimize(){const e=this.times.slice(),t=this.values.slice(),n=this.getValueSize(),i=this.getInterpolation()===ua,r=e.length-1;let o=1;for(let a=1;a0){e[o]=e[r];for(let a=r*n,l=o*n,c=0;c!==n;++c)t[l+c]=t[a+c];++o}return o!==e.length?(this.times=e.slice(0,o),this.values=t.slice(0,o*n)):(this.times=e,this.values=t),this}clone(){const e=this.times.slice(),t=this.values.slice(),n=this.constructor,i=new n(this.name,e,t);return i.createInterpolant=this.createInterpolant,i}}Un.prototype.TimeBufferType=Float32Array;Un.prototype.ValueBufferType=Float32Array;Un.prototype.DefaultInterpolation=xa;class us extends Un{constructor(e,t,n){super(e,t,n)}}us.prototype.ValueTypeName="bool";us.prototype.ValueBufferType=Array;us.prototype.DefaultInterpolation=wr;us.prototype.InterpolantFactoryMethodLinear=void 0;us.prototype.InterpolantFactoryMethodSmooth=void 0;class Ou extends Un{}Ou.prototype.ValueTypeName="color";class Ur extends Un{}Ur.prototype.ValueTypeName="number";class cm extends Qr{constructor(e,t,n,i){super(e,t,n,i)}interpolate_(e,t,n,i){const r=this.resultBuffer,o=this.sampleValues,a=this.valueSize,l=(n-t)/(i-t);let c=e*a;for(let u=c+a;c!==u;c+=4)hn.slerpFlat(r,0,o,c-a,o,c,l);return r}}class eo extends Un{InterpolantFactoryMethodLinear(e){return new cm(this.times,this.values,this.getValueSize(),e)}}eo.prototype.ValueTypeName="quaternion";eo.prototype.InterpolantFactoryMethodSmooth=void 0;class hs extends Un{constructor(e,t,n){super(e,t,n)}}hs.prototype.ValueTypeName="string";hs.prototype.ValueBufferType=Array;hs.prototype.DefaultInterpolation=wr;hs.prototype.InterpolantFactoryMethodLinear=void 0;hs.prototype.InterpolantFactoryMethodSmooth=void 0;class Or extends Un{}Or.prototype.ValueTypeName="vector";class Fr{constructor(e="",t=-1,n=[],i=Ra){this.name=e,this.tracks=n,this.duration=t,this.blendMode=i,this.uuid=vn(),this.duration<0&&this.resetDuration()}static parse(e){const t=[],n=e.tracks,i=1/(e.fps||1);for(let o=0,a=n.length;o!==a;++o)t.push(mT(n[o]).scale(i));const r=new this(e.name,e.duration,t,e.blendMode);return r.uuid=e.uuid,r}static toJSON(e){const t=[],n=e.tracks,i={name:e.name,duration:e.duration,tracks:t,uuid:e.uuid,blendMode:e.blendMode};for(let r=0,o=n.length;r!==o;++r)t.push(Un.toJSON(n[r]));return i}static CreateFromMorphTargetSequence(e,t,n,i){const r=t.length,o=[];for(let a=0;a1){const h=u[1];let d=i[h];d||(i[h]=d=[]),d.push(c)}}const o=[];for(const a in i)o.push(this.CreateFromMorphTargetSequence(a,i[a],t,n));return o}static parseAnimation(e,t){if(!e)return console.error("THREE.AnimationClip: No animation in JSONLoader data."),null;const n=function(h,d,f,g,v){if(f.length!==0){const p=[],m=[];Du(f,p,m,g),p.length!==0&&v.push(new h(d,p,m))}},i=[],r=e.name||"default",o=e.fps||30,a=e.blendMode;let l=e.length||-1;const c=e.hierarchy||[];for(let h=0;h{t&&t(r),this.manager.itemEnd(e)},0),r;if(Qn[e]!==void 0){Qn[e].push({onLoad:t,onProgress:n,onError:i});return}Qn[e]=[],Qn[e].push({onLoad:t,onProgress:n,onError:i});const o=new Request(e,{headers:new Headers(this.requestHeader),credentials:this.withCredentials?"include":"same-origin"}),a=this.mimeType,l=this.responseType;fetch(o).then(c=>{if(c.status===200||c.status===0){if(c.status===0&&console.warn("THREE.FileLoader: HTTP Status 0 received."),typeof ReadableStream>"u"||c.body===void 0||c.body.getReader===void 0)return c;const u=Qn[e],h=c.body.getReader(),d=c.headers.get("X-File-Size")||c.headers.get("Content-Length"),f=d?parseInt(d):0,g=f!==0;let v=0;const p=new ReadableStream({start(m){y();function y(){h.read().then(({done:_,value:x})=>{if(_)m.close();else{v+=x.byteLength;const A=new ProgressEvent("progress",{lengthComputable:g,loaded:v,total:f});for(let b=0,E=u.length;b{m.error(_)})}}});return new Response(p)}else throw new gT(`fetch for "${c.url}" responded with ${c.status}: ${c.statusText}`,c)}).then(c=>{switch(l){case"arraybuffer":return c.arrayBuffer();case"blob":return c.blob();case"document":return c.text().then(u=>new DOMParser().parseFromString(u,a));case"json":return c.json();default:if(a===void 0)return c.text();{const h=/charset="?([^;"\s]*)"?/i.exec(a),d=h&&h[1]?h[1].toLowerCase():void 0,f=new TextDecoder(d);return c.arrayBuffer().then(g=>f.decode(g))}}}).then(c=>{ni.add(e,c);const u=Qn[e];delete Qn[e];for(let h=0,d=u.length;h{const u=Qn[e];if(u===void 0)throw this.manager.itemError(e),c;delete Qn[e];for(let h=0,d=u.length;h{this.manager.itemEnd(e)}),this.manager.itemStart(e)}setResponseType(e){return this.responseType=e,this}setMimeType(e){return this.mimeType=e,this}}class vT extends on{constructor(e){super(e)}load(e,t,n,i){const r=this,o=new Wn(this.manager);o.setPath(this.path),o.setRequestHeader(this.requestHeader),o.setWithCredentials(this.withCredentials),o.load(e,function(a){try{t(r.parse(JSON.parse(a)))}catch(l){i?i(l):console.error(l),r.manager.itemError(e)}},n,i)}parse(e){const t=[];for(let n=0;n0:i.vertexColors=e.vertexColors),e.uniforms!==void 0)for(const r in e.uniforms){const o=e.uniforms[r];switch(i.uniforms[r]={},o.type){case"t":i.uniforms[r].value=n(o.value);break;case"c":i.uniforms[r].value=new Pe().setHex(o.value);break;case"v2":i.uniforms[r].value=new se().fromArray(o.value);break;case"v3":i.uniforms[r].value=new N().fromArray(o.value);break;case"v4":i.uniforms[r].value=new gt().fromArray(o.value);break;case"m3":i.uniforms[r].value=new Ze().fromArray(o.value);break;case"m4":i.uniforms[r].value=new qe().fromArray(o.value);break;default:i.uniforms[r].value=o.value}}if(e.defines!==void 0&&(i.defines=e.defines),e.vertexShader!==void 0&&(i.vertexShader=e.vertexShader),e.fragmentShader!==void 0&&(i.fragmentShader=e.fragmentShader),e.glslVersion!==void 0&&(i.glslVersion=e.glslVersion),e.extensions!==void 0)for(const r in e.extensions)i.extensions[r]=e.extensions[r];if(e.lights!==void 0&&(i.lights=e.lights),e.clipping!==void 0&&(i.clipping=e.clipping),e.size!==void 0&&(i.size=e.size),e.sizeAttenuation!==void 0&&(i.sizeAttenuation=e.sizeAttenuation),e.map!==void 0&&(i.map=n(e.map)),e.matcap!==void 0&&(i.matcap=n(e.matcap)),e.alphaMap!==void 0&&(i.alphaMap=n(e.alphaMap)),e.bumpMap!==void 0&&(i.bumpMap=n(e.bumpMap)),e.bumpScale!==void 0&&(i.bumpScale=e.bumpScale),e.normalMap!==void 0&&(i.normalMap=n(e.normalMap)),e.normalMapType!==void 0&&(i.normalMapType=e.normalMapType),e.normalScale!==void 0){let r=e.normalScale;Array.isArray(r)===!1&&(r=[r,r]),i.normalScale=new se().fromArray(r)}return e.displacementMap!==void 0&&(i.displacementMap=n(e.displacementMap)),e.displacementScale!==void 0&&(i.displacementScale=e.displacementScale),e.displacementBias!==void 0&&(i.displacementBias=e.displacementBias),e.roughnessMap!==void 0&&(i.roughnessMap=n(e.roughnessMap)),e.metalnessMap!==void 0&&(i.metalnessMap=n(e.metalnessMap)),e.emissiveMap!==void 0&&(i.emissiveMap=n(e.emissiveMap)),e.emissiveIntensity!==void 0&&(i.emissiveIntensity=e.emissiveIntensity),e.specularMap!==void 0&&(i.specularMap=n(e.specularMap)),e.specularIntensityMap!==void 0&&(i.specularIntensityMap=n(e.specularIntensityMap)),e.specularColorMap!==void 0&&(i.specularColorMap=n(e.specularColorMap)),e.envMap!==void 0&&(i.envMap=n(e.envMap)),e.envMapRotation!==void 0&&i.envMapRotation.fromArray(e.envMapRotation),e.envMapIntensity!==void 0&&(i.envMapIntensity=e.envMapIntensity),e.reflectivity!==void 0&&(i.reflectivity=e.reflectivity),e.refractionRatio!==void 0&&(i.refractionRatio=e.refractionRatio),e.lightMap!==void 0&&(i.lightMap=n(e.lightMap)),e.lightMapIntensity!==void 0&&(i.lightMapIntensity=e.lightMapIntensity),e.aoMap!==void 0&&(i.aoMap=n(e.aoMap)),e.aoMapIntensity!==void 0&&(i.aoMapIntensity=e.aoMapIntensity),e.gradientMap!==void 0&&(i.gradientMap=n(e.gradientMap)),e.clearcoatMap!==void 0&&(i.clearcoatMap=n(e.clearcoatMap)),e.clearcoatRoughnessMap!==void 0&&(i.clearcoatRoughnessMap=n(e.clearcoatRoughnessMap)),e.clearcoatNormalMap!==void 0&&(i.clearcoatNormalMap=n(e.clearcoatNormalMap)),e.clearcoatNormalScale!==void 0&&(i.clearcoatNormalScale=new se().fromArray(e.clearcoatNormalScale)),e.iridescenceMap!==void 0&&(i.iridescenceMap=n(e.iridescenceMap)),e.iridescenceThicknessMap!==void 0&&(i.iridescenceThicknessMap=n(e.iridescenceThicknessMap)),e.transmissionMap!==void 0&&(i.transmissionMap=n(e.transmissionMap)),e.thicknessMap!==void 0&&(i.thicknessMap=n(e.thicknessMap)),e.anisotropyMap!==void 0&&(i.anisotropyMap=n(e.anisotropyMap)),e.sheenColorMap!==void 0&&(i.sheenColorMap=n(e.sheenColorMap)),e.sheenRoughnessMap!==void 0&&(i.sheenRoughnessMap=n(e.sheenRoughnessMap)),i}setTextures(e){return this.textures=e,this}static createMaterialFromType(e){const t={ShadowMaterial:Jp,SpriteMaterial:wu,RawShaderMaterial:Kp,ShaderMaterial:Ln,PointsMaterial:Tu,MeshPhysicalMaterial:jp,MeshStandardMaterial:Nu,MeshPhongMaterial:Qp,MeshToonMaterial:em,MeshNormalMaterial:tm,MeshLambertMaterial:nm,MeshDepthMaterial:bu,MeshDistanceMaterial:Su,MeshBasicMaterial:hi,MeshMatcapMaterial:im,LineDashedMaterial:sm,LineBasicMaterial:rn,Material:Kt};return new t[e]}}class zc{static decodeText(e){if(console.warn("THREE.LoaderUtils: decodeText() has been deprecated with r165 and will be removed with r175. Use TextDecoder instead."),typeof TextDecoder<"u")return new TextDecoder().decode(e);let t="";for(let n=0,i=e.length;n0){const l=new Fu(t);r=new kr(l),r.setCrossOrigin(this.crossOrigin);for(let c=0,u=e.length;c0){i=new kr(this.manager),i.setCrossOrigin(this.crossOrigin);for(let o=0,a=e.length;o{const p=new sn;p.min.fromArray(v.boxMin),p.max.fromArray(v.boxMax);const m=new Zt;return m.radius=v.sphereRadius,m.center.fromArray(v.sphereCenter),{boxInitialized:v.boxInitialized,box:p,sphereInitialized:v.sphereInitialized,sphere:m}}),o._maxGeometryCount=e.maxGeometryCount,o._maxVertexCount=e.maxVertexCount,o._maxIndexCount=e.maxIndexCount,o._geometryInitialized=e.geometryInitialized,o._geometryCount=e.geometryCount,o._matricesTexture=c(e.matricesTexture.uuid),e.colorsTexture!==void 0&&(o._colorsTexture=c(e.colorsTexture.uuid));break;case"LOD":o=new Dp;break;case"Line":o=new Ci(a(e.geometry),l(e.material));break;case"LineLoop":o=new kp(a(e.geometry),l(e.material));break;case"LineSegments":o=new Xn(a(e.geometry),l(e.material));break;case"PointCloud":case"Points":o=new Bp(a(e.geometry),l(e.material));break;case"Sprite":o=new Np(l(e.material));break;case"Group":o=new Fs;break;case"Bone":o=new Au;break;default:o=new ct}if(o.uuid=e.uuid,e.name!==void 0&&(o.name=e.name),e.matrix!==void 0?(o.matrix.fromArray(e.matrix),e.matrixAutoUpdate!==void 0&&(o.matrixAutoUpdate=e.matrixAutoUpdate),o.matrixAutoUpdate&&o.matrix.decompose(o.position,o.quaternion,o.scale)):(e.position!==void 0&&o.position.fromArray(e.position),e.rotation!==void 0&&o.rotation.fromArray(e.rotation),e.quaternion!==void 0&&o.quaternion.fromArray(e.quaternion),e.scale!==void 0&&o.scale.fromArray(e.scale)),e.up!==void 0&&o.up.fromArray(e.up),e.castShadow!==void 0&&(o.castShadow=e.castShadow),e.receiveShadow!==void 0&&(o.receiveShadow=e.receiveShadow),e.shadow&&(e.shadow.bias!==void 0&&(o.shadow.bias=e.shadow.bias),e.shadow.normalBias!==void 0&&(o.shadow.normalBias=e.shadow.normalBias),e.shadow.radius!==void 0&&(o.shadow.radius=e.shadow.radius),e.shadow.mapSize!==void 0&&o.shadow.mapSize.fromArray(e.shadow.mapSize),e.shadow.camera!==void 0&&(o.shadow.camera=this.parseObject(e.shadow.camera))),e.visible!==void 0&&(o.visible=e.visible),e.frustumCulled!==void 0&&(o.frustumCulled=e.frustumCulled),e.renderOrder!==void 0&&(o.renderOrder=e.renderOrder),e.userData!==void 0&&(o.userData=e.userData),e.layers!==void 0&&(o.layers.mask=e.layers),e.children!==void 0){const d=e.children;for(let f=0;f"u"&&console.warn("THREE.ImageBitmapLoader: createImageBitmap() not supported."),typeof fetch>"u"&&console.warn("THREE.ImageBitmapLoader: fetch() not supported."),this.options={premultiplyAlpha:"none"}}setOptions(e){return this.options=e,this}load(e,t,n,i){e===void 0&&(e=""),this.path!==void 0&&(e=this.path+e),e=this.manager.resolveURL(e);const r=this,o=ni.get(e);if(o!==void 0){if(r.manager.itemStart(e),o.then){o.then(c=>{t&&t(c),r.manager.itemEnd(e)}).catch(c=>{i&&i(c)});return}return setTimeout(function(){t&&t(o),r.manager.itemEnd(e)},0),o}const a={};a.credentials=this.crossOrigin==="anonymous"?"same-origin":"include",a.headers=this.requestHeader;const l=fetch(e,a).then(function(c){return c.blob()}).then(function(c){return createImageBitmap(c,Object.assign(r.options,{colorSpaceConversion:"none"}))}).then(function(c){return ni.add(e,c),t&&t(c),r.manager.itemEnd(e),c}).catch(function(c){i&&i(c),ni.remove(e),r.manager.itemError(e),r.manager.itemEnd(e)});ni.add(e,l),r.manager.itemStart(e)}}let Xo;class Bu{static getContext(){return Xo===void 0&&(Xo=new(window.AudioContext||window.webkitAudioContext)),Xo}static setContext(e){Xo=e}}class CT extends on{constructor(e){super(e)}load(e,t,n,i){const r=this,o=new Wn(this.manager);o.setResponseType("arraybuffer"),o.setPath(this.path),o.setRequestHeader(this.requestHeader),o.setWithCredentials(this.withCredentials),o.load(e,function(l){try{const c=l.slice(0);Bu.getContext().decodeAudioData(c,function(h){t(h)}).catch(a)}catch(c){a(c)}},n,i);function a(l){i?i(l):console.error(l),r.manager.itemError(e)}}}const yd=new qe,xd=new qe,Hi=new qe;class PT{constructor(){this.type="StereoCamera",this.aspect=1,this.eyeSep=.064,this.cameraL=new Ut,this.cameraL.layers.enable(1),this.cameraL.matrixAutoUpdate=!1,this.cameraR=new Ut,this.cameraR.layers.enable(2),this.cameraR.matrixAutoUpdate=!1,this._cache={focus:null,fov:null,aspect:null,near:null,far:null,zoom:null,eyeSep:null}}update(e){const t=this._cache;if(t.focus!==e.focus||t.fov!==e.fov||t.aspect!==e.aspect*this.aspect||t.near!==e.near||t.far!==e.far||t.zoom!==e.zoom||t.eyeSep!==this.eyeSep){t.focus=e.focus,t.fov=e.fov,t.aspect=e.aspect*this.aspect,t.near=e.near,t.far=e.far,t.zoom=e.zoom,t.eyeSep=this.eyeSep,Hi.copy(e.projectionMatrix);const i=t.eyeSep/2,r=i*t.near/t.focus,o=t.near*Math.tan(ns*t.fov*.5)/t.zoom;let a,l;xd.elements[12]=-i,yd.elements[12]=i,a=-o*t.aspect+r,l=o*t.aspect+r,Hi.elements[0]=2*t.near/(l-a),Hi.elements[8]=(l+a)/(l-a),this.cameraL.projectionMatrix.copy(Hi),a=-o*t.aspect-r,l=o*t.aspect-r,Hi.elements[0]=2*t.near/(l-a),Hi.elements[8]=(l+a)/(l-a),this.cameraR.projectionMatrix.copy(Hi)}this.cameraL.matrixWorld.copy(e.matrixWorld).multiply(xd),this.cameraR.matrixWorld.copy(e.matrixWorld).multiply(yd)}}class il{constructor(e=!0){this.autoStart=e,this.startTime=0,this.oldTime=0,this.elapsedTime=0,this.running=!1}start(){this.startTime=Md(),this.oldTime=this.startTime,this.elapsedTime=0,this.running=!0}stop(){this.getElapsedTime(),this.running=!1,this.autoStart=!1}getElapsedTime(){return this.getDelta(),this.elapsedTime}getDelta(){let e=0;if(this.autoStart&&!this.running)return this.start(),0;if(this.running){const t=Md();e=(t-this.oldTime)/1e3,this.oldTime=t,this.elapsedTime+=e}return e}}function Md(){return(typeof performance>"u"?Date:performance).now()}const Gi=new N,bd=new hn,RT=new N,Wi=new N;class IT extends ct{constructor(){super(),this.type="AudioListener",this.context=Bu.getContext(),this.gain=this.context.createGain(),this.gain.connect(this.context.destination),this.filter=null,this.timeDelta=0,this._clock=new il}getInput(){return this.gain}removeFilter(){return this.filter!==null&&(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination),this.gain.connect(this.context.destination),this.filter=null),this}getFilter(){return this.filter}setFilter(e){return this.filter!==null?(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination)):this.gain.disconnect(this.context.destination),this.filter=e,this.gain.connect(this.filter),this.filter.connect(this.context.destination),this}getMasterVolume(){return this.gain.gain.value}setMasterVolume(e){return this.gain.gain.setTargetAtTime(e,this.context.currentTime,.01),this}updateMatrixWorld(e){super.updateMatrixWorld(e);const t=this.context.listener,n=this.up;if(this.timeDelta=this._clock.getDelta(),this.matrixWorld.decompose(Gi,bd,RT),Wi.set(0,0,-1).applyQuaternion(bd),t.positionX){const i=this.context.currentTime+this.timeDelta;t.positionX.linearRampToValueAtTime(Gi.x,i),t.positionY.linearRampToValueAtTime(Gi.y,i),t.positionZ.linearRampToValueAtTime(Gi.z,i),t.forwardX.linearRampToValueAtTime(Wi.x,i),t.forwardY.linearRampToValueAtTime(Wi.y,i),t.forwardZ.linearRampToValueAtTime(Wi.z,i),t.upX.linearRampToValueAtTime(n.x,i),t.upY.linearRampToValueAtTime(n.y,i),t.upZ.linearRampToValueAtTime(n.z,i)}else t.setPosition(Gi.x,Gi.y,Gi.z),t.setOrientation(Wi.x,Wi.y,Wi.z,n.x,n.y,n.z)}}class Mm extends ct{constructor(e){super(),this.type="Audio",this.listener=e,this.context=e.context,this.gain=this.context.createGain(),this.gain.connect(e.getInput()),this.autoplay=!1,this.buffer=null,this.detune=0,this.loop=!1,this.loopStart=0,this.loopEnd=0,this.offset=0,this.duration=void 0,this.playbackRate=1,this.isPlaying=!1,this.hasPlaybackControl=!0,this.source=null,this.sourceType="empty",this._startedAt=0,this._progress=0,this._connected=!1,this.filters=[]}getOutput(){return this.gain}setNodeSource(e){return this.hasPlaybackControl=!1,this.sourceType="audioNode",this.source=e,this.connect(),this}setMediaElementSource(e){return this.hasPlaybackControl=!1,this.sourceType="mediaNode",this.source=this.context.createMediaElementSource(e),this.connect(),this}setMediaStreamSource(e){return this.hasPlaybackControl=!1,this.sourceType="mediaStreamNode",this.source=this.context.createMediaStreamSource(e),this.connect(),this}setBuffer(e){return this.buffer=e,this.sourceType="buffer",this.autoplay&&this.play(),this}play(e=0){if(this.isPlaying===!0){console.warn("THREE.Audio: Audio is already playing.");return}if(this.hasPlaybackControl===!1){console.warn("THREE.Audio: this Audio has no playback control.");return}this._startedAt=this.context.currentTime+e;const t=this.context.createBufferSource();return t.buffer=this.buffer,t.loop=this.loop,t.loopStart=this.loopStart,t.loopEnd=this.loopEnd,t.onended=this.onEnded.bind(this),t.start(this._startedAt,this._progress+this.offset,this.duration),this.isPlaying=!0,this.source=t,this.setDetune(this.detune),this.setPlaybackRate(this.playbackRate),this.connect()}pause(){if(this.hasPlaybackControl===!1){console.warn("THREE.Audio: this Audio has no playback control.");return}return this.isPlaying===!0&&(this._progress+=Math.max(this.context.currentTime-this._startedAt,0)*this.playbackRate,this.loop===!0&&(this._progress=this._progress%(this.duration||this.buffer.duration)),this.source.stop(),this.source.onended=null,this.isPlaying=!1),this}stop(){if(this.hasPlaybackControl===!1){console.warn("THREE.Audio: this Audio has no playback control.");return}return this._progress=0,this.source!==null&&(this.source.stop(),this.source.onended=null),this.isPlaying=!1,this}connect(){if(this.filters.length>0){this.source.connect(this.filters[0]);for(let e=1,t=this.filters.length;e0){this.source.disconnect(this.filters[0]);for(let e=1,t=this.filters.length;e0&&this._mixBufferRegionAdditive(n,i,this._addIndex*t,1,t);for(let l=t,c=t+t;l!==c;++l)if(n[l]!==n[l+t]){a.setValue(n,i);break}}saveOriginalState(){const e=this.binding,t=this.buffer,n=this.valueSize,i=n*this._origIndex;e.getValue(t,i);for(let r=n,o=i;r!==o;++r)t[r]=t[i+r%n];this._setIdentity(),this.cumulativeWeight=0,this.cumulativeWeightAdditive=0}restoreOriginalState(){const e=this.valueSize*3;this.binding.setValue(this.buffer,e)}_setAdditiveIdentityNumeric(){const e=this._addIndex*this.valueSize,t=e+this.valueSize;for(let n=e;n=.5)for(let o=0;o!==r;++o)e[t+o]=e[n+o]}_slerp(e,t,n,i){hn.slerpFlat(e,t,e,t,e,n,i)}_slerpAdditive(e,t,n,i,r){const o=this._workIndex*r;hn.multiplyQuaternionsFlat(e,o,e,t,e,n),hn.slerpFlat(e,t,e,t,e,o,i)}_lerp(e,t,n,i,r){const o=1-i;for(let a=0;a!==r;++a){const l=t+a;e[l]=e[l]*o+e[n+a]*i}}_lerpAdditive(e,t,n,i,r){for(let o=0;o!==r;++o){const a=t+o;e[a]=e[a]+e[n+o]*i}}}const zu="\\[\\]\\.:\\/",UT=new RegExp("["+zu+"]","g"),Vu="[^"+zu+"]",OT="[^"+zu.replace("\\.","")+"]",FT=/((?:WC+[\/:])*)/.source.replace("WC",Vu),kT=/(WCOD+)?/.source.replace("WCOD",OT),BT=/(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC",Vu),zT=/\.(WC+)(?:\[(.+)\])?/.source.replace("WC",Vu),VT=new RegExp("^"+FT+kT+BT+zT+"$"),HT=["material","materials","bones","map"];class GT{constructor(e,t,n){const i=n||lt.parseTrackName(t);this._targetGroup=e,this._bindings=e.subscribe_(t,i)}getValue(e,t){this.bind();const n=this._targetGroup.nCachedObjects_,i=this._bindings[n];i!==void 0&&i.getValue(e,t)}setValue(e,t){const n=this._bindings;for(let i=this._targetGroup.nCachedObjects_,r=n.length;i!==r;++i)n[i].setValue(e,t)}bind(){const e=this._bindings;for(let t=this._targetGroup.nCachedObjects_,n=e.length;t!==n;++t)e[t].bind()}unbind(){const e=this._bindings;for(let t=this._targetGroup.nCachedObjects_,n=e.length;t!==n;++t)e[t].unbind()}}class lt{constructor(e,t,n){this.path=t,this.parsedPath=n||lt.parseTrackName(t),this.node=lt.findNode(e,this.parsedPath.nodeName),this.rootNode=e,this.getValue=this._getValue_unbound,this.setValue=this._setValue_unbound}static create(e,t,n){return e&&e.isAnimationObjectGroup?new lt.Composite(e,t,n):new lt(e,t,n)}static sanitizeNodeName(e){return e.replace(/\s/g,"_").replace(UT,"")}static parseTrackName(e){const t=VT.exec(e);if(t===null)throw new Error("PropertyBinding: Cannot parse trackName: "+e);const n={nodeName:t[2],objectName:t[3],objectIndex:t[4],propertyName:t[5],propertyIndex:t[6]},i=n.nodeName&&n.nodeName.lastIndexOf(".");if(i!==void 0&&i!==-1){const r=n.nodeName.substring(i+1);HT.indexOf(r)!==-1&&(n.nodeName=n.nodeName.substring(0,i),n.objectName=r)}if(n.propertyName===null||n.propertyName.length===0)throw new Error("PropertyBinding: can not parse propertyName from trackName: "+e);return n}static findNode(e,t){if(t===void 0||t===""||t==="."||t===-1||t===e.name||t===e.uuid)return e;if(e.skeleton){const n=e.skeleton.getBoneByName(t);if(n!==void 0)return n}if(e.children){const n=function(r){for(let o=0;o=r){const h=r++,d=e[h];t[d.uuid]=u,e[u]=d,t[c]=h,e[h]=l;for(let f=0,g=i;f!==g;++f){const v=n[f],p=v[h],m=v[u];v[u]=p,v[h]=m}}}this.nCachedObjects_=r}uncache(){const e=this._objects,t=this._indicesByUUID,n=this._bindings,i=n.length;let r=this.nCachedObjects_,o=e.length;for(let a=0,l=arguments.length;a!==l;++a){const c=arguments[a],u=c.uuid,h=t[u];if(h!==void 0)if(delete t[u],h0&&(t[f.uuid]=h),e[h]=f,e.pop();for(let g=0,v=i;g!==v;++g){const p=n[g];p[h]=p[d],p.pop()}}}this.nCachedObjects_=r}subscribe_(e,t){const n=this._bindingsIndicesByPath;let i=n[e];const r=this._bindings;if(i!==void 0)return r[i];const o=this._paths,a=this._parsedPaths,l=this._objects,c=l.length,u=this.nCachedObjects_,h=new Array(c);i=r.length,n[e]=i,o.push(e),a.push(t),r.push(h);for(let d=u,f=l.length;d!==f;++d){const g=l[d];h[d]=new lt(g,e,t)}return h}unsubscribe_(e){const t=this._bindingsIndicesByPath,n=t[e];if(n!==void 0){const i=this._paths,r=this._parsedPaths,o=this._bindings,a=o.length-1,l=o[a],c=e[a];t[c]=n,o[n]=l,o.pop(),r[n]=r[a],r.pop(),i[n]=i[a],i.pop()}}}class Sm{constructor(e,t,n=null,i=t.blendMode){this._mixer=e,this._clip=t,this._localRoot=n,this.blendMode=i;const r=t.tracks,o=r.length,a=new Array(o),l={endingStart:Ji,endingEnd:Ji};for(let c=0;c!==o;++c){const u=r[c].createInterpolant(null);a[c]=u,u.settings=l}this._interpolantSettings=l,this._interpolants=a,this._propertyBindings=new Array(o),this._cacheIndex=null,this._byClipCacheIndex=null,this._timeScaleInterpolant=null,this._weightInterpolant=null,this.loop=np,this._loopCount=-1,this._startTime=null,this.time=0,this.timeScale=1,this._effectiveTimeScale=1,this.weight=1,this._effectiveWeight=1,this.repetitions=1/0,this.paused=!1,this.enabled=!0,this.clampWhenFinished=!1,this.zeroSlopeAtStart=!0,this.zeroSlopeAtEnd=!0}play(){return this._mixer._activateAction(this),this}stop(){return this._mixer._deactivateAction(this),this.reset()}reset(){return this.paused=!1,this.enabled=!0,this.time=0,this._loopCount=-1,this._startTime=null,this.stopFading().stopWarping()}isRunning(){return this.enabled&&!this.paused&&this.timeScale!==0&&this._startTime===null&&this._mixer._isActiveAction(this)}isScheduled(){return this._mixer._isActiveAction(this)}startAt(e){return this._startTime=e,this}setLoop(e,t){return this.loop=e,this.repetitions=t,this}setEffectiveWeight(e){return this.weight=e,this._effectiveWeight=this.enabled?e:0,this.stopFading()}getEffectiveWeight(){return this._effectiveWeight}fadeIn(e){return this._scheduleFading(e,0,1)}fadeOut(e){return this._scheduleFading(e,1,0)}crossFadeFrom(e,t,n){if(e.fadeOut(t),this.fadeIn(t),n){const i=this._clip.duration,r=e._clip.duration,o=r/i,a=i/r;e.warp(1,o,t),this.warp(a,1,t)}return this}crossFadeTo(e,t,n){return e.crossFadeFrom(this,t,n)}stopFading(){const e=this._weightInterpolant;return e!==null&&(this._weightInterpolant=null,this._mixer._takeBackControlInterpolant(e)),this}setEffectiveTimeScale(e){return this.timeScale=e,this._effectiveTimeScale=this.paused?0:e,this.stopWarping()}getEffectiveTimeScale(){return this._effectiveTimeScale}setDuration(e){return this.timeScale=this._clip.duration/e,this.stopWarping()}syncWith(e){return this.time=e.time,this.timeScale=e.timeScale,this.stopWarping()}halt(e){return this.warp(this._effectiveTimeScale,0,e)}warp(e,t,n){const i=this._mixer,r=i.time,o=this.timeScale;let a=this._timeScaleInterpolant;a===null&&(a=i._lendControlInterpolant(),this._timeScaleInterpolant=a);const l=a.parameterPositions,c=a.sampleValues;return l[0]=r,l[1]=r+n,c[0]=e/o,c[1]=t/o,this}stopWarping(){const e=this._timeScaleInterpolant;return e!==null&&(this._timeScaleInterpolant=null,this._mixer._takeBackControlInterpolant(e)),this}getMixer(){return this._mixer}getClip(){return this._clip}getRoot(){return this._localRoot||this._mixer._root}_update(e,t,n,i){if(!this.enabled){this._updateWeight(e);return}const r=this._startTime;if(r!==null){const l=(e-r)*n;l<0||n===0?t=0:(this._startTime=null,t=n*l)}t*=this._updateTimeScale(e);const o=this._updateTime(t),a=this._updateWeight(e);if(a>0){const l=this._interpolants,c=this._propertyBindings;switch(this.blendMode){case fu:for(let u=0,h=l.length;u!==h;++u)l[u].evaluate(o),c[u].accumulateAdditive(a);break;case Ra:default:for(let u=0,h=l.length;u!==h;++u)l[u].evaluate(o),c[u].accumulate(i,a)}}}_updateWeight(e){let t=0;if(this.enabled){t=this.weight;const n=this._weightInterpolant;if(n!==null){const i=n.evaluate(e)[0];t*=i,e>n.parameterPositions[1]&&(this.stopFading(),i===0&&(this.enabled=!1))}}return this._effectiveWeight=t,t}_updateTimeScale(e){let t=0;if(!this.paused){t=this.timeScale;const n=this._timeScaleInterpolant;if(n!==null){const i=n.evaluate(e)[0];t*=i,e>n.parameterPositions[1]&&(this.stopWarping(),t===0?this.paused=!0:this.timeScale=t)}}return this._effectiveTimeScale=t,t}_updateTime(e){const t=this._clip.duration,n=this.loop;let i=this.time+e,r=this._loopCount;const o=n===ip;if(e===0)return r===-1?i:o&&(r&1)===1?t-i:i;if(n===tp){r===-1&&(this._loopCount=0,this._setEndings(!0,!0,!1));e:{if(i>=t)i=t;else if(i<0)i=0;else{this.time=i;break e}this.clampWhenFinished?this.paused=!0:this.enabled=!1,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:e<0?-1:1})}}else{if(r===-1&&(e>=0?(r=0,this._setEndings(!0,this.repetitions===0,o)):this._setEndings(this.repetitions===0,!0,o)),i>=t||i<0){const a=Math.floor(i/t);i-=t*a,r+=Math.abs(a);const l=this.repetitions-r;if(l<=0)this.clampWhenFinished?this.paused=!0:this.enabled=!1,i=e>0?t:0,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:e>0?1:-1});else{if(l===1){const c=e<0;this._setEndings(c,!c,o)}else this._setEndings(!1,!1,o);this._loopCount=r,this.time=i,this._mixer.dispatchEvent({type:"loop",action:this,loopDelta:a})}}else this.time=i;if(o&&(r&1)===1)return t-i}return i}_setEndings(e,t,n){const i=this._interpolantSettings;n?(i.endingStart=Ki,i.endingEnd=Ki):(e?i.endingStart=this.zeroSlopeAtStart?Ki:Ji:i.endingStart=Ar,t?i.endingEnd=this.zeroSlopeAtEnd?Ki:Ji:i.endingEnd=Ar)}_scheduleFading(e,t,n){const i=this._mixer,r=i.time;let o=this._weightInterpolant;o===null&&(o=i._lendControlInterpolant(),this._weightInterpolant=o);const a=o.parameterPositions,l=o.sampleValues;return a[0]=r,l[0]=t,a[1]=r+e,l[1]=n,this}}const $T=new Float32Array(1);class XT extends ui{constructor(e){super(),this._root=e,this._initMemoryManager(),this._accuIndex=0,this.time=0,this.timeScale=1}_bindAction(e,t){const n=e._localRoot||this._root,i=e._clip.tracks,r=i.length,o=e._propertyBindings,a=e._interpolants,l=n.uuid,c=this._bindingsByRootAndName;let u=c[l];u===void 0&&(u={},c[l]=u);for(let h=0;h!==r;++h){const d=i[h],f=d.name;let g=u[f];if(g!==void 0)++g.referenceCount,o[h]=g;else{if(g=o[h],g!==void 0){g._cacheIndex===null&&(++g.referenceCount,this._addInactiveBinding(g,l,f));continue}const v=t&&t._propertyBindings[h].binding.parsedPath;g=new bm(lt.create(n,f,v),d.ValueTypeName,d.getValueSize()),++g.referenceCount,this._addInactiveBinding(g,l,f),o[h]=g}a[h].resultBuffer=g.buffer}}_activateAction(e){if(!this._isActiveAction(e)){if(e._cacheIndex===null){const n=(e._localRoot||this._root).uuid,i=e._clip.uuid,r=this._actionsByClip[i];this._bindAction(e,r&&r.knownActions[0]),this._addInactiveAction(e,i,n)}const t=e._propertyBindings;for(let n=0,i=t.length;n!==i;++n){const r=t[n];r.useCount++===0&&(this._lendBinding(r),r.saveOriginalState())}this._lendAction(e)}}_deactivateAction(e){if(this._isActiveAction(e)){const t=e._propertyBindings;for(let n=0,i=t.length;n!==i;++n){const r=t[n];--r.useCount===0&&(r.restoreOriginalState(),this._takeBackBinding(r))}this._takeBackAction(e)}}_initMemoryManager(){this._actions=[],this._nActiveActions=0,this._actionsByClip={},this._bindings=[],this._nActiveBindings=0,this._bindingsByRootAndName={},this._controlInterpolants=[],this._nActiveControlInterpolants=0;const e=this;this.stats={actions:{get total(){return e._actions.length},get inUse(){return e._nActiveActions}},bindings:{get total(){return e._bindings.length},get inUse(){return e._nActiveBindings}},controlInterpolants:{get total(){return e._controlInterpolants.length},get inUse(){return e._nActiveControlInterpolants}}}}_isActiveAction(e){const t=e._cacheIndex;return t!==null&&t=0;--n)e[n].stop();return this}update(e){e*=this.timeScale;const t=this._actions,n=this._nActiveActions,i=this.time+=e,r=Math.sign(e),o=this._accuIndex^=1;for(let c=0;c!==n;++c)t[c]._update(i,e,r,o);const a=this._bindings,l=this._nActiveBindings;for(let c=0;c!==l;++c)a[c].apply(o);return this}setTime(e){this.time=0;for(let t=0;tthis.max.x||e.ythis.max.y)}containsBox(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y}getParameter(e,t){return t.set((e.x-this.min.x)/(this.max.x-this.min.x),(e.y-this.min.y)/(this.max.y-this.min.y))}intersectsBox(e){return!(e.max.xthis.max.x||e.max.ythis.max.y)}clampPoint(e,t){return t.copy(e).clamp(this.min,this.max)}distanceToPoint(e){return this.clampPoint(e,Td).distanceTo(e)}intersect(e){return this.min.max(e.min),this.max.min(e.max),this.isEmpty()&&this.makeEmpty(),this}union(e){return this.min.min(e.min),this.max.max(e.max),this}translate(e){return this.min.add(e),this.max.add(e),this}equals(e){return e.min.equals(this.min)&&e.max.equals(this.max)}}const Ed=new N,qo=new N;class QT{constructor(e=new N,t=new N){this.start=e,this.end=t}set(e,t){return this.start.copy(e),this.end.copy(t),this}copy(e){return this.start.copy(e.start),this.end.copy(e.end),this}getCenter(e){return e.addVectors(this.start,this.end).multiplyScalar(.5)}delta(e){return e.subVectors(this.end,this.start)}distanceSq(){return this.start.distanceToSquared(this.end)}distance(){return this.start.distanceTo(this.end)}at(e,t){return this.delta(t).multiplyScalar(e).add(this.start)}closestPointToPointParameter(e,t){Ed.subVectors(e,this.start),qo.subVectors(this.end,this.start);const n=qo.dot(qo);let r=qo.dot(Ed)/n;return t&&(r=Ct(r,0,1)),r}closestPointToPoint(e,t,n){const i=this.closestPointToPointParameter(e,t);return this.delta(n).multiplyScalar(i).add(this.start)}applyMatrix4(e){return this.start.applyMatrix4(e),this.end.applyMatrix4(e),this}equals(e){return e.start.equals(this.start)&&e.end.equals(this.end)}clone(){return new this.constructor().copy(this)}}const Cd=new N;class eE extends ct{constructor(e,t){super(),this.light=e,this.matrixAutoUpdate=!1,this.color=t,this.type="SpotLightHelper";const n=new it,i=[0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,-1,0,1,0,0,0,0,1,1,0,0,0,0,-1,1];for(let o=0,a=1,l=32;o1)for(let h=0;h.99999)this.quaternion.set(0,0,0,1);else if(e.y<-.99999)this.quaternion.set(1,0,0,0);else{Nd.set(e.z,0,-e.x).normalize();const t=Math.acos(e.y);this.quaternion.setFromAxisAngle(Nd,t)}}setLength(e,t=e*.2,n=t*.2){this.line.scale.set(1,Math.max(1e-4,e-t),1),this.line.updateMatrix(),this.cone.scale.set(n,t,n),this.cone.position.y=e,this.cone.updateMatrix()}setColor(e){this.line.material.color.set(e),this.cone.material.color.set(e)}copy(e){return super.copy(e,!1),this.line.copy(e.line),this.cone.copy(e.cone),this}dispose(){this.line.geometry.dispose(),this.line.material.dispose(),this.cone.geometry.dispose(),this.cone.material.dispose()}}class fE extends Xn{constructor(e=1){const t=[0,0,0,e,0,0,0,0,0,0,e,0,0,0,0,0,0,e],n=[1,0,0,1,.6,0,0,1,0,.6,1,0,0,0,1,0,.6,1],i=new it;i.setAttribute("position",new Ne(t,3)),i.setAttribute("color",new Ne(n,3));const r=new rn({vertexColors:!0,toneMapped:!1});super(i,r),this.type="AxesHelper"}setColors(e,t,n){const i=new Pe,r=this.geometry.attributes.color.array;return i.set(e),i.toArray(r,0),i.toArray(r,3),i.set(t),i.toArray(r,6),i.toArray(r,9),i.set(n),i.toArray(r,12),i.toArray(r,15),this.geometry.attributes.color.needsUpdate=!0,this}dispose(){this.geometry.dispose(),this.material.dispose()}}class bi{constructor(){this.type="ShapePath",this.color=new Pe,this.subPaths=[],this.currentPath=null}moveTo(e,t){return this.currentPath=new Ai,this.subPaths.push(this.currentPath),this.currentPath.moveTo(e,t),this}lineTo(e,t){return this.currentPath.lineTo(e,t),this}quadraticCurveTo(e,t,n,i){return this.currentPath.quadraticCurveTo(e,t,n,i),this}bezierCurveTo(e,t,n,i,r,o){return this.currentPath.bezierCurveTo(e,t,n,i,r,o),this}splineThru(e){return this.currentPath.splineThru(e),this}toShapes(e){function t(m){const y=[];for(let _=0,x=m.length;_Number.EPSILON){if(M<0&&(E=y[b],w=-w,I=y[A],M=-M),m.yI.y)continue;if(m.y===E.y){if(m.x===E.x)return!0}else{const F=M*(m.x-E.x)-w*(m.y-E.y);if(F===0)return!0;if(F<0)continue;x=!x}}else{if(m.y!==E.y)continue;if(I.x<=m.x&&m.x<=E.x||E.x<=m.x&&m.x<=I.x)return!0}}return x}const i=Pn.isClockWise,r=this.subPaths;if(r.length===0)return[];let o,a,l;const c=[];if(r.length===1)return a=r[0],l=new Ti,l.curves=a.curves,c.push(l),c;let u=!i(r[0].getPoints());u=e?!u:u;const h=[],d=[];let f=[],g=0,v;d[g]=void 0,f[g]=[];for(let m=0,y=r.length;m1){let m=!1,y=0;for(let _=0,x=d.length;_0&&m===!1&&(f=h)}let p;for(let m=0,y=d.length;m{s.delete(i)};return{on:i=>{s.add(i);const r=()=>e(i);return $n(r),{off:r}},off:e,trigger:(...i)=>Promise.all(Array.from(s).map(r=>r(...i)))}}function bt(s){return typeof s=="function"?s():ee(s)}const Hc=typeof window<"u"&&typeof document<"u";typeof WorkerGlobalScope<"u"&&globalThis instanceof WorkerGlobalScope;const gE=s=>s!=null,vE=Object.prototype.toString,_E=s=>vE.call(s)==="[object Object]",Gc=()=>{};function yE(s,e){function t(...n){return new Promise((i,r)=>{Promise.resolve(s(()=>e.apply(this,n),{fn:e,thisArg:this,args:n})).then(i).catch(r)})}return t}function xE(s,e={}){let t,n,i=Gc;const r=a=>{clearTimeout(a),i(),i=Gc};return a=>{const l=bt(s),c=bt(e.maxWait);return t&&r(t),l<=0||c!==void 0&&c<=0?(n&&(r(n),n=null),Promise.resolve(a())):new Promise((u,h)=>{i=e.rejectOnCancel?h:u,c&&!n&&(n=setTimeout(()=>{t&&r(t),n=null,u(a())},c)),t=setTimeout(()=>{n&&r(n),n=null,u(a())},l)})}}function ME(s,e,t=!1){return e.reduce((n,i)=>(i in s&&(!t||s[i]!==void 0)&&(n[i]=s[i]),n),{})}function bE(s){return ma()}function SE(s,e=200,t={}){return yE(xE(e,t),s)}function Dd(s,e=200,t={}){const n=Ge(s.value),i=SE(()=>{n.value=s.value},e,t);return wt(s,()=>i()),n}function wE(s,e={}){if(!Jd(s))return tg(s);const t=Array.isArray(s.value)?Array.from({length:s.value.length}):{};for(const n in s.value)t[n]=ng(()=>({get(){return s.value[n]},set(i){var r;if((r=bt(e.replaceRef))!=null?r:!0)if(Array.isArray(s.value)){const a=[...s.value];a[n]=i,s.value=a}else{const a={...s.value,[n]:i};Object.setPrototypeOf(a,Object.getPrototypeOf(s.value)),s.value=a}else s.value[n]=i}}));return t}function Gu(s,e=!0,t){bE()?Nn(s,t):e?s():Jc(s)}function AE(s,e=1e3,t={}){const{immediate:n=!0,immediateCallback:i=!1}=t;let r=null;const o=Ge(!1);function a(){r&&(clearInterval(r),r=null)}function l(){o.value=!1,a()}function c(){const u=bt(e);u<=0||(o.value=!0,i&&s(),a(),r=setInterval(s,u))}if(n&&Hc&&c(),Jd(e)||typeof e=="function"){const u=wt(e,()=>{o.value&&Hc&&c()});$n(u)}return $n(l),{isActive:o,pause:l,resume:c}}function Cn(s){var e;const t=bt(s);return(e=t==null?void 0:t.$el)!=null?e:t}const di=Hc?window:void 0;function Br(...s){let e,t,n,i;if(typeof s[0]=="string"||Array.isArray(s[0])?([t,n,i]=s,e=di):[e,t,n,i]=s,!e)return Gc;Array.isArray(t)||(t=[t]),Array.isArray(n)||(n=[n]);const r=[],o=()=>{r.forEach(u=>u()),r.length=0},a=(u,h,d,f)=>(u.addEventListener(h,d,f),()=>u.removeEventListener(h,d,f)),l=wt(()=>[Cn(e),bt(i)],([u,h])=>{if(o(),!u)return;const d=_E(h)?{...h}:h;r.push(...t.flatMap(f=>n.map(g=>a(u,f,g,d))))},{immediate:!0,flush:"post"}),c=()=>{l(),o()};return $n(c),c}function TE(){const s=Ge(!1),e=ma();return e&&Nn(()=>{s.value=!0},e),s}function sl(s){const e=TE();return ze(()=>(e.value,!!s()))}function EE(s,e,t={}){const{window:n=di,...i}=t;let r;const o=sl(()=>n&&"MutationObserver"in n),a=()=>{r&&(r.disconnect(),r=void 0)},l=ze(()=>{const d=bt(s),f=(Array.isArray(d)?d:[d]).map(Cn).filter(gE);return new Set(f)}),c=wt(()=>l.value,d=>{a(),o.value&&d.size&&(r=new MutationObserver(e),d.forEach(f=>r.observe(f,i)))},{immediate:!0,flush:"post"}),u=()=>r==null?void 0:r.takeRecords(),h=()=>{a(),c()};return $n(h),{isSupported:o,stop:h,takeRecords:u}}function Wu(s,e={}){const{immediate:t=!0,fpsLimit:n=void 0,window:i=di}=e,r=Ge(!1),o=n?1e3/n:null;let a=0,l=null;function c(d){if(!r.value||!i)return;a||(a=d);const f=d-a;if(o&&ft&&"matchMedia"in t&&typeof t.matchMedia=="function");let i;const r=Ge(!1),o=c=>{r.value=c.matches},a=()=>{i&&("removeEventListener"in i?i.removeEventListener("change",o):i.removeListener(o))},l=Pi(()=>{n.value&&(a(),i=t.matchMedia(bt(s)),"addEventListener"in i?i.addEventListener("change",o):i.addListener(o),r.value=i.matches)});return $n(()=>{l(),a(),i=void 0}),r}function PE(s={}){const{window:e=di}=s,t=Ge(1);if(e){let n=function(){t.value=e.devicePixelRatio,i(),r=e.matchMedia(`(resolution: ${t.value}dppx)`),r.addEventListener("change",n,{once:!0})},i=function(){r==null||r.removeEventListener("change",n)},r;n(),$n(i)}return{pixelRatio:t}}function Em(s,e,t={}){const{window:n=di,...i}=t;let r;const o=sl(()=>n&&"ResizeObserver"in n),a=()=>{r&&(r.disconnect(),r=void 0)},l=ze(()=>Array.isArray(s)?s.map(h=>Cn(h)):[Cn(s)]),c=wt(l,h=>{if(a(),o.value&&n){r=new ResizeObserver(e);for(const d of h)d&&r.observe(d,i)}},{immediate:!0,flush:"post"}),u=()=>{a(),c()};return $n(u),{isSupported:o,stop:u}}function RE(s,e={}){const{reset:t=!0,windowResize:n=!0,windowScroll:i=!0,immediate:r=!0}=e,o=Ge(0),a=Ge(0),l=Ge(0),c=Ge(0),u=Ge(0),h=Ge(0),d=Ge(0),f=Ge(0);function g(){const v=Cn(s);if(!v){t&&(o.value=0,a.value=0,l.value=0,c.value=0,u.value=0,h.value=0,d.value=0,f.value=0);return}const p=v.getBoundingClientRect();o.value=p.height,a.value=p.bottom,l.value=p.left,c.value=p.right,u.value=p.top,h.value=p.width,d.value=p.x,f.value=p.y}return Em(s,g),wt(()=>Cn(s),v=>!v&&g()),EE(s,g,{attributeFilter:["style","class"]}),i&&Br("scroll",g,{capture:!0,passive:!0}),n&&Br("resize",g,{passive:!0}),Gu(()=>{r&&g()}),{height:o,bottom:a,left:l,right:c,top:u,width:h,x:d,y:f,update:g}}function IE(s,e={width:0,height:0},t={}){const{window:n=di,box:i="content-box"}=t,r=ze(()=>{var h,d;return(d=(h=Cn(s))==null?void 0:h.namespaceURI)==null?void 0:d.includes("svg")}),o=Ge(e.width),a=Ge(e.height),{stop:l}=Em(s,([h])=>{const d=i==="border-box"?h.borderBoxSize:i==="content-box"?h.contentBoxSize:h.devicePixelContentBoxSize;if(n&&r.value){const f=Cn(s);if(f){const g=f.getBoundingClientRect();o.value=g.width,a.value=g.height}}else if(d){const f=Array.isArray(d)?d:[d];o.value=f.reduce((g,{inlineSize:v})=>g+v,0),a.value=f.reduce((g,{blockSize:v})=>g+v,0)}else o.value=h.contentRect.width,a.value=h.contentRect.height},t);Gu(()=>{const h=Cn(s);h&&(o.value="offsetWidth"in h?h.offsetWidth:e.width,a.value="offsetHeight"in h?h.offsetHeight:e.height)});const c=wt(()=>Cn(s),h=>{o.value=h?e.width:0,a.value=h?e.height:0});function u(){l(),c()}return{width:o,height:a,stop:u}}function LE(s){var e;const t=Ge(0);if(typeof performance>"u")return t;const n=(e=s==null?void 0:s.every)!=null?e:10;let i=performance.now(),r=0;return Wu(()=>{if(r+=1,r>=n){const o=performance.now(),a=o-i;t.value=Math.round(1e3/(a/r)),i=o,r=0}}),t}function NE(s={}){const e=Ge(),t=sl(()=>typeof performance<"u"&&"memory"in performance);if(t.value){const{interval:n=1e3}=s;AE(()=>{e.value=performance.memory},n,{immediate:s.immediate,immediateCallback:s.immediateCallback})}return{isSupported:t,memory:e}}const Cm={x:0,y:0,pointerId:0,pressure:0,tiltX:0,tiltY:0,width:0,height:0,twist:0,pointerType:null},DE=Object.keys(Cm);function UE(s={}){const{target:e=di}=s,t=Ge(!1),n=Ge(s.initialValue||{});Object.assign(n.value,Cm,n.value);const i=r=>{t.value=!0,!(s.pointerTypes&&!s.pointerTypes.includes(r.pointerType))&&(n.value=ME(r,DE,!1))};if(e){const r={passive:!0};Br(e,["pointerdown","pointermove","pointerup"],i,r),Br(e,"pointerleave",()=>t.value=!1,r)}return{...wE(n),isInside:t}}function OE(s={}){const{window:e=di,initialWidth:t=Number.POSITIVE_INFINITY,initialHeight:n=Number.POSITIVE_INFINITY,listenOrientation:i=!0,includeScrollbar:r=!0}=s,o=Ge(t),a=Ge(n),l=()=>{e&&(r?(o.value=e.innerWidth,a.value=e.innerHeight):(o.value=e.document.documentElement.clientWidth,a.value=e.document.documentElement.clientHeight))};if(l(),Gu(l),Br("resize",l,{passive:!0}),i){const c=CE("(orientation: portrait)");wt(c,()=>l())}return{width:o,height:a}}var FE=Object.defineProperty,kE=(s,e,t)=>e in s?FE(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t,Ud=(s,e,t)=>(kE(s,typeof e!="symbol"?e+"":e,t),t);const BE="@tresjs/core",zE="module",VE="4.0.2",HE="pnpm@9.1.4",GE="Declarative ThreeJS using Vue Components",WE="Alvaro Saburido (https://github.com/alvarosabu/)",$E="MIT",XE=["vue","3d","threejs","three","threejs-vue"],qE=!1,YE={".":{types:"./dist/index.d.ts",import:"./dist/tres.js",require:"./dist/tres.umd.cjs"},"./components":{types:"./dist/src/components/index.d.ts"},"./composables":{types:"./dist/src/composables/index.d.ts"},"./types":{types:"./dist/src/types/index.d.ts"},"./utils":{types:"./dist/src/utils/index.d.ts"},"./*":"./*"},ZE="./dist/tres.js",JE="./dist/tres.js",KE="./dist/index.d.ts",jE=["*.d.ts","dist"],QE={access:"public"},eC={dev:"cd playground && npm run dev",build:"vite build",playground:"cd playground && npm run dev",test:"vitest","test:ci":"vitest run","test:ui":"vitest --ui --coverage.enabled=true",release:"release-it",coverage:"vitest run --coverage",lint:"eslint .","lint:fix":"eslint . --fix","docs:dev":"vitepress dev docs","docs:build":"vitepress build docs","docs:serve":"vitepress serve docs","docs:preview":"vitepress preview docs","docs:contributors":"esno scripts/update-contributors.ts",prepare:"node .husky/install.mjs"},tC={three:">=0.133",vue:">=3.4"},nC={"@alvarosabu/utils":"^3.2.0","@vue/devtools-api":"^6.6.2","@vueuse/core":"^10.10.0"},iC={"@release-it/conventional-changelog":"^8.0.1","@stackblitz/sdk":"^1.10.0","@tresjs/cientos":"3.9.0","@tresjs/eslint-config":"^1.1.0","@types/three":"^0.165.0","@typescript-eslint/eslint-plugin":"^7.11.0","@typescript-eslint/parser":"^7.11.0","@vitejs/plugin-vue":"^5.0.5","@vitest/coverage-c8":"^0.33.0","@vitest/coverage-v8":"^1.6.0","@vitest/ui":"^1.6.0","@vue/test-utils":"^2.4.6",eslint:"^9.4.0","eslint-plugin-vue":"^9.26.0",esno:"^4.7.0",gsap:"^3.12.5",husky:"^9.0.11",jsdom:"^24.1.0",kolorist:"^1.8.0",ohmyfetch:"^0.4.21",pathe:"^1.1.2","release-it":"^17.3.0","rollup-plugin-analyzer":"^4.0.0","rollup-plugin-copy":"^3.5.0","rollup-plugin-visualizer":"^5.12.0",three:"^0.165.0",unocss:"^0.60.4",unplugin:"^1.10.1","unplugin-vue-components":"^0.27.0",vite:"^5.2.12","vite-plugin-banner":"^0.7.1","vite-plugin-dts":"3.9.1","vite-plugin-inspect":"^0.8.4","vite-plugin-require-transform":"^1.0.21","vite-svg-loader":"^5.1.0",vitepress:"1.2.2",vitest:"^1.6.0",vue:"^3.4.27","vue-demi":"^0.14.8"},sC={name:BE,type:zE,version:VE,packageManager:HE,description:GE,author:WE,license:$E,keywords:XE,sideEffects:qE,exports:YE,main:ZE,module:JE,types:KE,files:jE,publishConfig:QE,scripts:eC,peerDependencies:tC,dependencies:nC,devDependencies:iC},rC=({sizes:s})=>{const e=Ge([]),t=ze(()=>e.value[0]),n=o=>{const a=o instanceof qr?o:e.value.find(c=>c.uuid===o);if(!a)return;const l=e.value.filter(({uuid:c})=>c!==a.uuid);e.value=[a,...l]},i=(o,a=!1)=>{e.value.some(({uuid:l})=>l===o.uuid)||(a?n(o):e.value.push(o))},r=o=>{e.value=e.value.filter(({uuid:a})=>a!==o.uuid)};return Pi(()=>{s.aspectRatio.value&&e.value.forEach(o=>{!o.manual&&(o instanceof Ut||oC(o))&&(o instanceof Ut?o.aspect=s.aspectRatio.value:(o.left=s.width.value*-.5,o.right=s.width.value*.5,o.top=s.height.value*.5,o.bottom=s.height.value*-.5),o.updateProjectionMatrix())})}),Gn(()=>{e.value=[]}),{camera:t,cameras:e,registerCamera:i,deregisterCamera:r,setCameraActive:n}};function oC(s){return s.hasOwnProperty("isOrthographicCamera")&&s.isOrthographicCamera}const Pm=An(),Rm=An(),$u=An(),mr=new il;let fa=0,pa=0;const{pause:aC,resume:Od,isActive:lC}=Wu(()=>{Pm.trigger({delta:fa,elapsed:pa,clock:mr}),Rm.trigger({delta:fa,elapsed:pa,clock:mr}),$u.trigger({delta:fa,elapsed:pa,clock:mr})},{immediate:!1});$u.on(()=>{fa=mr.getDelta(),pa=mr.getElapsedTime()});let Fd=!1;const cC=()=>(Fd||(Fd=!0,Od()),{onBeforeLoop:Pm.on,onLoop:Rm.on,onAfterLoop:$u.on,pause:aC,resume:Od,isActive:lC}),Qo="[TresJS ▲ ■ ●] ";function to(){function s(...n){typeof n[0]=="string"?n[0]=Qo+n[0]:n.unshift(Qo),console.error(...n)}function e(...n){typeof n[0]=="string"?n[0]=Qo+n[0]:n.unshift(Qo),console.warn(...n)}function t(n,i){}return{logError:s,logWarning:e,logMessage:t}}function uC(s){return s instanceof Pe?s:Array.isArray(s)?new Pe(...s):new Pe(s)}class hC extends Nt{constructor(...e){super(...e),Ud(this,"type","HightlightMesh"),Ud(this,"createTime"),this.createTime=Date.now()}onBeforeRender(){const e=(Date.now()-this.createTime)/1e3,t=1+.07*Math.sin(2.5*e);this.scale.set(t,t,t)}}const Im=(s,e)=>{for(const t of Object.keys(e))e[t]instanceof Object&&Object.assign(e[t],Im(s[t],e[t]));return Object.assign(s||{},e),s},dC="html,body,base,head,link,meta,style,title,address,article,aside,footer,header,hgroup,h1,h2,h3,h4,h5,h6,nav,section,div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,ruby,s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,output,progress,select,textarea,details,dialog,menu,summary,template,blockquote,iframe,tfoot",fC=gC(dC);function kd(s){return s&&s.nodeType===1}function ea(s){return s.replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}const pC=/\B([A-Z])/g;function mC(s){return s.replace(pC,"-$1").toLowerCase()}function gC(s,e){const t=Object.create(null),n=s.split(",");for(let i=0;i!!t[i]}const Bd=(s,e)=>{if(!e)return;const t=Array.isArray(e)?e:e.match(/([^[.\]])+/g);return t==null?void 0:t.reduce((n,i)=>n&&n[i],s)},vC=(s,e,t)=>{const n=Array.isArray(e)?e:e.match(/([^[.\]])+/g);n&&n.reduce((i,r,o)=>(i[r]===void 0&&(i[r]={}),o===n.length-1&&(i[r]=t),i[r]),s)};function Lm(s,e){if(kd(s)&&kd(e)){const i=s.attributes,r=e.attributes;return i.length!==r.length?!1:Array.from(i).every(({name:o,value:a})=>e.getAttribute(o)===a)}if(s===e)return!0;if(s===null||typeof s!="object"||e===null||typeof e!="object")return!1;const t=Object.keys(s),n=Object.keys(e);if(t.length!==n.length)return!1;for(const i of t)if(!n.includes(i)||!Lm(s[i],e[i]))return!1;return!0}function _C(s,e){if(!Array.isArray(s)||!Array.isArray(e)||s.length!==e.length)return!1;for(let t=0;t{if(l.uuid===e)return l;for(const c of l.children){const u=i(c);if(u)return u}},r=i(s);if(!r){console.warn("Object with UUID not found in the scene.");return}let o=r;for(let l=0;lXu(n)),!(s instanceof ka)){const n=s;s&&((t=s.dispose)==null||t.call(s)),n.geometry&&(n.geometry.dispose(),delete n.geometry),Array.isArray(n.material)?(n.material.forEach(i=>zd(i)),delete n.material):n.material&&(zd(n.material),delete n.material)}}const bC=Number.parseInt(Gr.replace("dev","")),ta={realistic:{shadows:!0,physicallyCorrectLights:!0,outputColorSpace:ln,toneMapping:Ca,toneMappingExposure:3,shadowMap:{enabled:!0,type:su}},flat:{toneMapping:Hn,toneMappingExposure:1}};function SC({canvas:s,options:e,contextParts:{sizes:t,render:n,invalidate:i,advance:r}}){const o=ze(()=>({alpha:bt(e.alpha)??!0,depth:bt(e.depth),canvas:Cn(s),context:bt(e.context),stencil:bt(e.stencil),antialias:bt(e.antialias)??!0,precision:bt(e.precision),powerPreference:bt(e.powerPreference),premultipliedAlpha:bt(e.premultipliedAlpha),preserveDrawingBuffer:bt(e.preserveDrawingBuffer),logarithmicDepthBuffer:bt(e.logarithmicDepthBuffer),failIfMajorPerformanceCaveat:bt(e.failIfMajorPerformanceCaveat)})),a=Rn(new da(o.value));function l(){e.renderMode==="on-demand"&&i()}wt(o,()=>{a.value.dispose(),a.value=new da(o.value),l()}),wt([t.width,t.height],()=>{a.value.setSize(t.width.value,t.height.value),l()},{immediate:!0}),wt(()=>e.clearColor,l);const{pixelRatio:c}=PE();wt(c,()=>{a.value.setPixelRatio(c.value)});const{logError:u}=to(),h=(()=>{const f=new da,g={shadowMap:{enabled:f.shadowMap.enabled,type:f.shadowMap.type},toneMapping:f.toneMapping,toneMappingExposure:f.toneMappingExposure,outputColorSpace:f.outputColorSpace};return f.dispose(),g})(),d=bt(e.renderMode);return d==="on-demand"&&i(),d==="manual"&&setTimeout(()=>{r()},100),Pi(()=>{const f=bt(e.preset);f&&(f in ta||u(`Renderer Preset must be one of these: ${Object.keys(ta).join(", ")}`),Im(a.value,ta[f])),d==="always"&&(n.frames.value=Math.max(1,n.frames.value));const g=(m,y)=>{const _=bt(m),x=()=>{if(f)return Bd(ta[f],y)};if(_!==void 0)return _;const A=x();return A!==void 0?A:Bd(h,y)},v=(m,y)=>vC(a.value,y,g(m,y));v(e.shadows,"shadowMap.enabled"),v(e.toneMapping??Ca,"toneMapping"),v(e.shadowMapType,"shadowMap.type"),bC<150&&v(!e.useLegacyLights,"physicallyCorrectLights"),v(e.outputColorSpace,"outputColorSpace"),v(e.toneMappingExposure,"toneMappingExposure");const p=g(e.clearColor,"clearColor");p&&a.value.setClearColor(p?uC(p):new Pe(0))}),Gn(()=>{a.value.dispose(),a.value.forceContextLoss()}),{renderer:a}}const na=s=>typeof s=="function",wC=s=>s.constructor===Array;function AC(s){const e={nodes:{},materials:{}};return s&&s.traverse(t=>{t.name&&(e.nodes[t.name]=t),t.material&&!e.materials[t.material.name]&&(e.materials[t.material.name]=t.material)}),e}async function TC(s,e,t,n,i){const{logError:r}=to(),o=new s,a=(Array.isArray(e)?e:[e]).map(l=>new Promise((c,u)=>{o.load(l,h=>{h.scene&&Object.assign(h,AC(h.scene)),c(h)},n,h=>u(r("[useLoader] - Failed to load resource",h)))}));return wC(e)?await Promise.all(a):await a[0]}const EC=(s,e)=>{const t=ze(()=>e.renderer.value.domElement),n=Rn([]),{x:i,y:r}=UE({target:t}),o=ze(()=>s.value.filter(ge=>{var Be;return((Be=ge.__tres)==null?void 0:Be.eventCount)>0}));let a=0;const{width:l,height:c,top:u,left:h}=RE(t),d=({x:ge,y:Be})=>{if(t.value)return{x:(ge-h.value)/l.value*2-1,y:-((Be-u.value)/c.value)*2+1}},f=({x:ge,y:Be})=>{if(e.camera.value)return e.raycaster.value.setFromCamera(new se(ge,Be),e.camera.value),n.value=e.raycaster.value.intersectObjects(o.value,!0),n.value},g=ge=>{const Be=d({x:(ge==null?void 0:ge.clientX)??i.value,y:(ge==null?void 0:ge.clientY)??r.value});return Be?f(Be)||[]:[]},v=An(),p=An(),m=An(),y=An(),_=An(),x=An(),A=An(),b=An();function E(ge){const Be={};for(const U in ge)typeof U!="function"&&(Be[U]=ge[U]);return Be}const I=(ge,Be)=>{var U,D,R;const T=E(Be),ie=new N(Be==null?void 0:Be.clientX,Be==null?void 0:Be.clientY,0).unproject((U=e.camera)==null?void 0:U.value);ge.trigger({...T,intersections:n.value,unprojectedPoint:ie,ray:(D=e.raycaster)==null?void 0:D.value.ray,camera:(R=e.camera)==null?void 0:R.value,sourceEvent:Be,delta:a,stopPropagating:!1})};let w;const M=ge=>{g(ge),I(m,ge),w=ge},F=()=>{w&&M(w)};let V,G,q;const ae=ge=>{var Be;V=(Be=n.value[0])==null?void 0:Be.object,a=0,G=new se((ge==null?void 0:ge.clientX)??i.value,(ge==null?void 0:ge.clientY)??r.value),I(_,ge)};let j,oe=!1;const B=ge=>{var Be,U,D;ge instanceof PointerEvent&&(n.value.length===0&&I(x,ge),V===((Be=n.value[0])==null?void 0:Be.object)&&(q=new se((ge==null?void 0:ge.clientX)??i.value,(ge==null?void 0:ge.clientY)??r.value),a=G==null?void 0:G.distanceTo(q),ge.button===0?(I(v,ge),j===((U=n.value[0])==null?void 0:U.object)?oe=!0:(j=(D=n.value[0])==null?void 0:D.object,oe=!1)):ge.button===2&&I(A,ge)),I(y,ge))},Me=ge=>{oe&&(I(p,ge),j=void 0,oe=!1)},be=ge=>I(m,ge),Ae=ge=>I(b,ge);return t.value.addEventListener("pointerup",B),t.value.addEventListener("pointerdown",ae),t.value.addEventListener("pointermove",M),t.value.addEventListener("pointerleave",be),t.value.addEventListener("dblclick",Me),t.value.addEventListener("wheel",Ae),Gn(()=>{t!=null&&t.value&&(t.value.removeEventListener("pointerup",B),t.value.removeEventListener("pointerdown",ae),t.value.removeEventListener("pointermove",M),t.value.removeEventListener("pointerleave",be),t.value.removeEventListener("dblclick",Me),t.value.removeEventListener("wheel",Ae))}),{intersects:n,onClick:ge=>v.on(ge).off,onDblClick:ge=>p.on(ge).off,onContextMenu:ge=>A.on(ge).off,onPointerMove:ge=>m.on(ge).off,onPointerUp:ge=>y.on(ge).off,onPointerDown:ge=>_.on(ge).off,onPointerMissed:ge=>x.on(ge).off,onWheel:ge=>b.on(ge).off,forceUpdate:F}};function qu(s){let e=0;return s.traverse(t=>{if(t.isMesh&&t.geometry){const n=t.geometry,i=n.attributes.position.count*3*Float32Array.BYTES_PER_ELEMENT,r=n.index?n.index.count*Uint32Array.BYTES_PER_ELEMENT:0,o=n.attributes.normal?n.attributes.normal.count*3*Float32Array.BYTES_PER_ELEMENT:0,a=n.attributes.uv?n.attributes.uv.count*2*Float32Array.BYTES_PER_ELEMENT:0,l=i+r+o+a;e+=l}}),e}function CC(s){return(s/1024).toFixed(2)}const Wc=Ge({}),$c=s=>Object.assign(Wc.value,s);function PC(s,e,t=10){const n=bt(s)?OE():IE(ze(()=>bt(e).parentElement)),i=gr(Dd(n.width,t)),r=gr(Dd(n.height,t)),o=ze(()=>i.value/r.value);return{height:r,width:i,aspectRatio:o}}function Jl(){const s=new Map,e=new Set;let t=0,n=!1;const i=()=>{const o=Array.from(s.entries()).sort((a,l)=>{const c=a[1].priority-l[1].priority;return c===0?a[1].addI-l[1].addI:c});e.clear(),o.forEach(a=>e.add(a[0]))},r=o=>{s.delete(o),e.delete(o)};return{on:(o,a=0)=>{s.set(o,{priority:a,addI:t++});const l=()=>r(o);return $n(l),n=!0,{off:l}},off:r,trigger:(...o)=>{n&&(i(),n=!1),e.forEach(a=>a(...o))},dispose:()=>{s.clear(),e.clear()},get count(){return s.size}}}function RC(){const s=new il(!1),e=Ge(!1),t=Ge(!1);let n;const i=pp.generateUUID();let r=null;const o=Jl(),a=Jl(),l=Jl();let c={};function u(_){c=_}function h(_,x,A=0){switch(x){case"before":return o.on(_,A);case"render":return r||(r=_),a.dispose(),a.on(_);case"after":return l.on(_,A)}}function d(){e.value||(s.start(),e.value=!0,y())}function f(){e.value&&(s.stop(),cancelAnimationFrame(n),e.value=!1)}function g(){s.stop(),e.value=!1}function v(){s.start(),e.value=!0}function p(){t.value=!0}function m(){t.value=!1}function y(){const _=s.getDelta(),x=s.getElapsedTime(),A={camera:ee(c.camera),scene:ee(c.scene),renderer:ee(c.renderer),raycaster:ee(c.raycaster),controls:ee(c.controls),invalidate:c.invalidate,advance:c.advance},b={delta:_,elapsed:x,clock:s,...A};e.value&&o.trigger(b),t.value||(a.count?a.trigger(b):r&&r(b)),e.value&&l.trigger(b),n=requestAnimationFrame(y)}return{loopId:i,register:(_,x,A)=>h(_,x,A),start:d,stop:f,pause:g,resume:v,pauseRender:p,resumeRender:m,isRenderPaused:t,isActive:e,setContext:u}}function IC({scene:s,canvas:e,windowSize:t,disableRender:n,rendererOptions:i,emit:r}){const{logWarning:o}=to(),a=Rn(s),l=PC(t,e),{camera:c,cameras:u,registerCamera:h,deregisterCamera:d,setCameraActive:f}=rC({sizes:l,scene:s}),g={mode:Ge(i.renderMode||"always"),priority:Ge(0),frames:Ge(0),maxFrames:60,canBeInvalidated:ze(()=>g.mode.value==="on-demand"&&g.frames.value===0)};function v(G=1){i.renderMode==="on-demand"?g.frames.value=Math.min(g.maxFrames,g.frames.value+G):o("`invalidate` can only be used when `renderMode` is set to `on-demand`")}function p(){i.renderMode==="manual"?g.frames.value=1:o("`advance` can only be used when `renderMode` is set to `manual`")}const{renderer:m}=SC({scene:s,canvas:e,options:i,emit:r,contextParts:{sizes:l,camera:c,render:g,invalidate:v,advance:p},disableRender:n}),y={sizes:l,scene:a,camera:c,cameras:gr(u),renderer:m,raycaster:Rn(new wm),controls:Ge(null),perf:{maxFrames:160,fps:{value:0,accumulator:[]},memory:{currentMem:0,allocatedMem:0,accumulator:[]}},render:g,advance:p,extend:$c,invalidate:v,registerCamera:h,setCameraActive:f,deregisterCamera:d,loop:RC()};vr("useTres",y),y.scene.value.__tres={root:y},y.loop.register(()=>{c.value&&g.frames.value>0&&(m.value.render(s,c.value),r("render",y.renderer.value)),g.priority.value=0,g.mode.value==="always"?g.frames.value=1:g.frames.value=Math.max(0,g.frames.value-1)},"render"),y.loop.start(),Gn(()=>{y.loop.stop()});const _=100,x=LE({every:_}),{isSupported:A,memory:b}=NE({interval:_}),E=160;let I=performance.now();const w=({timestamp:G})=>{y.scene.value&&(y.perf.memory.allocatedMem=qu(y.scene.value)),G-I>=_&&(I=G,y.perf.fps.accumulator.push(x.value),y.perf.fps.accumulator.length>E&&y.perf.fps.accumulator.shift(),y.perf.fps.value=x.value,A.value&&b.value&&(y.perf.memory.accumulator.push(b.value.usedJSHeapSize/1024/1024),y.perf.memory.accumulator.length>E&&y.perf.memory.accumulator.shift(),y.perf.memory.currentMem=y.perf.memory.accumulator.reduce((q,ae)=>q+ae,0)/y.perf.memory.accumulator.length))};let M=0;const F=1,{pause:V}=Wu(({delta:G})=>{window.__TRES__DEVTOOLS__&&(w({timestamp:performance.now()}),M+=G,M>=F&&(window.__TRES__DEVTOOLS__.cb(y),M=0))},{immediate:!0});return Gn(()=>{V()}),y}function Nm(){const s=Vr("useTres");if(!s)throw new Error("useTresContext must be used together with useTresContextProvider");return s}function LC(s,e,t){const n=Rn(),i=Rn();s&&(n.value=s),e&&(i.value=e);const r=ze(()=>n.value?n.value.children:[]);function o(A,b){if(Array.isArray(A))for(const E of A)E(b);typeof A=="function"&&A(b)}function a(A,b){const E=[],I=()=>b.stopPropagating=!0;b.stopPropagation=I;for(const w of b==null?void 0:b.intersections){if(b.stopPropagating)return;b={...b,...w};const{object:M}=w;b.eventObject=M,o(M[A],b),E.push(M);let F=M.parent;for(;F!==null&&!b.stopPropagating&&!E.includes(F);)b.eventObject=F,o(F[A],b),E.push(F),F=F.parent;const V=mC(A.slice(2));t(V,{intersection:w,event:b})}}const{onClick:l,onDblClick:c,onContextMenu:u,onPointerMove:h,onPointerDown:d,onPointerUp:f,onPointerMissed:g,onWheel:v,forceUpdate:p}=EC(r,e);f(A=>a("onPointerUp",A)),d(A=>a("onPointerDown",A)),l(A=>a("onClick",A)),c(A=>a("onDoubleClick",A)),u(A=>a("onContextMenu",A)),v(A=>a("onWheel",A));let m=[];h(A=>{const b=A.intersections.map(({object:I})=>I),E=A.intersections;m.forEach(({object:I})=>{b.includes(I)||(A.intersections=m,a("onPointerLeave",A),a("onPointerOut",A))}),A.intersections=E,A.intersections.forEach(({object:I})=>{m.includes(I)||(a("onPointerEnter",A),a("onPointerOver",A))}),a("onPointerMove",A),m=A.intersections});const y=[];g(A=>{const b=()=>A.stopPropagating=!0;A.stopPropagation=b,y.forEach(E=>{A.stopPropagating||(A.eventObject=E,o(E.onPointerMissed,A))}),t("pointer-missed",{event:A})});function _(A){y.push(A)}function x(A){const b=y.indexOf(A);b>-1&&y.splice(b,1)}return e.eventManager={forceUpdate:p,registerPointerMissedObject:_,deregisterPointerMissedObject:x},{forceUpdate:p,registerPointerMissedObject:_,deregisterPointerMissedObject:x}}const{logError:Vd}=to(),Hd=["onClick","onContextMenu","onPointerMove","onPointerEnter","onPointerLeave","onPointerOver","onPointerOut","onDoubleClick","onPointerDown","onPointerUp","onPointerCancel","onPointerMissed","onLostPointerCapture","onWheel"];function Gd(s){var e;const t=(e=s==null?void 0:s.__tres)==null?void 0:e.root;t&&t.render&&t.render.canBeInvalidated.value&&t.invalidate()}const NC=()=>{let s=null;function e(l,c,u,h){if(h||(h={}),h.args||(h.args=[]),l==="template"||fC(l))return null;let d=l.replace("Tres",""),f;if(l==="primitive"){(h==null?void 0:h.object)===void 0&&Vd("Tres primitives need a prop 'object'");const g=h.object;d=g.type,f=Object.assign(g.clone(),{type:d})}else{const g=Wc.value[d];g||Vd(`${d} is not defined on the THREE namespace. Use extend to add it to the catalog.`),f=new g(...h.args)}return f?(f.isCamera&&(h!=null&&h.position||f.position.set(3,3,3),h!=null&&h.lookAt||f.lookAt(0,0,0)),(h==null?void 0:h.attach)===void 0&&(f.isMaterial?f.attach="material":f.isBufferGeometry&&(f.attach="geometry")),f.__tres={...f.__tres,type:d,memoizedProps:h,eventCount:0,disposable:!0,primitive:l==="primitive"},f.isObject3D&&f.__tres&&(h!=null&&h.material||h!=null&&h.geometry)&&(f.__tres.disposable=!1),f):null}function t(l,c){var u,h,d,f,g;if(!l)return;c&&c.isScene&&(s=c),s&&l.__tres&&(l.__tres.root=s.__tres.root);const v=c||s;if(l!=null&&l.isObject3D){const{registerCamera:p}=(u=l==null?void 0:l.__tres)==null?void 0:u.root;l!=null&&l.isCamera&&p(l),l.onPointerMissed&&(h=l==null?void 0:l.__tres)!=null&&h.root&&((g=(f=(d=l==null?void 0:l.__tres)==null?void 0:d.root)==null?void 0:f.eventManager)==null||g.registerPointerMissedObject(l))}l!=null&&l.isObject3D&&v!=null&&v.isObject3D?(v.add(l),l.dispatchEvent({type:"added"})):l!=null&&l.isFog?v.fog=l:typeof(l==null?void 0:l.attach)=="string"&&(l.__previousAttach=l[v==null?void 0:v.attach],v&&(v[l.attach]=l))}function n(l){var c,u,h,d;if(!l)return;const f=l.__tres;if(l.parent=l.parent||s,l.isObject3D){const g=v=>{var p,m;const y=(m=(p=l==null?void 0:l.__tres)==null?void 0:p.root)==null?void 0:m.deregisterCamera;v.isCamera&&(y==null||y(v))};(c=l.removeFromParent)==null||c.call(l),l.traverse(v=>{var p,m;g(v),v.onPointerMissed&&((m=(p=f==null?void 0:f.root)==null?void 0:p.eventManager)==null||m.deregisterPointerMissedObject(v))}),g(l),Gd(l),!((u=l.__tres)!=null&&u.primitive)&&(h=l.__tres)!=null&&h.disposable&&Xu(l),(d=l.dispose)==null||d.call(l)}}function i(l,c,u,h){var d,f;if(l){let g=l,v=c;if((d=l==null?void 0:l.__tres)!=null&&d.primitive&&v==="object"&&u!==null){const _=e("primitive",void 0,void 0,{object:h});for(const x in _){if(x==="uuid")continue;const A=l[x],b=_[x];!(A!=null&&A.set)&&!na(A)?l[x]=b:A.constructor===b.constructor&&A!=null&&A.copy?A==null||A.copy(b):Array.isArray(b)?A.set(...b):!A.isColor&&A.setScalar?A.setScalar(b):A.set(b)}_!=null&&_.__tres&&(_.__tres.root=s==null?void 0:s.__tres.root),_!=null&&_.isGroup?(l.geometry=void 0,l.material=void 0):delete l.isGroup}if(l!=null&&l.isObject3D&&v==="blocks-pointer-events"){h||h===""?l[v]=h:delete l[v];return}Hd.includes(c)&&(l.__tres.eventCount+=1);let p=ea(v),m=g==null?void 0:g[p];if(v==="args"){const _=l,x=u??[],A=h??[],b=((f=l==null?void 0:l.__tres)==null?void 0:f.type)||l.type;b&&x.length&&!_C(x,A)&&(g=Object.assign(_,new Wc.value[b](...h)));return}if(g.type==="BufferGeometry"){if(v==="args")return;g.setAttribute(ea(v),new pt(...h));return}if(v.includes("-")&&m===void 0){const _=v.split("-");m=_.reduce((x,A)=>x[ea(A)],g),v=_.pop(),p=v,m!=null&&m.set||(g=_.reduce((x,A)=>x[ea(A)],g))}let y=h;if(y===""&&(y=!0),na(m)){Hd.includes(c)||(Array.isArray(y)?l[p](...y):l[p](y)),p.startsWith("on")&&na(y)&&(g[p]=y);return}!(m!=null&&m.set)&&!na(m)?g[p]=y:m.constructor===y.constructor&&m!=null&&m.copy?m==null||m.copy(y):Array.isArray(y)?m.set(...y):!m.isColor&&m.setScalar?m.setScalar(y):m.set(y),Gd(l)}}function r(l){return(l==null?void 0:l.parent)||null}function o(l){const c=new ct;return c.name=l,c.__tres={type:"Comment"},c.__tres.root=s==null?void 0:s.__tres.root,c}function a(l){if(!l)return null;const c=l.parent||s,u=c.children.indexOf(l);return c.children[u+1]||null}return{insert:t,remove:n,createElement:e,patchProp:i,parentNode:r,createText:()=>{},createComment:o,setText:()=>{},setElementText:()=>{},nextSibling:a,querySelector:()=>{},setScopeId:()=>{},cloneNode:()=>{},insertStaticContent:()=>{}}};function DC(){return Dm().__VUE_DEVTOOLS_GLOBAL_HOOK__}function Dm(){return typeof navigator<"u"&&typeof window<"u"?window:typeof globalThis<"u"?globalThis:{}}const UC=typeof Proxy=="function",OC="devtools-plugin:setup",FC="plugin:settings:set";let ar,Xc;function kC(){var s;return ar!==void 0||(typeof window<"u"&&window.performance?(ar=!0,Xc=window.performance):typeof globalThis<"u"&&!((s=globalThis.perf_hooks)===null||s===void 0)&&s.performance?(ar=!0,Xc=globalThis.perf_hooks.performance):ar=!1),ar}function BC(){return kC()?Xc.now():Date.now()}class zC{constructor(e,t){this.target=null,this.targetQueue=[],this.onQueue=[],this.plugin=e,this.hook=t;const n={};if(e.settings)for(const o in e.settings){const a=e.settings[o];n[o]=a.defaultValue}const i=`__vue-devtools-plugin-settings__${e.id}`;let r=Object.assign({},n);try{const o=localStorage.getItem(i),a=JSON.parse(o);Object.assign(r,a)}catch{}this.fallbacks={getSettings(){return r},setSettings(o){try{localStorage.setItem(i,JSON.stringify(o))}catch{}r=o},now(){return BC()}},t&&t.on(FC,(o,a)=>{o===this.plugin.id&&this.fallbacks.setSettings(a)}),this.proxiedOn=new Proxy({},{get:(o,a)=>this.target?this.target.on[a]:(...l)=>{this.onQueue.push({method:a,args:l})}}),this.proxiedTarget=new Proxy({},{get:(o,a)=>this.target?this.target[a]:a==="on"?this.proxiedOn:Object.keys(this.fallbacks).includes(a)?(...l)=>(this.targetQueue.push({method:a,args:l,resolve:()=>{}}),this.fallbacks[a](...l)):(...l)=>new Promise(c=>{this.targetQueue.push({method:a,args:l,resolve:c})})})}async setRealTarget(e){this.target=e;for(const t of this.onQueue)this.target.on[t.method](...t.args);for(const t of this.targetQueue)t.resolve(await this.target[t.method](...t.args))}}function VC(s,e){const t=s,n=Dm(),i=DC(),r=UC&&t.enableEarlyProxy;if(i&&(n.__VUE_DEVTOOLS_PLUGIN_API_AVAILABLE__||!r))i.emit(OC,s,e);else{const o=r?new zC(t,i):null;(n.__VUE_DEVTOOLS_PLUGINS__=n.__VUE_DEVTOOLS_PLUGINS__||[]).push({pluginDescriptor:t,setupFn:e,proxy:o}),o&&e(o.proxiedTarget)}}function HC(s,e){const t=`▲ ■ ●${s}`;typeof Wd=="function"?Wd(t,e):console.log(t)}function Wd(s,e){throw new Error(s+e)}const Um=s=>{const e={id:s.uuid,label:s.type,children:[],tags:[]};s.name!==""&&e.tags.push({label:s.name,textColor:5750629,backgroundColor:15793395});const t=qu(s);return t>0&&e.tags.push({label:`${CC(t)} KB`,textColor:15707189,backgroundColor:16775644,tooltip:"Memory usage"}),s.type.includes("Light")&&(e.tags.push({label:`${s.intensity}`,textColor:9738662,backgroundColor:16316922,tooltip:"Intensity"}),e.tags.push({label:`#${s.color.getHexString()}`,textColor:9738662,backgroundColor:16316922,tooltip:"Color"})),s.type.includes("Camera")&&(e.tags.push({label:`${s.fov}°`,textColor:9738662,backgroundColor:16316922,tooltip:"Field of view"}),e.tags.push({label:`x: ${Math.round(s.position.x)} y: ${Math.round(s.position.y)} z: ${Math.round(s.position.z)}`,textColor:9738662,backgroundColor:16316922,tooltip:"Position"})),e};function Om(s,e,t=""){s.children.forEach(n=>{if(n.type==="HightlightMesh"||t&&!n.type.includes(t)&&!n.name.includes(t))return;const i=Um(n);e.children.push(i),Om(n,i,t)})}const GC=[],lr="tres:inspector",WC=ig({sceneGraph:null});function $C(s,e){VC({id:"dev.esm.tres",label:"TresJS 🪐",logo:"https://raw.githubusercontent.com/Tresjs/tres/main/public/favicon.svg",packageName:"tresjs",homepage:"https://tresjs.org",componentStateTypes:GC,app:s},t=>{typeof t.now!="function"&&HC("You seem to be using an outdated version of Vue Devtools. Are you still using the Beta release instead of the stable one? You can find the links at https://devtools.vuejs.org/guide/installation.html."),t.addInspector({id:lr,label:"TresJS 🪐",icon:"account_tree",treeFilterPlaceholder:"Search instances"}),setInterval(()=>{t.sendInspectorTree(lr)},1e3),setInterval(()=>{t.notifyComponentUpdate()},5e3),t.on.getInspectorTree(r=>{if(r.inspectorId===lr){const o=Um(e.scene.value);Om(e.scene.value,o,r.filter),WC.sceneGraph=o,r.rootNodes=[o]}});let n=null,i=null;t.on.getInspectorState(r=>{var o;if(r.inspectorId===lr){const[a]=e.scene.value.getObjectsByProperty("uuid",r.nodeId);if(!a)return;if(i&&n&&n.parent&&i.remove(n),a.isMesh){const l=xC(a);a.add(l),n=l,i=a}r.state={object:[{key:"uuid",editable:!0,value:a.uuid},{key:"name",editable:!0,value:a.name},{key:"type",editable:!0,value:a.type},{key:"position",editable:!0,value:a.position},{key:"rotation",editable:!0,value:a.rotation},{key:"scale",editable:!0,value:a.scale},{key:"geometry",value:a.geometry},{key:"material",value:a.material},{key:"color",editable:!0,value:a.color},{key:"intensity",editable:!0,value:a.intensity},{key:"castShadow",editable:!0,value:a.castShadow},{key:"receiveShadow",editable:!0,value:a.receiveShadow},{key:"frustumCulled",editable:!0,value:a.frustumCulled},{key:"matrixAutoUpdate",editable:!0,value:a.matrixAutoUpdate},{key:"matrixWorldNeedsUpdate",editable:!0,value:a.matrixWorldNeedsUpdate},{key:"matrixWorld",value:a.matrixWorld},{key:"visible",editable:!0,value:a.visible}]},a.isScene&&(r.state.info={memory:qu(a),objects:a.children.length,calls:e.renderer.value.info.render.calls,triangles:e.renderer.value.info.render.triangles,points:e.renderer.value.info.render.points,lines:e.renderer.value.info.render.lines},r.state.programs=((o=e.renderer.value.info.programs)==null?void 0:o.map(l=>({key:l.name,value:{...l,vertexShader:l.vertexShader,attributes:l.getAttributes(),uniforms:l.getUniforms()}})))||[])}}),t.on.editInspectorState(r=>{r.inspectorId===lr&&yC(e.scene.value,r.nodeId,r.path,r.state.value)})})}const XC=["data-scene","data-tres"],qC=Ue({__name:"TresCanvas",props:{shadows:{type:Boolean,default:void 0},clearColor:{},toneMapping:{},shadowMapType:{},useLegacyLights:{type:Boolean,default:void 0},outputColorSpace:{},toneMappingExposure:{},renderMode:{default:"always"},camera:{},preset:{},windowSize:{type:Boolean,default:void 0},disableRender:{type:Boolean,default:void 0},context:{},precision:{},alpha:{type:Boolean,default:void 0},premultipliedAlpha:{type:Boolean},antialias:{type:Boolean,default:void 0},stencil:{type:Boolean,default:void 0},preserveDrawingBuffer:{type:Boolean,default:void 0},powerPreference:{},depth:{type:Boolean,default:void 0},logarithmicDepthBuffer:{type:Boolean,default:void 0},failIfMajorPerformanceCaveat:{type:Boolean,default:void 0}},emits:["render","click","double-click","context-menu","pointer-move","pointer-up","pointer-down","pointer-enter","pointer-leave","pointer-over","pointer-out","pointer-missed","wheel"],setup(s,{expose:e,emit:t}){var n;const i=s,r=t,o=Zd(),{logWarning:a}=to(),l=Ge(),c=Rn(new ka),u=(n=ma())==null?void 0:n.appContext.app;$c(mE);const h=p=>Ue({setup(){var m;const y=(m=ma())==null?void 0:m.appContext;return y&&(y.app=u),vr("useTres",p),vr("extend",$c),typeof window<"u"&&$C(y==null?void 0:y.app,p),()=>eh(xt,null,o!=null&&o.default?o.default():[])}}),d=p=>{const m=h(p),{render:y}=sg(NC());y(eh(m),c.value)},f=(p,m=!1)=>{Xu(p.scene.value),m&&(p.renderer.value.dispose(),p.renderer.value.renderLists.dispose(),p.renderer.value.forceContextLoss()),c.value.__tres={root:p},d(p)},g=ze(()=>i.disableRender),v=Rn(null);return e({context:v,dispose:()=>f(v.value,!0)}),Nn(()=>{const p=l;v.value=IC({scene:c.value,canvas:p,windowSize:i.windowSize??!1,disableRender:g.value??!1,rendererOptions:i,emit:r}),LC(c.value,v.value,r);const{registerCamera:m,camera:y,cameras:_,deregisterCamera:x}=v.value;d(v.value);const A=()=>{const b=new Ut(45,window.innerWidth/window.innerHeight,.1,1e3);b.position.set(3,3,3),b.lookAt(0,0,0),m(b);const E=Pi(()=>{_.value.length>=2&&(b.removeFromParent(),x(b),E==null||E())})};wt(()=>i.camera,(b,E)=>{b&&m(b),E&&(E.removeFromParent(),x(E))},{immediate:!0}),y.value||(a("No camera found. Creating a default perspective camera. To have full control over a camera, please add one to the scene."),A())}),Gn(()=>{f(v.value)}),(p,m)=>(Y(),fe("canvas",{ref_key:"canvas",ref:l,"data-scene":c.value.uuid,class:yt(p.$attrs.class),"data-tres":`tresjs ${ee(sC).version}`,style:Zc({display:"block",width:"100%",height:"100%",position:p.windowSize?"fixed":"relative",top:0,left:0,pointerEvents:"auto",touchAction:"none",...p.$attrs.style})},null,14,XC))}}),YC=ln;class wa extends on{constructor(e){super(e),this.defaultDPI=90,this.defaultUnit="px"}load(e,t,n,i){const r=this,o=new Wn(r.manager);o.setPath(r.path),o.setRequestHeader(r.requestHeader),o.setWithCredentials(r.withCredentials),o.load(e,function(a){try{t(r.parse(a))}catch(l){i?i(l):console.error(l),r.manager.itemError(e)}},n,i)}parse(e){const t=this;function n(U,D){if(U.nodeType!==1)return;const R=x(U);let T=!1,ie=null;switch(U.nodeName){case"svg":D=g(U,D);break;case"style":r(U);break;case"g":D=g(U,D);break;case"path":D=g(U,D),U.hasAttribute("d")&&(ie=i(U));break;case"rect":D=g(U,D),ie=l(U);break;case"polygon":D=g(U,D),ie=c(U);break;case"polyline":D=g(U,D),ie=u(U);break;case"circle":D=g(U,D),ie=h(U);break;case"ellipse":D=g(U,D),ie=d(U);break;case"line":D=g(U,D),ie=f(U);break;case"defs":T=!0;break;case"use":D=g(U,D);const L=(U.getAttributeNS("http://www.w3.org/1999/xlink","href")||"").substring(1),X=U.viewportElement.getElementById(L);X?n(X,D):console.warn("SVGLoader: 'use node' references non-existent node id: "+L);break}ie&&(D.fill!==void 0&&D.fill!=="none"&&ie.color.setStyle(D.fill,YC),b(ie,Ae),V.push(ie),ie.userData={node:U,style:D});const he=U.childNodes;for(let J=0;J0?Ae.copy(q[q.length-1]):Ae.identity())}function i(U){const D=new bi,R=new se,T=new se,ie=new se;let he=!0,J=!1;const L=U.getAttribute("d");if(L===""||L==="none")return null;const X=L.match(/[a-df-z][^a-df-z]*/ig);for(let K=0,H=X.length;K0&&(R.copy(ie),D.currentPath.currentPoint.copy(R),he=!0);break;default:console.warn($)}J=!1}return D}function r(U){if(!(!U.sheet||!U.sheet.cssRules||!U.sheet.cssRules.length))for(let D=0;Die.trim());for(let ie=0;ieJ!==""));G[T[ie]]=Object.assign(G[T[ie]]||{},he)}}}function o(U,D,R,T,ie,he,J,L){if(D==0||R==0){U.lineTo(L.x,L.y);return}T=T*Math.PI/180,D=Math.abs(D),R=Math.abs(R);const X=(J.x-L.x)/2,K=(J.y-L.y)/2,H=Math.cos(T)*X+Math.sin(T)*K,$=-Math.sin(T)*X+Math.cos(T)*K;let te=D*D,le=R*R;const k=H*H,O=$*$,P=k/te+O/le;if(P>1){const xe=Math.sqrt(P);D=xe*D,R=xe*R,te=D*D,le=R*R}const S=te*O+le*k,Q=(te*le-S)/S;let pe=Math.sqrt(Math.max(0,Q));ie===he&&(pe=-pe);const ce=pe*D*$/R,ve=-pe*R*H/D,Ve=Math.cos(T)*ce-Math.sin(T)*ve+(J.x+L.x)/2,Ee=Math.sin(T)*ce+Math.cos(T)*ve+(J.y+L.y)/2,Te=a(1,0,(H-ce)/D,($-ve)/R),Qe=a((H-ce)/D,($-ve)/R,(-H-ce)/D,(-$-ve)/R)%(Math.PI*2);U.currentPath.absellipse(Ve,Ee,D,R,Te,Te+Qe,he===0,T)}function a(U,D,R,T){const ie=U*R+D*T,he=Math.sqrt(U*U+D*D)*Math.sqrt(R*R+T*T);let J=Math.acos(Math.max(-1,Math.min(1,ie/he)));return U*T-D*R<0&&(J=-J),J}function l(U){const D=_(U.getAttribute("x")||0),R=_(U.getAttribute("y")||0),T=_(U.getAttribute("rx")||U.getAttribute("ry")||0),ie=_(U.getAttribute("ry")||U.getAttribute("rx")||0),he=_(U.getAttribute("width")),J=_(U.getAttribute("height")),L=1-.551915024494,X=new bi;return X.moveTo(D+T,R),X.lineTo(D+he-T,R),(T!==0||ie!==0)&&X.bezierCurveTo(D+he-T*L,R,D+he,R+ie*L,D+he,R+ie),X.lineTo(D+he,R+J-ie),(T!==0||ie!==0)&&X.bezierCurveTo(D+he,R+J-ie*L,D+he-T*L,R+J,D+he-T,R+J),X.lineTo(D+T,R+J),(T!==0||ie!==0)&&X.bezierCurveTo(D+T*L,R+J,D,R+J-ie*L,D,R+J-ie),X.lineTo(D,R+ie),(T!==0||ie!==0)&&X.bezierCurveTo(D,R+ie*L,D+T*L,R,D+T,R),X}function c(U){function D(he,J,L){const X=_(J),K=_(L);ie===0?T.moveTo(X,K):T.lineTo(X,K),ie++}const R=/([+-]?\d*\.?\d+(?:e[+-]?\d+)?)(?:,|\s)([+-]?\d*\.?\d+(?:e[+-]?\d+)?)/g,T=new bi;let ie=0;return U.getAttribute("points").replace(R,D),T.currentPath.autoClose=!0,T}function u(U){function D(he,J,L){const X=_(J),K=_(L);ie===0?T.moveTo(X,K):T.lineTo(X,K),ie++}const R=/([+-]?\d*\.?\d+(?:e[+-]?\d+)?)(?:,|\s)([+-]?\d*\.?\d+(?:e[+-]?\d+)?)/g,T=new bi;let ie=0;return U.getAttribute("points").replace(R,D),T.currentPath.autoClose=!1,T}function h(U){const D=_(U.getAttribute("cx")||0),R=_(U.getAttribute("cy")||0),T=_(U.getAttribute("r")||0),ie=new Ai;ie.absarc(D,R,T,0,Math.PI*2);const he=new bi;return he.subPaths.push(ie),he}function d(U){const D=_(U.getAttribute("cx")||0),R=_(U.getAttribute("cy")||0),T=_(U.getAttribute("rx")||0),ie=_(U.getAttribute("ry")||0),he=new Ai;he.absellipse(D,R,T,ie,0,Math.PI*2);const J=new bi;return J.subPaths.push(he),J}function f(U){const D=_(U.getAttribute("x1")||0),R=_(U.getAttribute("y1")||0),T=_(U.getAttribute("x2")||0),ie=_(U.getAttribute("y2")||0),he=new bi;return he.moveTo(D,R),he.lineTo(T,ie),he.currentPath.autoClose=!1,he}function g(U,D){D=Object.assign({},D);let R={};if(U.hasAttribute("class")){const J=U.getAttribute("class").split(/\s/).filter(Boolean).map(L=>L.trim());for(let L=0;L0&&D.premultiply(q[q.length-1]),Ae.copy(D),q.push(D),D}function A(U){const D=new Ze,R=ae;if(U.nodeName==="use"&&(U.hasAttribute("x")||U.hasAttribute("y"))){const T=_(U.getAttribute("x")),ie=_(U.getAttribute("y"));D.translate(T,ie)}if(U.hasAttribute("transform")){const T=U.getAttribute("transform").split(")");for(let ie=T.length-1;ie>=0;ie--){const he=T[ie].trim();if(he==="")continue;const J=he.indexOf("("),L=he.length;if(J>0&&J=1){const H=K[0];let $=0;K.length>=2&&($=K[1]),R.translate(H,$)}break;case"rotate":if(K.length>=1){let H=0,$=0,te=0;H=K[0]*Math.PI/180,K.length>=3&&($=K[1],te=K[2]),j.makeTranslation(-$,-te),oe.makeRotation(H),B.multiplyMatrices(oe,j),j.makeTranslation($,te),R.multiplyMatrices(j,B)}break;case"scale":if(K.length>=1){const H=K[0];let $=H;K.length>=2&&($=K[1]),R.scale(H,$)}break;case"skewX":K.length===1&&R.set(1,Math.tan(K[0]*Math.PI/180),0,0,1,0,0,0,1);break;case"skewY":K.length===1&&R.set(1,0,0,Math.tan(K[0]*Math.PI/180),1,0,0,0,1);break;case"matrix":K.length===6&&R.set(K[0],K[2],K[4],K[1],K[3],K[5],0,0,1);break}}D.premultiply(R)}}return D}function b(U,D){function R(J){be.set(J.x,J.y,1).applyMatrix3(D),J.set(be.x,be.y)}function T(J){const L=J.xRadius,X=J.yRadius,K=Math.cos(J.aRotation),H=Math.sin(J.aRotation),$=new N(L*K,L*H,0),te=new N(-X*H,X*K,0),le=$.applyMatrix3(D),k=te.applyMatrix3(D),O=ae.set(le.x,k.x,0,le.y,k.y,0,0,0,1),P=j.copy(O).invert(),pe=oe.copy(P).transpose().multiply(P).elements,ce=F(pe[0],pe[1],pe[4]),ve=Math.sqrt(ce.rt1),Ve=Math.sqrt(ce.rt2);if(J.xRadius=1/ve,J.yRadius=1/Ve,J.aRotation=Math.atan2(ce.sn,ce.cs),!((J.aEndAngle-J.aStartAngle)%(2*Math.PI){const{x:Je,y:Re}=new N(Math.cos(st),Math.sin(st),0).applyMatrix3(xe);return Math.atan2(Re,Je)};J.aStartAngle=Oe(J.aStartAngle),J.aEndAngle=Oe(J.aEndAngle),E(D)&&(J.aClockwise=!J.aClockwise)}}function ie(J){const L=w(D),X=M(D);J.xRadius*=L,J.yRadius*=X;const K=L>Number.EPSILON?Math.atan2(D.elements[1],D.elements[0]):Math.atan2(-D.elements[3],D.elements[4]);J.aRotation+=K,E(D)&&(J.aStartAngle*=-1,J.aEndAngle*=-1,J.aClockwise=!J.aClockwise)}const he=U.subPaths;for(let J=0,L=he.length;JNumber.EPSILON}function w(U){const D=U.elements;return Math.sqrt(D[0]*D[0]+D[1]*D[1])}function M(U){const D=U.elements;return Math.sqrt(D[3]*D[3]+D[4]*D[4])}function F(U,D,R){let T,ie,he,J,L;const X=U+R,K=U-R,H=Math.sqrt(K*K+4*D*D);return X>0?(T=.5*(X+H),L=1/T,ie=U*L*R-D*L*D):X<0?ie=.5*(X-H):(T=.5*H,ie=-.5*H),K>0?he=K+H:he=K-H,Math.abs(he)>2*Math.abs(D)?(L=-2*D/he,J=1/Math.sqrt(1+L*L),he=L*J):Math.abs(D)===0?(he=1,J=0):(L=-.5*he/D,he=1/Math.sqrt(1+L*L),J=L*he),K>0&&(L=he,he=-J,J=L),{rt1:T,rt2:ie,cs:he,sn:J}}const V=[],G={},q=[],ae=new Ze,j=new Ze,oe=new Ze,B=new Ze,Me=new se,be=new N,Ae=new Ze,ge=new DOMParser().parseFromString(e,"image/svg+xml");return n(ge.documentElement,{fill:"#000",fillOpacity:1,strokeOpacity:1,strokeWidth:1,strokeLineJoin:"miter",strokeLineCap:"butt",strokeMiterLimit:4}),{paths:V,xml:ge.documentElement}}static createShapes(e){const n={ORIGIN:0,DESTINATION:1,BETWEEN:2,LEFT:3,RIGHT:4,BEHIND:5,BEYOND:6},i={loc:n.ORIGIN,t:0};function r(v,p,m,y){const _=v.x,x=p.x,A=m.x,b=y.x,E=v.y,I=p.y,w=m.y,M=y.y,F=(b-A)*(E-w)-(M-w)*(_-A),V=(x-_)*(E-w)-(I-E)*(_-A),G=(M-w)*(x-_)-(b-A)*(I-E),q=F/G,ae=V/G;if(G===0&&F!==0||q<=0||q>=1||ae<0||ae>1)return null;if(F===0&&G===0){for(let j=0;j<2;j++)if(o(j===0?m:y,v,p),i.loc==n.ORIGIN){const oe=j===0?m:y;return{x:oe.x,y:oe.y,t:i.t}}else if(i.loc==n.BETWEEN){const oe=+(_+i.t*(x-_)).toPrecision(10),B=+(E+i.t*(I-E)).toPrecision(10);return{x:oe,y:B,t:i.t}}return null}else{for(let B=0;B<2;B++)if(o(B===0?m:y,v,p),i.loc==n.ORIGIN){const Me=B===0?m:y;return{x:Me.x,y:Me.y,t:i.t}}const j=+(_+q*(x-_)).toPrecision(10),oe=+(E+q*(I-E)).toPrecision(10);return{x:j,y:oe,t:q}}}function o(v,p,m){const y=m.x-p.x,_=m.y-p.y,x=v.x-p.x,A=v.y-p.y,b=y*A-x*_;if(v.x===p.x&&v.y===p.y){i.loc=n.ORIGIN,i.t=0;return}if(v.x===m.x&&v.y===m.y){i.loc=n.DESTINATION,i.t=1;return}if(b<-Number.EPSILON){i.loc=n.LEFT;return}if(b>Number.EPSILON){i.loc=n.RIGHT;return}if(y*x<0||_*A<0){i.loc=n.BEHIND;return}if(Math.sqrt(y*y+_*_)M.t<=w.t+Number.EPSILON&&M.t>=w.t-Number.EPSILON)===void 0&&(m.push(w),y.push(new se(w.x,w.y)))}}return y}function l(v,p,m){const y=new se;p.getCenter(y);const _=[];return m.forEach(x=>{x.boundingBox.containsPoint(y)&&a(v,x.points).forEach(b=>{_.push({identifier:x.identifier,isCW:x.isCW,point:b})})}),_.sort((x,A)=>x.point.x-A.point.x),_}function c(v,p,m,y,_){(_==null||_==="")&&(_="nonzero");const x=new se;v.boundingBox.getCenter(x);const A=[new se(m,x.y),new se(y,x.y)],b=l(A,v.boundingBox,p);b.sort((V,G)=>V.point.x-G.point.x);const E=[],I=[];b.forEach(V=>{V.identifier===v.identifier?E.push(V):I.push(V)});const w=E[0].point.x,M=[];let F=0;for(;F0&&M[M.length-1]===I[F].identifier?M.pop():M.push(I[F].identifier),F++;if(M.push(v.identifier),_==="evenodd"){const V=M.length%2===0,G=M[M.length-2];return{identifier:v.identifier,isHole:V,for:G}}else if(_==="nonzero"){let V=!0,G=null,q=null;for(let ae=0;ae{const p=v.getPoints();let m=-999999999,y=999999999,_=-999999999,x=999999999;for(let A=0;Am&&(m=b.y),b.y_&&(_=b.x),b.x=x&&(u=x-1),{curves:v.curves,points:p,isCW:Pn.isClockWise(p),identifier:-1,boundingBox:new Am(new se(x,y),new se(_,m))}});d=d.filter(v=>v.points.length>1);for(let v=0;vc(v,d,u,h,e.userData?e.userData.style.fillRule:void 0)),g=[];return d.forEach(v=>{if(!f[v.identifier].isHole){const m=new Ti;m.curves=v.curves,f.filter(_=>_.isHole&&_.for===v.identifier).forEach(_=>{const x=d[_.identifier],A=new Ai;A.curves=x.curves,m.holes.push(A)}),g.push(m)}}),g}static getStrokeStyle(e,t,n,i,r){return e=e!==void 0?e:1,t=t!==void 0?t:"#000",n=n!==void 0?n:"miter",i=i!==void 0?i:"butt",r=r!==void 0?r:4,{strokeColor:t,strokeWidth:e,strokeLineJoin:n,strokeLineCap:i,strokeMiterLimit:r}}static pointsToStroke(e,t,n,i){const r=[],o=[],a=[];if(wa.pointsToStrokeWithBuffers(e,t,n,i,r,o,a)===0)return null;const l=new it;return l.setAttribute("position",new Ne(r,3)),l.setAttribute("normal",new Ne(o,3)),l.setAttribute("uv",new Ne(a,2)),l}static pointsToStrokeWithBuffers(e,t,n,i,r,o,a,l){const c=new se,u=new se,h=new se,d=new se,f=new se,g=new se,v=new se,p=new se,m=new se,y=new se,_=new se,x=new se,A=new se,b=new se,E=new se,I=new se,w=new se;n=n!==void 0?n:12,i=i!==void 0?i:.001,l=l!==void 0?l:0,e=K(e);const M=e.length;if(M<2)return 0;const F=e[0].equals(e[M-1]);let V,G=e[0],q;const ae=t.strokeWidth/2,j=1/(M-1);let oe=0,B,Me,be,Ae,ge=!1,Be=0,U=l*3,D=l*2;R(e[0],e[1],c).multiplyScalar(ae),p.copy(e[0]).sub(c),m.copy(e[0]).add(c),y.copy(p),_.copy(m);for(let H=1;HNumber.EPSILON){const le=ae/te;h.multiplyScalar(-le),d.subVectors(V,G),f.copy(d).setLength(le).add(h),I.copy(f).negate();const k=f.length(),O=d.length();d.divideScalar(O),g.subVectors(q,V);const P=g.length();switch(g.divideScalar(P),d.dot(I)=i&&te.push(H[le]);return te.push(H[H.length-1]),te}}}const ZC=`// -// Description : Array and textureless GLSL 2D/3D/4D simplex -// noise functions. -// Author : Ian McEwan, Ashima Arts. -// Maintainer : stegu -// Lastmod : 20201014 (stegu) -// License : Copyright (C) 2011 Ashima Arts. All rights reserved. -// Distributed under the MIT License. See LICENSE file. -// https://github.com/ashima/webgl-noise -// https://github.com/stegu/webgl-noise -// - -vec3 mod289(vec3 x) { - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec4 mod289(vec4 x) { - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec4 permute(vec4 x) { - return mod289(((x*34.0)+10.0)*x); -} - -vec4 taylorInvSqrt(vec4 r) -{ - return 1.79284291400159 - 0.85373472095314 * r; -} - -float snoise(vec3 v) - { - const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; - const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); - -// First corner - vec3 i = floor(v + dot(v, C.yyy) ); - vec3 x0 = v - i + dot(i, C.xxx) ; - -// Other corners - vec3 g = step(x0.yzx, x0.xyz); - vec3 l = 1.0 - g; - vec3 i1 = min( g.xyz, l.zxy ); - vec3 i2 = max( g.xyz, l.zxy ); - - // x0 = x0 - 0.0 + 0.0 * C.xxx; - // x1 = x0 - i1 + 1.0 * C.xxx; - // x2 = x0 - i2 + 2.0 * C.xxx; - // x3 = x0 - 1.0 + 3.0 * C.xxx; - vec3 x1 = x0 - i1 + C.xxx; - vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y - vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y - -// Permutations - i = mod289(i); - vec4 p = permute( permute( permute( - i.z + vec4(0.0, i1.z, i2.z, 1.0 )) - + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) - + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); - -// Gradients: 7x7 points over a square, mapped onto an octahedron. -// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) - float n_ = 0.142857142857; // 1.0/7.0 - vec3 ns = n_ * D.wyz - D.xzx; - - vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7) - - vec4 x_ = floor(j * ns.z); - vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N) - - vec4 x = x_ *ns.x + ns.yyyy; - vec4 y = y_ *ns.x + ns.yyyy; - vec4 h = 1.0 - abs(x) - abs(y); - - vec4 b0 = vec4( x.xy, y.xy ); - vec4 b1 = vec4( x.zw, y.zw ); - - //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; - //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; - vec4 s0 = floor(b0)*2.0 + 1.0; - vec4 s1 = floor(b1)*2.0 + 1.0; - vec4 sh = -step(h, vec4(0.0)); - - vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ; - vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ; - - vec3 p0 = vec3(a0.xy,h.x); - vec3 p1 = vec3(a0.zw,h.y); - vec3 p2 = vec3(a1.xy,h.z); - vec3 p3 = vec3(a1.zw,h.w); - -//Normalise gradients - vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); - p0 *= norm.x; - p1 *= norm.y; - p2 *= norm.z; - p3 *= norm.w; - -// Mix final noise value - vec4 m = max(0.5 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); - m = m * m; - return 105.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), - dot(p2,x2), dot(p3,x3) ) ); - } - -// demo code: -// float color(vec2 xy) { return 0.7 * snoise(vec3(xy, 0.3*iTime)); } -// void mainImage(out vec4 fragColor, in vec2 fragCoord) { -// vec2 p = (fragCoord.xy/iResolution.y) * 2.0 - 1.0; - -// vec3 xyz = vec3(p, 0); - -// vec2 step = vec2(1.3, 1.7); -// float n = color(xyz.xy); -// n += 0.5 * color(xyz.xy * 2.0 - step); -// n += 0.25 * color(xyz.xy * 4.0 - 2.0 * step); -// n += 0.125 * color(xyz.xy * 8.0 - 3.0 * step); -// n += 0.0625 * color(xyz.xy * 16.0 - 4.0 * step); -// n += 0.03125 * color(xyz.xy * 32.0 - 5.0 * step); - -// fragColor.xyz = vec3(0.5 + 0.5 * vec3(n, n, n)); - -// } -`,JC=` -varying vec2 vUv; - -void main() { - vec4 modelPosition = modelMatrix * vec4(position, 1.0); - vec4 viewPosition = viewMatrix * modelPosition; - gl_Position = projectionMatrix * viewPosition; - vUv = uv; -} -`,KC=Ue({__name:"Background",async setup(s){let e,t;const{renderer:n,sizes:i}=Nm(),{paths:r}=([e,t]=rg(()=>TC(wa,"/circuit-board.svg")),e=await e,t(),e),o=r.map(p=>wa.createShapes(p)).reduce((p,m)=>[...p,...m]),a=ze(()=>Math.ceil(i.height.value/304)),l=ze(()=>Math.ceil(i.width.value/304)),c=Ge(new se(1/0,1/0));function u(p){c.value=new se(p.screenX,window.screen.availHeight-p.screenY),d.value&&d.value.children.forEach(m=>{m.material.uniforms.uMouse.value=c.value})}function h(p){p.relatedTarget||(c.value=new se(1/0,1/0),d.value&&d.value.children.forEach(m=>{m.material.uniforms.uMouse.value=c.value}))}Nn(()=>{window.addEventListener("mousemove",u),window.addEventListener("mouseout",h)}),Gn(()=>{window.removeEventListener("mousemove",u),window.removeEventListener("mouseout",h)});const d=Rn(null),f={uTime:{value:0},uMouse:{value:new se(1/0,1/0)}},g=ZC+` -precision mediump float; -uniform float uTime; -uniform vec2 uMouse; -varying vec2 vUv; - -void main() { - float dist = distance(gl_FragCoord.xy, uMouse); - float alpha = max(0., 1. - dist / 304.); - alpha += max(0., snoise(vec3(gl_FragCoord.xy / 304., uTime / 4.))); - gl_FragColor = vec4(0, 0, 0, alpha); -} -`,{onLoop:v}=cC();return v(({elapsed:p})=>{d.value&&d.value.children.forEach(m=>{m.material.uniforms.uTime.value=p})}),(p,m)=>{const y=cn("TresShapeGeometry"),_=cn("TresShaderMaterial"),x=cn("TresMesh"),A=cn("TresGroup");return ee(n)?(Y(),$e(A,{key:0,ref_key:"groupRef",ref:d},{default:ye(()=>[(Y(!0),fe(xt,null,Jt(a.value*l.value,b=>(Y(),$e(x,{position:[(b%l.value-l.value/2)*304,(Math.floor((b-1)/l.value)-a.value/2)*304,0]},{default:ye(()=>[ke(y,{args:[ee(o)]},null,8,["args"]),ke(_,{vertexShader:JC,fragmentShader:g,uniforms:f,blending:ee(va)},null,8,["blending"])]),_:2},1032,["position"]))),256))]),_:1},512)):De("",!0)}}}),jC=Ue({__name:"Camera",setup(s){const e=Nm();return wt([e.sizes.width,e.sizes.height,e.camera],([t,n,i])=>{const r=i;r&&(r.left=0,r.bottom=0,r.right=t,r.top=n,r.updateProjectionMatrix())}),(t,n)=>{const i=cn("TresOrthographicCamera");return Y(),$e(i,{position:[0,0,10]})}}}),no=s=>(Wt("data-v-1f4bd229"),s=s(),$t(),s),QC={class:"background"},eP={class:"vp-doc"},tP=no(()=>me("a",{class:"h-card",rel:"me",href:"/about"},[me("img",{src:ag,alt:""}),Ht("The Paper Pilot")],-1)),nP=no(()=>me("a",{rel:"license",href:"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"CC BY-NC-SA 4.0",-1)),iP=no(()=>me("div",null,"Any and all opinions listed here are my own and not representative of my employers; future, past and present.",-1)),sP=no(()=>me("div",null,[me("a",{href:"https://resume.incremental.social/thepaperpilot/thepaperpilot"},"Resume"),Ht(" (not actively seeking new opportunities).")],-1)),rP=no(()=>me("div",null,[Ht("Site built from "),me("a",{href:"https://code.incremental.social/thepaperpilot/pages/commit/d4d1e112feca180efdcc10b4465211fbbec4e6a5"},"this commit"),Ht(" on "),me("time",null,"Thursday, June 27, 2024 at 08:29:24"),Ht(". "),me("a",{href:"https://www.thepaperpilot.org/licenses.txt"},"Legal disclaimers"),Ht(".")],-1)),oP=Ue({__name:"Layout",setup(s){return(e,t)=>{const n=cn("TresAmbientLight"),i=cn("ClientOnly");return Y(),$e(ee(cf).Layout,null,{"layout-top":ye(()=>[ke(ee(_x)),ke(i,null,{default:ye(()=>[me("div",QC,[ke(ee(qC),null,{default:ye(()=>[ke(jC),ke(n,{intensity:1}),(Y(),$e(og,null,{default:ye(()=>[ke(KC)]),_:1}))]),_:1})])]),_:1})]),"layout-bottom":ye(()=>[me("footer",eP,[me("div",null,[Ht("CC "+ft(new Date().getFullYear())+" ",1),tP,Ht(". "),nP,Ht(".")]),iP,sP,rP])]),_:1})}}}),aP=Ye(oP,[["__scopeId","data-v-1f4bd229"]]),cP={...cf,Layout:aP};export{cP as R,X0 as c,ot as u}; diff --git a/assets/garden_activitypub_index.md.CWpyy_YP.js b/assets/garden_activitypub_index.md.CWpyy_YP.js new file mode 100644 index 00000000..97d7822f --- /dev/null +++ b/assets/garden_activitypub_index.md.CWpyy_YP.js @@ -0,0 +1 @@ +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as s,Q as e,K as a,u as t,p as d}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"ActivityPub",-1),c=["innerHTML"],o=e("hr",null,null,-1),u=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/fediverse/index.md"},"Fediverse")],-1),p=e("details",null,[e("summary",null,"Tags:"),e("a",{href:"/garden/decentralized/index.md"},"Decentralized")],-1),_=e("p",null,[e("a",{href:"https://activitypub.rocks",target:"_blank",rel:"noreferrer"},"ActivityPub"),a(" is a protocol for "),e("a",{href:"/garden/fediverse/"},"Federated Social Media")],-1),y=JSON.parse('{"title":"ActivityPub","description":"","frontmatter":{"public":"true","slug":"activitypub","tags":["Decentralized"],"title":"ActivityPub","prev":false,"next":false},"headers":[],"relativePath":"garden/activitypub/index.md","filePath":"garden/activitypub/index.md"}'),f={name:"garden/activitypub/index.md"},x=Object.assign(f,{setup(m){const i=n();return(h,v)=>(d(),s("div",null,[l,e("p",null,[a("8 words, ~0 minute read. "),e("span",{innerHTML:t(r)[`site/${t(i).page.value.relativePath}`]},null,8,c)]),o,u,p,_]))}});export{y as __pageData,x as default}; diff --git a/assets/garden_activitypub_index.md.CWpyy_YP.lean.js b/assets/garden_activitypub_index.md.CWpyy_YP.lean.js new file mode 100644 index 00000000..97d7822f --- /dev/null +++ b/assets/garden_activitypub_index.md.CWpyy_YP.lean.js @@ -0,0 +1 @@ +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as s,Q as e,K as a,u as t,p as d}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"ActivityPub",-1),c=["innerHTML"],o=e("hr",null,null,-1),u=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/fediverse/index.md"},"Fediverse")],-1),p=e("details",null,[e("summary",null,"Tags:"),e("a",{href:"/garden/decentralized/index.md"},"Decentralized")],-1),_=e("p",null,[e("a",{href:"https://activitypub.rocks",target:"_blank",rel:"noreferrer"},"ActivityPub"),a(" is a protocol for "),e("a",{href:"/garden/fediverse/"},"Federated Social Media")],-1),y=JSON.parse('{"title":"ActivityPub","description":"","frontmatter":{"public":"true","slug":"activitypub","tags":["Decentralized"],"title":"ActivityPub","prev":false,"next":false},"headers":[],"relativePath":"garden/activitypub/index.md","filePath":"garden/activitypub/index.md"}'),f={name:"garden/activitypub/index.md"},x=Object.assign(f,{setup(m){const i=n();return(h,v)=>(d(),s("div",null,[l,e("p",null,[a("8 words, ~0 minute read. "),e("span",{innerHTML:t(r)[`site/${t(i).page.value.relativePath}`]},null,8,c)]),o,u,p,_]))}});export{y as __pageData,x as default}; diff --git a/assets/garden_activitypub_index.md.DLZvHPXj.js b/assets/garden_activitypub_index.md.DLZvHPXj.js deleted file mode 100644 index 7da39941..00000000 --- a/assets/garden_activitypub_index.md.DLZvHPXj.js +++ /dev/null @@ -1 +0,0 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as s,j as e,a,k as t,o as d}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"ActivityPub",-1),c=["innerHTML"],o=e("hr",null,null,-1),u=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/fediverse/index.md"},"Fediverse")],-1),p=e("details",null,[e("summary",null,"Tags:"),e("a",{href:"/garden/decentralized/index.md"},"Decentralized")],-1),_=e("p",null,[e("a",{href:"https://activitypub.rocks",target:"_blank",rel:"noreferrer"},"ActivityPub"),a(" is a protocol for "),e("a",{href:"/garden/fediverse/"},"Federated Social Media")],-1),y=JSON.parse('{"title":"ActivityPub","description":"","frontmatter":{"public":"true","slug":"activitypub","tags":["Decentralized"],"title":"ActivityPub","prev":false,"next":false},"headers":[],"relativePath":"garden/activitypub/index.md","filePath":"garden/activitypub/index.md"}'),f={name:"garden/activitypub/index.md"},x=Object.assign(f,{setup(m){const i=n();return(h,v)=>(d(),s("div",null,[l,e("p",null,[a("8 words, ~0 minute read. "),e("span",{innerHTML:t(r)[`site/${t(i).page.value.relativePath}`]},null,8,c)]),o,u,p,_]))}});export{y as __pageData,x as default}; diff --git a/assets/garden_activitypub_index.md.DLZvHPXj.lean.js b/assets/garden_activitypub_index.md.DLZvHPXj.lean.js deleted file mode 100644 index 7da39941..00000000 --- a/assets/garden_activitypub_index.md.DLZvHPXj.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as s,j as e,a,k as t,o as d}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"ActivityPub",-1),c=["innerHTML"],o=e("hr",null,null,-1),u=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/fediverse/index.md"},"Fediverse")],-1),p=e("details",null,[e("summary",null,"Tags:"),e("a",{href:"/garden/decentralized/index.md"},"Decentralized")],-1),_=e("p",null,[e("a",{href:"https://activitypub.rocks",target:"_blank",rel:"noreferrer"},"ActivityPub"),a(" is a protocol for "),e("a",{href:"/garden/fediverse/"},"Federated Social Media")],-1),y=JSON.parse('{"title":"ActivityPub","description":"","frontmatter":{"public":"true","slug":"activitypub","tags":["Decentralized"],"title":"ActivityPub","prev":false,"next":false},"headers":[],"relativePath":"garden/activitypub/index.md","filePath":"garden/activitypub/index.md"}'),f={name:"garden/activitypub/index.md"},x=Object.assign(f,{setup(m){const i=n();return(h,v)=>(d(),s("div",null,[l,e("p",null,[a("8 words, ~0 minute read. "),e("span",{innerHTML:t(r)[`site/${t(i).page.value.relativePath}`]},null,8,c)]),o,u,p,_]))}});export{y as __pageData,x as default}; diff --git a/assets/garden_advent-incremental_index.md.CbzLDkso.js b/assets/garden_advent-incremental_index.md.DJsWBIkL.js similarity index 89% rename from assets/garden_advent-incremental_index.md.CbzLDkso.js rename to assets/garden_advent-incremental_index.md.DJsWBIkL.js index a74c4598..aa56f840 100644 --- a/assets/garden_advent-incremental_index.md.CbzLDkso.js +++ b/assets/garden_advent-incremental_index.md.DJsWBIkL.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as r,c as s,j as e,a as o,k as t,ag as d,o as i}from"./chunks/framework.VBE0TPts.js";const p=e("h1",{class:"p-name"},"Advent Incremental",-1),c=["innerHTML"],m=d('
Tags:My ProjectsProfectus

Play it here!

An Open Source game made in Profectus over the course of 1 month by myself and other devs I know in the Incremental Games community!

I had the idea of an advent-style game that unlocked new pieces of content every real-life day a couple days before December started.

This was one of the most hectic months of my life!

I'm super happy with how it turned out. It ended up being way more ambitious than I anticipated but the end result is super large and awesome!

The TV Tropes page on this game mentions some of the cool things about this game

',8),v=JSON.parse('{"title":"Advent Incremental","description":"","frontmatter":{"public":"true","slug":"advent-incremental","tags":["My Projects","Profectus"],"title":"Advent Incremental","prev":false,"next":false},"headers":[],"relativePath":"garden/advent-incremental/index.md","filePath":"garden/advent-incremental/index.md"}'),l={name:"garden/advent-incremental/index.md"},y=Object.assign(l,{setup(h){const a=r();return(u,f)=>(i(),s("div",null,[p,e("p",null,[o("104 words, ~1 minute read. "),e("span",{innerHTML:t(n)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),m]))}});export{v as __pageData,y as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as r,q as s,Q as e,K as o,u as t,ag as d,p as i}from"./chunks/framework.DvHfxfnp.js";const p=e("h1",{class:"p-name"},"Advent Incremental",-1),c=["innerHTML"],m=d('
Tags:My ProjectsProfectus

Play it here!

An Open Source game made in Profectus over the course of 1 month by myself and other devs I know in the Incremental Games community!

I had the idea of an advent-style game that unlocked new pieces of content every real-life day a couple days before December started.

This was one of the most hectic months of my life!

I'm super happy with how it turned out. It ended up being way more ambitious than I anticipated but the end result is super large and awesome!

The TV Tropes page on this game mentions some of the cool things about this game

',8),v=JSON.parse('{"title":"Advent Incremental","description":"","frontmatter":{"public":"true","slug":"advent-incremental","tags":["My Projects","Profectus"],"title":"Advent Incremental","prev":false,"next":false},"headers":[],"relativePath":"garden/advent-incremental/index.md","filePath":"garden/advent-incremental/index.md"}'),l={name:"garden/advent-incremental/index.md"},y=Object.assign(l,{setup(h){const a=r();return(u,f)=>(i(),s("div",null,[p,e("p",null,[o("104 words, ~1 minute read. "),e("span",{innerHTML:t(n)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),m]))}});export{v as __pageData,y as default}; diff --git a/assets/garden_advent-incremental_index.md.CbzLDkso.lean.js b/assets/garden_advent-incremental_index.md.DJsWBIkL.lean.js similarity index 77% rename from assets/garden_advent-incremental_index.md.CbzLDkso.lean.js rename to assets/garden_advent-incremental_index.md.DJsWBIkL.lean.js index 06306179..b2752415 100644 --- a/assets/garden_advent-incremental_index.md.CbzLDkso.lean.js +++ b/assets/garden_advent-incremental_index.md.DJsWBIkL.lean.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as r,c as s,j as e,a as o,k as t,ag as d,o as i}from"./chunks/framework.VBE0TPts.js";const p=e("h1",{class:"p-name"},"Advent Incremental",-1),c=["innerHTML"],m=d("",8),v=JSON.parse('{"title":"Advent Incremental","description":"","frontmatter":{"public":"true","slug":"advent-incremental","tags":["My Projects","Profectus"],"title":"Advent Incremental","prev":false,"next":false},"headers":[],"relativePath":"garden/advent-incremental/index.md","filePath":"garden/advent-incremental/index.md"}'),l={name:"garden/advent-incremental/index.md"},y=Object.assign(l,{setup(h){const a=r();return(u,f)=>(i(),s("div",null,[p,e("p",null,[o("104 words, ~1 minute read. "),e("span",{innerHTML:t(n)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),m]))}});export{v as __pageData,y as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as r,q as s,Q as e,K as o,u as t,ag as d,p as i}from"./chunks/framework.DvHfxfnp.js";const p=e("h1",{class:"p-name"},"Advent Incremental",-1),c=["innerHTML"],m=d("",8),v=JSON.parse('{"title":"Advent Incremental","description":"","frontmatter":{"public":"true","slug":"advent-incremental","tags":["My Projects","Profectus"],"title":"Advent Incremental","prev":false,"next":false},"headers":[],"relativePath":"garden/advent-incremental/index.md","filePath":"garden/advent-incremental/index.md"}'),l={name:"garden/advent-incremental/index.md"},y=Object.assign(l,{setup(h){const a=r();return(u,f)=>(i(),s("div",null,[p,e("p",null,[o("104 words, ~1 minute read. "),e("span",{innerHTML:t(n)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),m]))}});export{v as __pageData,y as default}; diff --git a/assets/garden_artificial-intelligence_index.md.BevJsmT8.js b/assets/garden_artificial-intelligence_index.md.B-XBqRL_.js similarity index 92% rename from assets/garden_artificial-intelligence_index.md.BevJsmT8.js rename to assets/garden_artificial-intelligence_index.md.B-XBqRL_.js index 92dfd3f8..a0e5ee93 100644 --- a/assets/garden_artificial-intelligence_index.md.BevJsmT8.js +++ b/assets/garden_artificial-intelligence_index.md.B-XBqRL_.js @@ -1 +1 @@ -import{d as l}from"./chunks/git.data.DG5NumsR.js";import{u as r,c as i,j as e,a as n,k as a,ag as o,o as s}from"./chunks/framework.VBE0TPts.js";const c=e("h1",{class:"p-name"},"Artificial Intelligence",-1),d=["innerHTML"],p=o('
Referenced by:Command Palettes

Catch all term that refers to many different things

Generative AI

  • Models trained on large amounts of existing human made content in order to produce more of that content
  • Copyright concerns over how training data is obtained
  • Common Examples

Human + AI cooperation

',7),b=JSON.parse('{"title":"Artificial Intelligence","description":"","frontmatter":{"public":"true","slug":"artificial-intelligence","title":"Artificial Intelligence","prev":false,"next":false},"headers":[],"relativePath":"garden/artificial-intelligence/index.md","filePath":"garden/artificial-intelligence/index.md"}'),u={name:"garden/artificial-intelligence/index.md"},k=Object.assign(u,{setup(h){const t=r();return(m,f)=>(s(),i("div",null,[c,e("p",null,[n("101 words, ~1 minute read. "),e("span",{innerHTML:a(l)[`site/${a(t).page.value.relativePath}`]},null,8,d)]),p]))}});export{b as __pageData,k as default}; +import{d as l}from"./chunks/git.data.DG5NumsR.js";import{M as r,q as i,Q as e,K as n,u as a,ag as o,p as s}from"./chunks/framework.DvHfxfnp.js";const c=e("h1",{class:"p-name"},"Artificial Intelligence",-1),d=["innerHTML"],p=o('
Referenced by:Command Palettes

Catch all term that refers to many different things

Generative AI

  • Models trained on large amounts of existing human made content in order to produce more of that content
  • Copyright concerns over how training data is obtained
  • Common Examples

Human + AI cooperation

',7),b=JSON.parse('{"title":"Artificial Intelligence","description":"","frontmatter":{"public":"true","slug":"artificial-intelligence","title":"Artificial Intelligence","prev":false,"next":false},"headers":[],"relativePath":"garden/artificial-intelligence/index.md","filePath":"garden/artificial-intelligence/index.md"}'),u={name:"garden/artificial-intelligence/index.md"},k=Object.assign(u,{setup(h){const t=r();return(m,f)=>(s(),i("div",null,[c,e("p",null,[n("101 words, ~1 minute read. "),e("span",{innerHTML:a(l)[`site/${a(t).page.value.relativePath}`]},null,8,d)]),p]))}});export{b as __pageData,k as default}; diff --git a/assets/garden_artificial-intelligence_index.md.BevJsmT8.lean.js b/assets/garden_artificial-intelligence_index.md.B-XBqRL_.lean.js similarity index 77% rename from assets/garden_artificial-intelligence_index.md.BevJsmT8.lean.js rename to assets/garden_artificial-intelligence_index.md.B-XBqRL_.lean.js index 5c305ac3..9610c42b 100644 --- a/assets/garden_artificial-intelligence_index.md.BevJsmT8.lean.js +++ b/assets/garden_artificial-intelligence_index.md.B-XBqRL_.lean.js @@ -1 +1 @@ -import{d as l}from"./chunks/git.data.DG5NumsR.js";import{u as r,c as i,j as e,a as n,k as a,ag as o,o as s}from"./chunks/framework.VBE0TPts.js";const c=e("h1",{class:"p-name"},"Artificial Intelligence",-1),d=["innerHTML"],p=o("",7),b=JSON.parse('{"title":"Artificial Intelligence","description":"","frontmatter":{"public":"true","slug":"artificial-intelligence","title":"Artificial Intelligence","prev":false,"next":false},"headers":[],"relativePath":"garden/artificial-intelligence/index.md","filePath":"garden/artificial-intelligence/index.md"}'),u={name:"garden/artificial-intelligence/index.md"},k=Object.assign(u,{setup(h){const t=r();return(m,f)=>(s(),i("div",null,[c,e("p",null,[n("101 words, ~1 minute read. "),e("span",{innerHTML:a(l)[`site/${a(t).page.value.relativePath}`]},null,8,d)]),p]))}});export{b as __pageData,k as default}; +import{d as l}from"./chunks/git.data.DG5NumsR.js";import{M as r,q as i,Q as e,K as n,u as a,ag as o,p as s}from"./chunks/framework.DvHfxfnp.js";const c=e("h1",{class:"p-name"},"Artificial Intelligence",-1),d=["innerHTML"],p=o("",7),b=JSON.parse('{"title":"Artificial Intelligence","description":"","frontmatter":{"public":"true","slug":"artificial-intelligence","title":"Artificial Intelligence","prev":false,"next":false},"headers":[],"relativePath":"garden/artificial-intelligence/index.md","filePath":"garden/artificial-intelligence/index.md"}'),u={name:"garden/artificial-intelligence/index.md"},k=Object.assign(u,{setup(h){const t=r();return(m,f)=>(s(),i("div",null,[c,e("p",null,[n("101 words, ~1 minute read. "),e("span",{innerHTML:a(l)[`site/${a(t).page.value.relativePath}`]},null,8,d)]),p]))}});export{b as __pageData,k as default}; diff --git a/assets/garden_atproto_index.md.DS2dsksJ.js b/assets/garden_atproto_index.md.DGb10zg_.js similarity index 73% rename from assets/garden_atproto_index.md.DS2dsksJ.js rename to assets/garden_atproto_index.md.DGb10zg_.js index 19a1392a..16a4e3dd 100644 --- a/assets/garden_atproto_index.md.DS2dsksJ.js +++ b/assets/garden_atproto_index.md.DGb10zg_.js @@ -1 +1 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as o,c as s,j as e,a as n,k as a,ag as d,o as i}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"ATProto",-1),c=["innerHTML"],p=d('
Referenced by:Fediverse
Tags:Decentralized

The AT Protocol is a protocol for Federated Social Media

Currently only used by Bluesky

In comparison to other Fediverse protocols, ATProto is designed for a small number of large instances

',6),T=JSON.parse('{"title":"ATProto","description":"","frontmatter":{"alias":"The AT Protocol","public":"true","slug":"atproto","tags":["Decentralized"],"title":"ATProto","prev":false,"next":false},"headers":[],"relativePath":"garden/atproto/index.md","filePath":"garden/atproto/index.md"}'),_={name:"garden/atproto/index.md"},P=Object.assign(_,{setup(m){const r=o();return(f,u)=>(i(),s("div",null,[l,e("p",null,[n("31 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,c)]),p]))}});export{T as __pageData,P as default}; +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as o,q as s,Q as e,K as n,u as a,ag as d,p as i}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"ATProto",-1),p=["innerHTML"],c=d('
Referenced by:Fediverse
Tags:Decentralized

The AT Protocol is a protocol for Federated Social Media

Currently only used by Bluesky

In comparison to other Fediverse protocols, ATProto is designed for a small number of large instances

',6),T=JSON.parse('{"title":"ATProto","description":"","frontmatter":{"alias":"The AT Protocol","public":"true","slug":"atproto","tags":["Decentralized"],"title":"ATProto","prev":false,"next":false},"headers":[],"relativePath":"garden/atproto/index.md","filePath":"garden/atproto/index.md"}'),_={name:"garden/atproto/index.md"},P=Object.assign(_,{setup(m){const r=o();return(f,u)=>(i(),s("div",null,[l,e("p",null,[n("31 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,p)]),c]))}});export{T as __pageData,P as default}; diff --git a/assets/garden_atproto_index.md.DS2dsksJ.lean.js b/assets/garden_atproto_index.md.DGb10zg_.lean.js similarity index 59% rename from assets/garden_atproto_index.md.DS2dsksJ.lean.js rename to assets/garden_atproto_index.md.DGb10zg_.lean.js index 7b9ca4eb..0fcd1ed7 100644 --- a/assets/garden_atproto_index.md.DS2dsksJ.lean.js +++ b/assets/garden_atproto_index.md.DGb10zg_.lean.js @@ -1 +1 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as o,c as s,j as e,a as n,k as a,ag as d,o as i}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"ATProto",-1),c=["innerHTML"],p=d("",6),T=JSON.parse('{"title":"ATProto","description":"","frontmatter":{"alias":"The AT Protocol","public":"true","slug":"atproto","tags":["Decentralized"],"title":"ATProto","prev":false,"next":false},"headers":[],"relativePath":"garden/atproto/index.md","filePath":"garden/atproto/index.md"}'),_={name:"garden/atproto/index.md"},P=Object.assign(_,{setup(m){const r=o();return(f,u)=>(i(),s("div",null,[l,e("p",null,[n("31 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,c)]),p]))}});export{T as __pageData,P as default}; +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as o,q as s,Q as e,K as n,u as a,ag as d,p as i}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"ATProto",-1),p=["innerHTML"],c=d("",6),T=JSON.parse('{"title":"ATProto","description":"","frontmatter":{"alias":"The AT Protocol","public":"true","slug":"atproto","tags":["Decentralized"],"title":"ATProto","prev":false,"next":false},"headers":[],"relativePath":"garden/atproto/index.md","filePath":"garden/atproto/index.md"}'),_={name:"garden/atproto/index.md"},P=Object.assign(_,{setup(m){const r=o();return(f,u)=>(i(),s("div",null,[l,e("p",null,[n("31 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,p)]),c]))}});export{T as __pageData,P as default}; diff --git a/assets/garden_babble-buds_index.md.D-MhN_8s.js b/assets/garden_babble-buds_index.md.Cdl6QJzR.js similarity index 90% rename from assets/garden_babble-buds_index.md.D-MhN_8s.js rename to assets/garden_babble-buds_index.md.Cdl6QJzR.js index d533adc9..238b3492 100644 --- a/assets/garden_babble-buds_index.md.D-MhN_8s.js +++ b/assets/garden_babble-buds_index.md.Cdl6QJzR.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as o,j as e,a as n,k as t,ag as i,o as b}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Babble Buds",-1),l=["innerHTML"],p=i('
Tags:My Projects

Babble Buds is a tool for creating puppets and interacting with puppets controlled by others on a shared stage

Note: I need to move the website off replit because of their monetization strategy changing. In the meantime, you can check it out from its github repository

Inspired by Puppet Pals by Robert Moran

Intended for use in RPG Campaigns

The renderer was separated into its own project, babble.js, so it could be used for stuff like cutscenes

I ported the engine to C# and used it for the cutscenes in Dice Armor

  • I don't believe I ever separated it out into its own project, but you can find the code here
',9),g=JSON.parse('{"title":"Babble Buds","description":"","frontmatter":{"public":"true","slug":"babble-buds","tags":["My Projects"],"title":"Babble Buds","prev":false,"next":false},"headers":[],"relativePath":"garden/babble-buds/index.md","filePath":"garden/babble-buds/index.md"}'),c={name:"garden/babble-buds/index.md"},y=Object.assign(c,{setup(u){const a=s();return(h,_)=>(b(),o("div",null,[d,e("p",null,[n("113 words, ~1 minute read. "),e("span",{innerHTML:t(r)[`site/${t(a).page.value.relativePath}`]},null,8,l)]),p]))}});export{g as __pageData,y as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as o,Q as e,K as n,u as t,ag as i,p as b}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Babble Buds",-1),l=["innerHTML"],p=i('
Tags:My Projects

Babble Buds is a tool for creating puppets and interacting with puppets controlled by others on a shared stage

Note: I need to move the website off replit because of their monetization strategy changing. In the meantime, you can check it out from its github repository

Inspired by Puppet Pals by Robert Moran

Intended for use in RPG Campaigns

The renderer was separated into its own project, babble.js, so it could be used for stuff like cutscenes

I ported the engine to C# and used it for the cutscenes in Dice Armor

  • I don't believe I ever separated it out into its own project, but you can find the code here
',9),g=JSON.parse('{"title":"Babble Buds","description":"","frontmatter":{"public":"true","slug":"babble-buds","tags":["My Projects"],"title":"Babble Buds","prev":false,"next":false},"headers":[],"relativePath":"garden/babble-buds/index.md","filePath":"garden/babble-buds/index.md"}'),c={name:"garden/babble-buds/index.md"},y=Object.assign(c,{setup(u){const a=s();return(h,_)=>(b(),o("div",null,[d,e("p",null,[n("113 words, ~1 minute read. "),e("span",{innerHTML:t(r)[`site/${t(a).page.value.relativePath}`]},null,8,l)]),p]))}});export{g as __pageData,y as default}; diff --git a/assets/garden_babble-buds_index.md.D-MhN_8s.lean.js b/assets/garden_babble-buds_index.md.Cdl6QJzR.lean.js similarity index 75% rename from assets/garden_babble-buds_index.md.D-MhN_8s.lean.js rename to assets/garden_babble-buds_index.md.Cdl6QJzR.lean.js index cb4f22b9..10139e2e 100644 --- a/assets/garden_babble-buds_index.md.D-MhN_8s.lean.js +++ b/assets/garden_babble-buds_index.md.Cdl6QJzR.lean.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as o,j as e,a as n,k as t,ag as i,o as b}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Babble Buds",-1),l=["innerHTML"],p=i("",9),g=JSON.parse('{"title":"Babble Buds","description":"","frontmatter":{"public":"true","slug":"babble-buds","tags":["My Projects"],"title":"Babble Buds","prev":false,"next":false},"headers":[],"relativePath":"garden/babble-buds/index.md","filePath":"garden/babble-buds/index.md"}'),c={name:"garden/babble-buds/index.md"},y=Object.assign(c,{setup(u){const a=s();return(h,_)=>(b(),o("div",null,[d,e("p",null,[n("113 words, ~1 minute read. "),e("span",{innerHTML:t(r)[`site/${t(a).page.value.relativePath}`]},null,8,l)]),p]))}});export{g as __pageData,y as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as o,Q as e,K as n,u as t,ag as i,p as b}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Babble Buds",-1),l=["innerHTML"],p=i("",9),g=JSON.parse('{"title":"Babble Buds","description":"","frontmatter":{"public":"true","slug":"babble-buds","tags":["My Projects"],"title":"Babble Buds","prev":false,"next":false},"headers":[],"relativePath":"garden/babble-buds/index.md","filePath":"garden/babble-buds/index.md"}'),c={name:"garden/babble-buds/index.md"},y=Object.assign(c,{setup(u){const a=s();return(h,_)=>(b(),o("div",null,[d,e("p",null,[n("113 words, ~1 minute read. "),e("span",{innerHTML:t(r)[`site/${t(a).page.value.relativePath}`]},null,8,l)]),p]))}});export{g as __pageData,y as default}; diff --git a/assets/garden_capture-the-citadel_index.md.B81Zl3jT.js b/assets/garden_capture-the-citadel_index.md.BSzKEtwa.js similarity index 69% rename from assets/garden_capture-the-citadel_index.md.B81Zl3jT.js rename to assets/garden_capture-the-citadel_index.md.BSzKEtwa.js index 688e5c71..5770e4b8 100644 --- a/assets/garden_capture-the-citadel_index.md.B81Zl3jT.js +++ b/assets/garden_capture-the-citadel_index.md.BSzKEtwa.js @@ -1 +1 @@ -import{u as s,c as n,j as e,a as t,k as a,ah as i,o as l}from"./chunks/framework.VBE0TPts.js";import{d as o}from"./chunks/git.data.DG5NumsR.js";const c=e("h1",{class:"p-name"},"Capture the Citadel",-1),d=["innerHTML"],h=e("hr",null,null,-1),p=e("details",null,[e("summary",null,"Tags:"),e("a",{href:"/garden/my-projects/index.md"},"My Projects")],-1),u=e("p",null,"A 3D VR re-envisioning of a Slay the Spire-style game by Anthony Lawn and Grant Barbee for their VR class in college's final project.",-1),_=e("p",null,[t("For more details, visit "),e("a",{href:"https://grantcbarbee.github.io/conquer-the-citadel.html",target:"_blank",rel:"noreferrer"},"Grant's page on the game"),t(".")],-1),m=e("div",{class:"img-container"},[e("img",{src:i,title:"screenshot.png"})],-1),j=JSON.parse('{"title":"Capture the Citadel","description":"","frontmatter":{"public":"true","slug":"capture-the-citadel","tags":["My Projects"],"title":"Capture the Citadel","prev":false,"next":false},"headers":[],"relativePath":"garden/capture-the-citadel/index.md","filePath":"garden/capture-the-citadel/index.md"}'),g={name:"garden/capture-the-citadel/index.md"},C=Object.assign(g,{setup(f){const r=s();return(b,v)=>(l(),n("div",null,[c,e("p",null,[t("39 words, ~0 minute read. "),e("span",{innerHTML:a(o)[`site/${a(r).page.value.relativePath}`]},null,8,d)]),h,p,u,_,m]))}});export{j as __pageData,C as default}; +import{M as s,q as n,Q as e,K as t,u as a,ah as i,p as l}from"./chunks/framework.DvHfxfnp.js";import{d as o}from"./chunks/git.data.DG5NumsR.js";const c=e("h1",{class:"p-name"},"Capture the Citadel",-1),d=["innerHTML"],p=e("hr",null,null,-1),h=e("details",null,[e("summary",null,"Tags:"),e("a",{href:"/garden/my-projects/index.md"},"My Projects")],-1),u=e("p",null,"A 3D VR re-envisioning of a Slay the Spire-style game by Anthony Lawn and Grant Barbee for their VR class in college's final project.",-1),_=e("p",null,[t("For more details, visit "),e("a",{href:"https://grantcbarbee.github.io/conquer-the-citadel.html",target:"_blank",rel:"noreferrer"},"Grant's page on the game"),t(".")],-1),m=e("div",{class:"img-container"},[e("img",{src:i,title:"screenshot.png"})],-1),C=JSON.parse('{"title":"Capture the Citadel","description":"","frontmatter":{"public":"true","slug":"capture-the-citadel","tags":["My Projects"],"title":"Capture the Citadel","prev":false,"next":false},"headers":[],"relativePath":"garden/capture-the-citadel/index.md","filePath":"garden/capture-the-citadel/index.md"}'),g={name:"garden/capture-the-citadel/index.md"},j=Object.assign(g,{setup(f){const r=s();return(b,v)=>(l(),n("div",null,[c,e("p",null,[t("39 words, ~0 minute read. "),e("span",{innerHTML:a(o)[`site/${a(r).page.value.relativePath}`]},null,8,d)]),p,h,u,_,m]))}});export{C as __pageData,j as default}; diff --git a/assets/garden_capture-the-citadel_index.md.B81Zl3jT.lean.js b/assets/garden_capture-the-citadel_index.md.BSzKEtwa.lean.js similarity index 69% rename from assets/garden_capture-the-citadel_index.md.B81Zl3jT.lean.js rename to assets/garden_capture-the-citadel_index.md.BSzKEtwa.lean.js index 688e5c71..5770e4b8 100644 --- a/assets/garden_capture-the-citadel_index.md.B81Zl3jT.lean.js +++ b/assets/garden_capture-the-citadel_index.md.BSzKEtwa.lean.js @@ -1 +1 @@ -import{u as s,c as n,j as e,a as t,k as a,ah as i,o as l}from"./chunks/framework.VBE0TPts.js";import{d as o}from"./chunks/git.data.DG5NumsR.js";const c=e("h1",{class:"p-name"},"Capture the Citadel",-1),d=["innerHTML"],h=e("hr",null,null,-1),p=e("details",null,[e("summary",null,"Tags:"),e("a",{href:"/garden/my-projects/index.md"},"My Projects")],-1),u=e("p",null,"A 3D VR re-envisioning of a Slay the Spire-style game by Anthony Lawn and Grant Barbee for their VR class in college's final project.",-1),_=e("p",null,[t("For more details, visit "),e("a",{href:"https://grantcbarbee.github.io/conquer-the-citadel.html",target:"_blank",rel:"noreferrer"},"Grant's page on the game"),t(".")],-1),m=e("div",{class:"img-container"},[e("img",{src:i,title:"screenshot.png"})],-1),j=JSON.parse('{"title":"Capture the Citadel","description":"","frontmatter":{"public":"true","slug":"capture-the-citadel","tags":["My Projects"],"title":"Capture the Citadel","prev":false,"next":false},"headers":[],"relativePath":"garden/capture-the-citadel/index.md","filePath":"garden/capture-the-citadel/index.md"}'),g={name:"garden/capture-the-citadel/index.md"},C=Object.assign(g,{setup(f){const r=s();return(b,v)=>(l(),n("div",null,[c,e("p",null,[t("39 words, ~0 minute read. "),e("span",{innerHTML:a(o)[`site/${a(r).page.value.relativePath}`]},null,8,d)]),h,p,u,_,m]))}});export{j as __pageData,C as default}; +import{M as s,q as n,Q as e,K as t,u as a,ah as i,p as l}from"./chunks/framework.DvHfxfnp.js";import{d as o}from"./chunks/git.data.DG5NumsR.js";const c=e("h1",{class:"p-name"},"Capture the Citadel",-1),d=["innerHTML"],p=e("hr",null,null,-1),h=e("details",null,[e("summary",null,"Tags:"),e("a",{href:"/garden/my-projects/index.md"},"My Projects")],-1),u=e("p",null,"A 3D VR re-envisioning of a Slay the Spire-style game by Anthony Lawn and Grant Barbee for their VR class in college's final project.",-1),_=e("p",null,[t("For more details, visit "),e("a",{href:"https://grantcbarbee.github.io/conquer-the-citadel.html",target:"_blank",rel:"noreferrer"},"Grant's page on the game"),t(".")],-1),m=e("div",{class:"img-container"},[e("img",{src:i,title:"screenshot.png"})],-1),C=JSON.parse('{"title":"Capture the Citadel","description":"","frontmatter":{"public":"true","slug":"capture-the-citadel","tags":["My Projects"],"title":"Capture the Citadel","prev":false,"next":false},"headers":[],"relativePath":"garden/capture-the-citadel/index.md","filePath":"garden/capture-the-citadel/index.md"}'),g={name:"garden/capture-the-citadel/index.md"},j=Object.assign(g,{setup(f){const r=s();return(b,v)=>(l(),n("div",null,[c,e("p",null,[t("39 words, ~0 minute read. "),e("span",{innerHTML:a(o)[`site/${a(r).page.value.relativePath}`]},null,8,d)]),p,h,u,_,m]))}});export{C as __pageData,j as default}; diff --git a/assets/garden_chat-glue_index.md.DrB0BEZa.js b/assets/garden_chat-glue_index.md.BybR6u1O.js similarity index 85% rename from assets/garden_chat-glue_index.md.DrB0BEZa.js rename to assets/garden_chat-glue_index.md.BybR6u1O.js index df679ab5..9ca2320f 100644 --- a/assets/garden_chat-glue_index.md.DrB0BEZa.js +++ b/assets/garden_chat-glue_index.md.BybR6u1O.js @@ -1 +1 @@ -import{d as s}from"./chunks/git.data.DG5NumsR.js";import{u as l,c as r,j as e,a as t,k as a,o as i}from"./chunks/framework.VBE0TPts.js";const o=e("h1",{class:"p-name"},"Chat Glue",-1),d=["innerHTML"],c=e("hr",null,null,-1),h=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/commune/index.md"},"Commune"),e("a",{href:"/garden/my-personal-website/index.md"},"My Personal Website"),e("a",{href:"/garden/the-small-web/index.md"},"The Small Web")],-1),u=e("p",null,"A theoretical chat system designed to solve the problems of transcribing branching conversations into linear timelines.",-1),m=e("p",null,[t("Defined by the "),e("a",{href:"https://a9.io/glue-comic/",target:"_blank",rel:"noreferrer"},"Chatting with Glue"),t(" comic.")],-1),v=JSON.parse('{"title":"Chat Glue","description":"","frontmatter":{"public":"true","slug":"chat-glue","title":"Chat Glue","prev":false,"next":false},"headers":[],"relativePath":"garden/chat-glue/index.md","filePath":"garden/chat-glue/index.md"}'),_={name:"garden/chat-glue/index.md"},y=Object.assign(_,{setup(p){const n=l();return(g,f)=>(i(),r("div",null,[o,e("p",null,[t("23 words, ~0 minute read. "),e("span",{innerHTML:a(s)[`site/${a(n).page.value.relativePath}`]},null,8,d)]),c,h,u,m]))}});export{v as __pageData,y as default}; +import{d as s}from"./chunks/git.data.DG5NumsR.js";import{M as l,q as r,Q as e,K as t,u as a,p as i}from"./chunks/framework.DvHfxfnp.js";const o=e("h1",{class:"p-name"},"Chat Glue",-1),d=["innerHTML"],c=e("hr",null,null,-1),h=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/commune/index.md"},"Commune"),e("a",{href:"/garden/my-personal-website/index.md"},"My Personal Website"),e("a",{href:"/garden/the-small-web/index.md"},"The Small Web")],-1),u=e("p",null,"A theoretical chat system designed to solve the problems of transcribing branching conversations into linear timelines.",-1),m=e("p",null,[t("Defined by the "),e("a",{href:"https://a9.io/glue-comic/",target:"_blank",rel:"noreferrer"},"Chatting with Glue"),t(" comic.")],-1),v=JSON.parse('{"title":"Chat Glue","description":"","frontmatter":{"public":"true","slug":"chat-glue","title":"Chat Glue","prev":false,"next":false},"headers":[],"relativePath":"garden/chat-glue/index.md","filePath":"garden/chat-glue/index.md"}'),_={name:"garden/chat-glue/index.md"},y=Object.assign(_,{setup(p){const n=l();return(g,f)=>(i(),r("div",null,[o,e("p",null,[t("23 words, ~0 minute read. "),e("span",{innerHTML:a(s)[`site/${a(n).page.value.relativePath}`]},null,8,d)]),c,h,u,m]))}});export{v as __pageData,y as default}; diff --git a/assets/garden_chat-glue_index.md.DrB0BEZa.lean.js b/assets/garden_chat-glue_index.md.BybR6u1O.lean.js similarity index 85% rename from assets/garden_chat-glue_index.md.DrB0BEZa.lean.js rename to assets/garden_chat-glue_index.md.BybR6u1O.lean.js index df679ab5..9ca2320f 100644 --- a/assets/garden_chat-glue_index.md.DrB0BEZa.lean.js +++ b/assets/garden_chat-glue_index.md.BybR6u1O.lean.js @@ -1 +1 @@ -import{d as s}from"./chunks/git.data.DG5NumsR.js";import{u as l,c as r,j as e,a as t,k as a,o as i}from"./chunks/framework.VBE0TPts.js";const o=e("h1",{class:"p-name"},"Chat Glue",-1),d=["innerHTML"],c=e("hr",null,null,-1),h=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/commune/index.md"},"Commune"),e("a",{href:"/garden/my-personal-website/index.md"},"My Personal Website"),e("a",{href:"/garden/the-small-web/index.md"},"The Small Web")],-1),u=e("p",null,"A theoretical chat system designed to solve the problems of transcribing branching conversations into linear timelines.",-1),m=e("p",null,[t("Defined by the "),e("a",{href:"https://a9.io/glue-comic/",target:"_blank",rel:"noreferrer"},"Chatting with Glue"),t(" comic.")],-1),v=JSON.parse('{"title":"Chat Glue","description":"","frontmatter":{"public":"true","slug":"chat-glue","title":"Chat Glue","prev":false,"next":false},"headers":[],"relativePath":"garden/chat-glue/index.md","filePath":"garden/chat-glue/index.md"}'),_={name:"garden/chat-glue/index.md"},y=Object.assign(_,{setup(p){const n=l();return(g,f)=>(i(),r("div",null,[o,e("p",null,[t("23 words, ~0 minute read. "),e("span",{innerHTML:a(s)[`site/${a(n).page.value.relativePath}`]},null,8,d)]),c,h,u,m]))}});export{v as __pageData,y as default}; +import{d as s}from"./chunks/git.data.DG5NumsR.js";import{M as l,q as r,Q as e,K as t,u as a,p as i}from"./chunks/framework.DvHfxfnp.js";const o=e("h1",{class:"p-name"},"Chat Glue",-1),d=["innerHTML"],c=e("hr",null,null,-1),h=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/commune/index.md"},"Commune"),e("a",{href:"/garden/my-personal-website/index.md"},"My Personal Website"),e("a",{href:"/garden/the-small-web/index.md"},"The Small Web")],-1),u=e("p",null,"A theoretical chat system designed to solve the problems of transcribing branching conversations into linear timelines.",-1),m=e("p",null,[t("Defined by the "),e("a",{href:"https://a9.io/glue-comic/",target:"_blank",rel:"noreferrer"},"Chatting with Glue"),t(" comic.")],-1),v=JSON.parse('{"title":"Chat Glue","description":"","frontmatter":{"public":"true","slug":"chat-glue","title":"Chat Glue","prev":false,"next":false},"headers":[],"relativePath":"garden/chat-glue/index.md","filePath":"garden/chat-glue/index.md"}'),_={name:"garden/chat-glue/index.md"},y=Object.assign(_,{setup(p){const n=l();return(g,f)=>(i(),r("div",null,[o,e("p",null,[t("23 words, ~0 minute read. "),e("span",{innerHTML:a(s)[`site/${a(n).page.value.relativePath}`]},null,8,d)]),c,h,u,m]))}});export{v as __pageData,y as default}; diff --git a/assets/garden_chronological_index.md.Du31gSeZ.js b/assets/garden_chronological_index.md.CwbET-Cb.js similarity index 88% rename from assets/garden_chronological_index.md.Du31gSeZ.js rename to assets/garden_chronological_index.md.CwbET-Cb.js index b22598e9..7d0accf7 100644 --- a/assets/garden_chronological_index.md.Du31gSeZ.js +++ b/assets/garden_chronological_index.md.CwbET-Cb.js @@ -1 +1 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as r,c as i,j as e,a as n,k as a,ag as l,o as s}from"./chunks/framework.VBE0TPts.js";const c=e("h1",{class:"p-name"},"Chronological",-1),d=["innerHTML"],h=l('
Referenced by:Digital GardensFreeform vs Chronological Dichotomy

A collection of information that is tied to its creation or edit date

Part of the Freeform vs Chronological Dichotomy

Anything with a "timeline" or "feed" is considered chronological

  • Even if there's algorithmic sortings that take things other than creation or edit date into account!

Chronological displays are less suitable as stores of knowledge (Digital Gardens)

Social media overuses timelines and feeds

RSS feeds work really well with this form of content

',9),v=JSON.parse('{"title":"Chronological","description":"","frontmatter":{"public":"true","slug":"chronological","title":"Chronological","prev":false,"next":false},"headers":[],"relativePath":"garden/chronological/index.md","filePath":"garden/chronological/index.md"}'),g={name:"garden/chronological/index.md"},y=Object.assign(g,{setup(m){const o=r();return(f,p)=>(s(),i("div",null,[c,e("p",null,[n("73 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(o).page.value.relativePath}`]},null,8,d)]),h]))}});export{v as __pageData,y as default}; +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as r,q as i,Q as e,K as n,u as a,ag as l,p as s}from"./chunks/framework.DvHfxfnp.js";const c=e("h1",{class:"p-name"},"Chronological",-1),d=["innerHTML"],h=l('
Referenced by:Digital GardensFreeform vs Chronological Dichotomy

A collection of information that is tied to its creation or edit date

Part of the Freeform vs Chronological Dichotomy

Anything with a "timeline" or "feed" is considered chronological

  • Even if there's algorithmic sortings that take things other than creation or edit date into account!

Chronological displays are less suitable as stores of knowledge (Digital Gardens)

Social media overuses timelines and feeds

RSS feeds work really well with this form of content

',9),v=JSON.parse('{"title":"Chronological","description":"","frontmatter":{"public":"true","slug":"chronological","title":"Chronological","prev":false,"next":false},"headers":[],"relativePath":"garden/chronological/index.md","filePath":"garden/chronological/index.md"}'),g={name:"garden/chronological/index.md"},y=Object.assign(g,{setup(m){const o=r();return(f,p)=>(s(),i("div",null,[c,e("p",null,[n("73 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(o).page.value.relativePath}`]},null,8,d)]),h]))}});export{v as __pageData,y as default}; diff --git a/assets/garden_chronological_index.md.Du31gSeZ.lean.js b/assets/garden_chronological_index.md.CwbET-Cb.lean.js similarity index 75% rename from assets/garden_chronological_index.md.Du31gSeZ.lean.js rename to assets/garden_chronological_index.md.CwbET-Cb.lean.js index 4d151064..19edc5a6 100644 --- a/assets/garden_chronological_index.md.Du31gSeZ.lean.js +++ b/assets/garden_chronological_index.md.CwbET-Cb.lean.js @@ -1 +1 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as r,c as i,j as e,a as n,k as a,ag as l,o as s}from"./chunks/framework.VBE0TPts.js";const c=e("h1",{class:"p-name"},"Chronological",-1),d=["innerHTML"],h=l("",9),v=JSON.parse('{"title":"Chronological","description":"","frontmatter":{"public":"true","slug":"chronological","title":"Chronological","prev":false,"next":false},"headers":[],"relativePath":"garden/chronological/index.md","filePath":"garden/chronological/index.md"}'),g={name:"garden/chronological/index.md"},y=Object.assign(g,{setup(m){const o=r();return(f,p)=>(s(),i("div",null,[c,e("p",null,[n("73 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(o).page.value.relativePath}`]},null,8,d)]),h]))}});export{v as __pageData,y as default}; +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as r,q as i,Q as e,K as n,u as a,ag as l,p as s}from"./chunks/framework.DvHfxfnp.js";const c=e("h1",{class:"p-name"},"Chronological",-1),d=["innerHTML"],h=l("",9),v=JSON.parse('{"title":"Chronological","description":"","frontmatter":{"public":"true","slug":"chronological","title":"Chronological","prev":false,"next":false},"headers":[],"relativePath":"garden/chronological/index.md","filePath":"garden/chronological/index.md"}'),g={name:"garden/chronological/index.md"},y=Object.assign(g,{setup(m){const o=r();return(f,p)=>(s(),i("div",null,[c,e("p",null,[n("73 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(o).page.value.relativePath}`]},null,8,d)]),h]))}});export{v as __pageData,y as default}; diff --git a/assets/garden_cinny_index.md.Ch9QVly5.js b/assets/garden_cinny_index.md.ZTWxRUBw.js similarity index 59% rename from assets/garden_cinny_index.md.Ch9QVly5.js rename to assets/garden_cinny_index.md.ZTWxRUBw.js index 4ab61fe4..93b2158d 100644 --- a/assets/garden_cinny_index.md.Ch9QVly5.js +++ b/assets/garden_cinny_index.md.ZTWxRUBw.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as i,j as e,a as n,k as a,o as l}from"./chunks/framework.VBE0TPts.js";const o=e("h1",{class:"p-name"},"Cinny",-1),c=["innerHTML"],d=e("hr",null,null,-1),u=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/incremental-social/index.md"},"Incremental Social")],-1),_=e("p",null,[e("a",{href:"https://cinny.in",target:"_blank",rel:"noreferrer"},"Cinny"),n(" is an "),e("a",{href:"/garden/open-source/"},"Open Source"),n(" web client for the "),e("a",{href:"/garden/matrix/"},"Matrix"),n(" messaging protocol")],-1),x=JSON.parse('{"title":"Cinny","description":"","frontmatter":{"public":"true","slug":"cinny","title":"Cinny","prev":false,"next":false},"headers":[],"relativePath":"garden/cinny/index.md","filePath":"garden/cinny/index.md"}'),p={name:"garden/cinny/index.md"},b=Object.assign(p,{setup(m){const t=s();return(h,f)=>(l(),i("div",null,[o,e("p",null,[n("3 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,c)]),d,u,_]))}});export{x as __pageData,b as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as i,Q as e,K as n,u as a,p as l}from"./chunks/framework.DvHfxfnp.js";const o=e("h1",{class:"p-name"},"Cinny",-1),c=["innerHTML"],d=e("hr",null,null,-1),u=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/incremental-social/index.md"},"Incremental Social")],-1),p=e("p",null,[e("a",{href:"https://cinny.in",target:"_blank",rel:"noreferrer"},"Cinny"),n(" is an "),e("a",{href:"/garden/open-source/"},"Open Source"),n(" web client for the "),e("a",{href:"/garden/matrix/"},"Matrix"),n(" messaging protocol")],-1),x=JSON.parse('{"title":"Cinny","description":"","frontmatter":{"public":"true","slug":"cinny","title":"Cinny","prev":false,"next":false},"headers":[],"relativePath":"garden/cinny/index.md","filePath":"garden/cinny/index.md"}'),_={name:"garden/cinny/index.md"},b=Object.assign(_,{setup(m){const t=s();return(h,f)=>(l(),i("div",null,[o,e("p",null,[n("3 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,c)]),d,u,p]))}});export{x as __pageData,b as default}; diff --git a/assets/garden_cinny_index.md.Ch9QVly5.lean.js b/assets/garden_cinny_index.md.ZTWxRUBw.lean.js similarity index 59% rename from assets/garden_cinny_index.md.Ch9QVly5.lean.js rename to assets/garden_cinny_index.md.ZTWxRUBw.lean.js index 4ab61fe4..93b2158d 100644 --- a/assets/garden_cinny_index.md.Ch9QVly5.lean.js +++ b/assets/garden_cinny_index.md.ZTWxRUBw.lean.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as i,j as e,a as n,k as a,o as l}from"./chunks/framework.VBE0TPts.js";const o=e("h1",{class:"p-name"},"Cinny",-1),c=["innerHTML"],d=e("hr",null,null,-1),u=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/incremental-social/index.md"},"Incremental Social")],-1),_=e("p",null,[e("a",{href:"https://cinny.in",target:"_blank",rel:"noreferrer"},"Cinny"),n(" is an "),e("a",{href:"/garden/open-source/"},"Open Source"),n(" web client for the "),e("a",{href:"/garden/matrix/"},"Matrix"),n(" messaging protocol")],-1),x=JSON.parse('{"title":"Cinny","description":"","frontmatter":{"public":"true","slug":"cinny","title":"Cinny","prev":false,"next":false},"headers":[],"relativePath":"garden/cinny/index.md","filePath":"garden/cinny/index.md"}'),p={name:"garden/cinny/index.md"},b=Object.assign(p,{setup(m){const t=s();return(h,f)=>(l(),i("div",null,[o,e("p",null,[n("3 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,c)]),d,u,_]))}});export{x as __pageData,b as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as i,Q as e,K as n,u as a,p as l}from"./chunks/framework.DvHfxfnp.js";const o=e("h1",{class:"p-name"},"Cinny",-1),c=["innerHTML"],d=e("hr",null,null,-1),u=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/incremental-social/index.md"},"Incremental Social")],-1),p=e("p",null,[e("a",{href:"https://cinny.in",target:"_blank",rel:"noreferrer"},"Cinny"),n(" is an "),e("a",{href:"/garden/open-source/"},"Open Source"),n(" web client for the "),e("a",{href:"/garden/matrix/"},"Matrix"),n(" messaging protocol")],-1),x=JSON.parse('{"title":"Cinny","description":"","frontmatter":{"public":"true","slug":"cinny","title":"Cinny","prev":false,"next":false},"headers":[],"relativePath":"garden/cinny/index.md","filePath":"garden/cinny/index.md"}'),_={name:"garden/cinny/index.md"},b=Object.assign(_,{setup(m){const t=s();return(h,f)=>(l(),i("div",null,[o,e("p",null,[n("3 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,c)]),d,u,p]))}});export{x as __pageData,b as default}; diff --git a/assets/garden_command-palettes_index.md.Br8Wqkvv.js b/assets/garden_command-palettes_index.md.BrnpBbTf.js similarity index 82% rename from assets/garden_command-palettes_index.md.Br8Wqkvv.js rename to assets/garden_command-palettes_index.md.BrnpBbTf.js index 0d6e14a7..80fb1952 100644 --- a/assets/garden_command-palettes_index.md.Br8Wqkvv.js +++ b/assets/garden_command-palettes_index.md.BrnpBbTf.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as l,j as e,a as o,k as a,ag as i,o as r}from"./chunks/framework.VBE0TPts.js";const m=e("h1",{class:"p-name"},"Command Palettes",-1),c=["innerHTML"],p=i('

Command palettes are a design pattern where apps expose functionality through a search bar

Typing what you want is almost certainly easier and faster than finding the action in some submenu or remembering an arcane hotkey

  • Especially with fuzzy search that also looks through descriptions of actions
  • Command palettes scale very well with large amounts of actions

Artificial Intelligence will make command palettes increasingly powerful

  • Eventually these may become conversational interfaces

Maggie Appleton discusses this pattern in her article on Command K Bars

  • The name comes from the fact many apps use the ctrl/cmd k shortcut to open the command palette

Many softwares I use have some form of command palette

  • Linear
  • Logseq
  • Visual Studio Code
',10),y=JSON.parse('{"title":"Command Palettes","description":"","frontmatter":{"public":"true","slug":"command-palettes","title":"Command Palettes","prev":false,"next":false},"headers":[],"relativePath":"garden/command-palettes/index.md","filePath":"garden/command-palettes/index.md"}'),d={name:"garden/command-palettes/index.md"},T=Object.assign(d,{setup(u){const t=s();return(h,_)=>(r(),l("div",null,[m,e("p",null,[o("117 words, ~1 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,c)]),p]))}});export{y as __pageData,T as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as l,Q as e,K as i,u as a,ag as o,p as r}from"./chunks/framework.DvHfxfnp.js";const m=e("h1",{class:"p-name"},"Command Palettes",-1),c=["innerHTML"],p=o('

Command palettes are a design pattern where apps expose functionality through a search bar

Typing what you want is almost certainly easier and faster than finding the action in some submenu or remembering an arcane hotkey

  • Especially with fuzzy search that also looks through descriptions of actions
  • Command palettes scale very well with large amounts of actions

Artificial Intelligence will make command palettes increasingly powerful

  • Eventually these may become conversational interfaces

Maggie Appleton discusses this pattern in her article on Command K Bars

  • The name comes from the fact many apps use the ctrl/cmd k shortcut to open the command palette

Many softwares I use have some form of command palette

  • Linear
  • Logseq
  • Visual Studio Code
',10),y=JSON.parse('{"title":"Command Palettes","description":"","frontmatter":{"public":"true","slug":"command-palettes","title":"Command Palettes","prev":false,"next":false},"headers":[],"relativePath":"garden/command-palettes/index.md","filePath":"garden/command-palettes/index.md"}'),d={name:"garden/command-palettes/index.md"},T=Object.assign(d,{setup(u){const t=s();return(h,_)=>(r(),l("div",null,[m,e("p",null,[i("117 words, ~1 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,c)]),p]))}});export{y as __pageData,T as default}; diff --git a/assets/garden_command-palettes_index.md.Br8Wqkvv.lean.js b/assets/garden_command-palettes_index.md.BrnpBbTf.lean.js similarity index 59% rename from assets/garden_command-palettes_index.md.Br8Wqkvv.lean.js rename to assets/garden_command-palettes_index.md.BrnpBbTf.lean.js index 677febc3..b0ce6f9f 100644 --- a/assets/garden_command-palettes_index.md.Br8Wqkvv.lean.js +++ b/assets/garden_command-palettes_index.md.BrnpBbTf.lean.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as l,j as e,a as o,k as a,ag as i,o as r}from"./chunks/framework.VBE0TPts.js";const m=e("h1",{class:"p-name"},"Command Palettes",-1),c=["innerHTML"],p=i("",10),y=JSON.parse('{"title":"Command Palettes","description":"","frontmatter":{"public":"true","slug":"command-palettes","title":"Command Palettes","prev":false,"next":false},"headers":[],"relativePath":"garden/command-palettes/index.md","filePath":"garden/command-palettes/index.md"}'),d={name:"garden/command-palettes/index.md"},T=Object.assign(d,{setup(u){const t=s();return(h,_)=>(r(),l("div",null,[m,e("p",null,[o("117 words, ~1 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,c)]),p]))}});export{y as __pageData,T as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as l,Q as e,K as i,u as a,ag as o,p as r}from"./chunks/framework.DvHfxfnp.js";const m=e("h1",{class:"p-name"},"Command Palettes",-1),c=["innerHTML"],p=o("",10),y=JSON.parse('{"title":"Command Palettes","description":"","frontmatter":{"public":"true","slug":"command-palettes","title":"Command Palettes","prev":false,"next":false},"headers":[],"relativePath":"garden/command-palettes/index.md","filePath":"garden/command-palettes/index.md"}'),d={name:"garden/command-palettes/index.md"},T=Object.assign(d,{setup(u){const t=s();return(h,_)=>(r(),l("div",null,[m,e("p",null,[i("117 words, ~1 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,c)]),p]))}});export{y as __pageData,T as default}; diff --git a/assets/garden_commune_index.md.VBDo-SJ7.js b/assets/garden_commune_index.md.V0TqobbD.js similarity index 89% rename from assets/garden_commune_index.md.VBDo-SJ7.js rename to assets/garden_commune_index.md.V0TqobbD.js index f436be91..428d75f0 100644 --- a/assets/garden_commune_index.md.VBDo-SJ7.js +++ b/assets/garden_commune_index.md.V0TqobbD.js @@ -1 +1 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as i,c as n,j as e,a as l,k as a,ag as s,o as d}from"./chunks/framework.VBE0TPts.js";const o=e("h1",{class:"p-name"},"Commune",-1),m=["innerHTML"],h=s('
Referenced by:Federated IdentityMy Personal Website/nowWebringsWeird

An Open Source Matrix web client built to be better for communities than anything else out there

  • Currently in development
  • Exposes certain channels such that they are web indexable
  • Will include features like Chat Glue and communal Digital Gardens

Created by Erlend Sogge Heggen, a ex-employee from Discourse

  • Maintains the Commune Blog with great write ups on the issues of the modern web, social media, etc. and how they can be improved (by Commune or related projects)
  • Also maintains a Personal Blog about similar topics

The Commune community is very interested in various topics and how they can relate together:

Related projects:

  • @laxla@tech.lgbt is creating Gimli, a federated discord alternative
    • Built on ActivityPub
    • "Guild-based" in ways matrix is not?
    • Will integrate with F3 as well
    • Wants to handle blogging as well
    • Certainly seems similar to Commune's message gardening concept
',10),b=JSON.parse('{"title":"Commune","description":"","frontmatter":{"public":"true","slug":"commune","title":"Commune","prev":false,"next":false},"headers":[],"relativePath":"garden/commune/index.md","filePath":"garden/commune/index.md"}'),c={name:"garden/commune/index.md"},y=Object.assign(c,{setup(u){const r=i();return(g,f)=>(d(),n("div",null,[o,e("p",null,[l("144 words, ~1 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,m)]),h]))}});export{b as __pageData,y as default}; +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as n,Q as e,K as l,u as a,ag as s,p as d}from"./chunks/framework.DvHfxfnp.js";const o=e("h1",{class:"p-name"},"Commune",-1),m=["innerHTML"],h=s('
Referenced by:Federated IdentityMy Personal Website/nowWebringsWeird

An Open Source Matrix web client built to be better for communities than anything else out there

  • Currently in development
  • Exposes certain channels such that they are web indexable
  • Will include features like Chat Glue and communal Digital Gardens

Created by Erlend Sogge Heggen, a ex-employee from Discourse

  • Maintains the Commune Blog with great write ups on the issues of the modern web, social media, etc. and how they can be improved (by Commune or related projects)
  • Also maintains a Personal Blog about similar topics

The Commune community is very interested in various topics and how they can relate together:

Related projects:

  • @laxla@tech.lgbt is creating Gimli, a federated discord alternative
    • Built on ActivityPub
    • "Guild-based" in ways matrix is not?
    • Will integrate with F3 as well
    • Wants to handle blogging as well
    • Certainly seems similar to Commune's message gardening concept
',10),b=JSON.parse('{"title":"Commune","description":"","frontmatter":{"public":"true","slug":"commune","title":"Commune","prev":false,"next":false},"headers":[],"relativePath":"garden/commune/index.md","filePath":"garden/commune/index.md"}'),u={name:"garden/commune/index.md"},y=Object.assign(u,{setup(c){const r=i();return(g,f)=>(d(),n("div",null,[o,e("p",null,[l("144 words, ~1 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,m)]),h]))}});export{b as __pageData,y as default}; diff --git a/assets/garden_commune_index.md.VBDo-SJ7.lean.js b/assets/garden_commune_index.md.V0TqobbD.lean.js similarity index 56% rename from assets/garden_commune_index.md.VBDo-SJ7.lean.js rename to assets/garden_commune_index.md.V0TqobbD.lean.js index 7c17d3fa..9a354d33 100644 --- a/assets/garden_commune_index.md.VBDo-SJ7.lean.js +++ b/assets/garden_commune_index.md.V0TqobbD.lean.js @@ -1 +1 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as i,c as n,j as e,a as l,k as a,ag as s,o as d}from"./chunks/framework.VBE0TPts.js";const o=e("h1",{class:"p-name"},"Commune",-1),m=["innerHTML"],h=s("",10),b=JSON.parse('{"title":"Commune","description":"","frontmatter":{"public":"true","slug":"commune","title":"Commune","prev":false,"next":false},"headers":[],"relativePath":"garden/commune/index.md","filePath":"garden/commune/index.md"}'),c={name:"garden/commune/index.md"},y=Object.assign(c,{setup(u){const r=i();return(g,f)=>(d(),n("div",null,[o,e("p",null,[l("144 words, ~1 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,m)]),h]))}});export{b as __pageData,y as default}; +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as n,Q as e,K as l,u as a,ag as s,p as d}from"./chunks/framework.DvHfxfnp.js";const o=e("h1",{class:"p-name"},"Commune",-1),m=["innerHTML"],h=s("",10),b=JSON.parse('{"title":"Commune","description":"","frontmatter":{"public":"true","slug":"commune","title":"Commune","prev":false,"next":false},"headers":[],"relativePath":"garden/commune/index.md","filePath":"garden/commune/index.md"}'),u={name:"garden/commune/index.md"},y=Object.assign(u,{setup(c){const r=i();return(g,f)=>(d(),n("div",null,[o,e("p",null,[l("144 words, ~1 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,m)]),h]))}});export{b as __pageData,y as default}; diff --git a/assets/garden_davey-wreden_index.md.Bxj_Btrg.js b/assets/garden_davey-wreden_index.md.0Vgk25Ik.js similarity index 86% rename from assets/garden_davey-wreden_index.md.Bxj_Btrg.js rename to assets/garden_davey-wreden_index.md.0Vgk25Ik.js index d83ae596..f27d14e0 100644 --- a/assets/garden_davey-wreden_index.md.Bxj_Btrg.js +++ b/assets/garden_davey-wreden_index.md.0Vgk25Ik.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as t,c as d,j as e,a as i,k as a,ag as s,o as l}from"./chunks/framework.VBE0TPts.js";const o=e("h1",{class:"p-name"},"Davey Wreden",-1),h=["innerHTML"],u=s('
Referenced by:Ivy RoadThe Beginner's Guide
Tagged by:Ivy RoadThe Beginner's GuideWanderstop

Projects:

Talks and Interviews:

',7),v=JSON.parse('{"title":"Davey Wreden","description":"","frontmatter":{"public":"true","slug":"davey-wreden","title":"Davey Wreden","prev":false,"next":false},"headers":[],"relativePath":"garden/davey-wreden/index.md","filePath":"garden/davey-wreden/index.md"}'),g={name:"garden/davey-wreden/index.md"},f=Object.assign(g,{setup(_){const r=t();return(c,m)=>(l(),d("div",null,[o,e("p",null,[i("37 words, ~0 minute read. "),e("span",{innerHTML:a(n)[`site/${a(r).page.value.relativePath}`]},null,8,h)]),u]))}});export{v as __pageData,f as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as t,q as d,Q as e,K as i,u as a,ag as s,p as l}from"./chunks/framework.DvHfxfnp.js";const o=e("h1",{class:"p-name"},"Davey Wreden",-1),h=["innerHTML"],u=s('
Referenced by:Ivy RoadThe Beginner's Guide
Tagged by:Ivy RoadThe Beginner's GuideWanderstop

Projects:

Talks and Interviews:

',7),v=JSON.parse('{"title":"Davey Wreden","description":"","frontmatter":{"public":"true","slug":"davey-wreden","title":"Davey Wreden","prev":false,"next":false},"headers":[],"relativePath":"garden/davey-wreden/index.md","filePath":"garden/davey-wreden/index.md"}'),g={name:"garden/davey-wreden/index.md"},f=Object.assign(g,{setup(_){const r=t();return(m,c)=>(l(),d("div",null,[o,e("p",null,[i("37 words, ~0 minute read. "),e("span",{innerHTML:a(n)[`site/${a(r).page.value.relativePath}`]},null,8,h)]),u]))}});export{v as __pageData,f as default}; diff --git a/assets/garden_davey-wreden_index.md.Bxj_Btrg.lean.js b/assets/garden_davey-wreden_index.md.0Vgk25Ik.lean.js similarity index 66% rename from assets/garden_davey-wreden_index.md.Bxj_Btrg.lean.js rename to assets/garden_davey-wreden_index.md.0Vgk25Ik.lean.js index d95e9a3b..0b82b160 100644 --- a/assets/garden_davey-wreden_index.md.Bxj_Btrg.lean.js +++ b/assets/garden_davey-wreden_index.md.0Vgk25Ik.lean.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as t,c as d,j as e,a as i,k as a,ag as s,o as l}from"./chunks/framework.VBE0TPts.js";const o=e("h1",{class:"p-name"},"Davey Wreden",-1),h=["innerHTML"],u=s("",7),v=JSON.parse('{"title":"Davey Wreden","description":"","frontmatter":{"public":"true","slug":"davey-wreden","title":"Davey Wreden","prev":false,"next":false},"headers":[],"relativePath":"garden/davey-wreden/index.md","filePath":"garden/davey-wreden/index.md"}'),g={name:"garden/davey-wreden/index.md"},f=Object.assign(g,{setup(_){const r=t();return(c,m)=>(l(),d("div",null,[o,e("p",null,[i("37 words, ~0 minute read. "),e("span",{innerHTML:a(n)[`site/${a(r).page.value.relativePath}`]},null,8,h)]),u]))}});export{v as __pageData,f as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as t,q as d,Q as e,K as i,u as a,ag as s,p as l}from"./chunks/framework.DvHfxfnp.js";const o=e("h1",{class:"p-name"},"Davey Wreden",-1),h=["innerHTML"],u=s("",7),v=JSON.parse('{"title":"Davey Wreden","description":"","frontmatter":{"public":"true","slug":"davey-wreden","title":"Davey Wreden","prev":false,"next":false},"headers":[],"relativePath":"garden/davey-wreden/index.md","filePath":"garden/davey-wreden/index.md"}'),g={name:"garden/davey-wreden/index.md"},f=Object.assign(g,{setup(_){const r=t();return(m,c)=>(l(),d("div",null,[o,e("p",null,[i("37 words, ~0 minute read. "),e("span",{innerHTML:a(n)[`site/${a(r).page.value.relativePath}`]},null,8,h)]),u]))}});export{v as __pageData,f as default}; diff --git a/assets/garden_decentralized_index.md.BThYPn4k.js b/assets/garden_decentralized_index.md.DYgiFscC.js similarity index 90% rename from assets/garden_decentralized_index.md.BThYPn4k.js rename to assets/garden_decentralized_index.md.DYgiFscC.js index 2ff95093..cd523b71 100644 --- a/assets/garden_decentralized_index.md.BThYPn4k.js +++ b/assets/garden_decentralized_index.md.DYgiFscC.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as i,c as n,j as e,a as d,k as a,ag as s,o as l}from"./chunks/framework.VBE0TPts.js";const o=e("h1",{class:"p-name"},"Decentralized",-1),c=["innerHTML"],m=s('
Referenced by:CommuneFedi v2MatrixSocial Media
Tagged by:ATProtoActivityPubFederated IdentityFediverseNostr

Something with no central source of authority

Common examples:

In practice, the "pick a server" problem causes email and the fediverse to trend towards a handful of large servers that still suffer from some of the issues of centralization

Advantages over centralization:

  • Data ownership
  • Increased privacy
  • No rules to follow
  • Can fully customize your experience
  • No single entity can make the experience worse for everyone
  • Anyone and everyone can try their hand at improving the ecosystem
',9),v=JSON.parse('{"title":"Decentralized","description":"","frontmatter":{"alias":"Federated","public":"true","slug":"decentralized","title":"Decentralized","prev":false,"next":false},"headers":[],"relativePath":"garden/decentralized/index.md","filePath":"garden/decentralized/index.md"}'),u={name:"garden/decentralized/index.md"},x=Object.assign(u,{setup(f){const t=i();return(p,h)=>(l(),n("div",null,[o,e("p",null,[d("80 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,c)]),m]))}});export{v as __pageData,x as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as n,Q as e,K as d,u as a,ag as s,p as l}from"./chunks/framework.DvHfxfnp.js";const o=e("h1",{class:"p-name"},"Decentralized",-1),c=["innerHTML"],m=s('
Referenced by:CommuneFedi v2MatrixSocial Media
Tagged by:ATProtoActivityPubFederated IdentityFediverseNostr

Something with no central source of authority

Common examples:

In practice, the "pick a server" problem causes email and the fediverse to trend towards a handful of large servers that still suffer from some of the issues of centralization

Advantages over centralization:

  • Data ownership
  • Increased privacy
  • No rules to follow
  • Can fully customize your experience
  • No single entity can make the experience worse for everyone
  • Anyone and everyone can try their hand at improving the ecosystem
',9),v=JSON.parse('{"title":"Decentralized","description":"","frontmatter":{"alias":"Federated","public":"true","slug":"decentralized","title":"Decentralized","prev":false,"next":false},"headers":[],"relativePath":"garden/decentralized/index.md","filePath":"garden/decentralized/index.md"}'),u={name:"garden/decentralized/index.md"},x=Object.assign(u,{setup(f){const t=i();return(p,h)=>(l(),n("div",null,[o,e("p",null,[d("80 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,c)]),m]))}});export{v as __pageData,x as default}; diff --git a/assets/garden_decentralized_index.md.BThYPn4k.lean.js b/assets/garden_decentralized_index.md.DYgiFscC.lean.js similarity index 75% rename from assets/garden_decentralized_index.md.BThYPn4k.lean.js rename to assets/garden_decentralized_index.md.DYgiFscC.lean.js index 6041b0b0..8238de41 100644 --- a/assets/garden_decentralized_index.md.BThYPn4k.lean.js +++ b/assets/garden_decentralized_index.md.DYgiFscC.lean.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as i,c as n,j as e,a as d,k as a,ag as s,o as l}from"./chunks/framework.VBE0TPts.js";const o=e("h1",{class:"p-name"},"Decentralized",-1),c=["innerHTML"],m=s("",9),v=JSON.parse('{"title":"Decentralized","description":"","frontmatter":{"alias":"Federated","public":"true","slug":"decentralized","title":"Decentralized","prev":false,"next":false},"headers":[],"relativePath":"garden/decentralized/index.md","filePath":"garden/decentralized/index.md"}'),u={name:"garden/decentralized/index.md"},x=Object.assign(u,{setup(f){const t=i();return(p,h)=>(l(),n("div",null,[o,e("p",null,[d("80 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,c)]),m]))}});export{v as __pageData,x as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as n,Q as e,K as d,u as a,ag as s,p as l}from"./chunks/framework.DvHfxfnp.js";const o=e("h1",{class:"p-name"},"Decentralized",-1),c=["innerHTML"],m=s("",9),v=JSON.parse('{"title":"Decentralized","description":"","frontmatter":{"alias":"Federated","public":"true","slug":"decentralized","title":"Decentralized","prev":false,"next":false},"headers":[],"relativePath":"garden/decentralized/index.md","filePath":"garden/decentralized/index.md"}'),u={name:"garden/decentralized/index.md"},x=Object.assign(u,{setup(f){const t=i();return(p,h)=>(l(),n("div",null,[o,e("p",null,[d("80 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,c)]),m]))}});export{v as __pageData,x as default}; diff --git a/assets/garden_dice-armor_index.md.CjnpEGDY.js b/assets/garden_dice-armor_index.md.BE5P-PMF.js similarity index 98% rename from assets/garden_dice-armor_index.md.CjnpEGDY.js rename to assets/garden_dice-armor_index.md.BE5P-PMF.js index 3ff73ad9..25b19614 100644 --- a/assets/garden_dice-armor_index.md.CjnpEGDY.js +++ b/assets/garden_dice-armor_index.md.BE5P-PMF.js @@ -1 +1 @@ -import{u as i,c as s,j as e,a as o,k as t,ag as n,o as r,ai as l,aj as d,ak as h,al as c,am as m,an as p,ao as u,ap as g,aq as f}from"./chunks/framework.VBE0TPts.js";import{d as y}from"./chunks/git.data.DG5NumsR.js";const b=e("h1",{class:"p-name"},"Dice Armor",-1),v=["innerHTML"],w=n('
Referenced by:Babble Buds
Tags:My Projects

Download it here

Dice Armor is a game that started development as a semester-long project by a team of nine: a producer, a creative director, a narrative writer, an artist, two programmers, and 3 game designers. The information here is about my contributions as the lead programmer over the semester because I can show off stuff like the editor scripts I wrote. I was doing everything from interface coding, editor scripts, integrating Babble Buds, and of course, everything related to the gameplay itself. To date I'm still the lead programmer for the game; for more up-to-date information on the current state of the game please visit the official site.

The build available here was created for showing off at the end of the semester, and as such has some buttons present to make the game easier to skip parts of the game to see all the content: You start with all the dice in the game already in the shop, there's a button to give yourself free money to buy these dice with, and in the duel, there are buttons to force a win or a loss, which can be used to skip the tutorial (not recommended for first-time players).

Dice Armor is a dice dueling game. Players can use abilities, flip dice, and attack each other to win in a dice game that puts chance into the hands of the players. This is what the dueling scene looks like, with a tutorial cutscene happening on top to guide the player through the basics. Also, all the dice are constructed dynamically, using quaternion math to figure out the placement of each component relative to the face it is going on. The die in the middle has one of the player' and opponents' portraits on each of its sides.

For many of the objects I've created, I've made scriptable objects so that game designers can add and modify them easily. Additionally, I would create custom inspectors for the objects to help make them as easy to understand and edit as possible. The opponent's artificial intelligence is made up of many strategies, in a prioritized list. When it is the opponents' turn they go through each strategy and check if they can be run, and if so then the opponent performs the strategy and starts back over at the top of the list of strategies. The + sign under the list of strategies opens an organized dropdown of all the various strategies.

In addition to custom inspector code, I've created new tools for the editor for our game designers to use. This is a duel simulator that will take two opponents and simulate an arbitrary number of duels between them, and output the results and summarize them for you, much much quicker than manually going through the duels, even with an absurdly high timeScale. This will become incredibly useful in making balance changes and testing new dice against existing sets. This is a screenshot of it in edit mode, but in play mode it removes the "Dueling Managers" field and will use whatever the current duel balance settings are, allowing for the GDs to test freely in play mode without worrying about undoing all their changes afterward.

I created the Babble Buds puppet editor and ported the rendering library I wrote for it to C# so it could be used in Unity. Dice Armor has a full campaign using cutscenes made using the Babble Buds cutscene editor, taking advantage of its support for custom commands and fields to control things like talking, giving the player dice and money, starting duels, and controlling player progression through the story.

When a cutscene ends, its final command is to either start a duel or set the next cutscene in the story. In the latter case, there is an additional field for what to call the next cutscene, and what location it takes place. The cutscene is then added to the player's save file, and when they visit the city locations are greyed out until they have at least one action to do there. Each location has a dynamically populated action wheel with a custom range of acceptable angles.

The dice shop is dynamically populated by a list of dice available to the player, which can be changed during cutscenes, and is checked against the dice owned by the player to generate sold-out indicators. On the left, the player can choose to filter the options down to a single dice effect, which also updates the "Buy All" button to buy only all the dice in the current filter.

The inventory works most the same as the shop, but for equipping dice. It also allows you to drag individual dice or entire sets to the equipped dice glyph. While dragging it will highlight all the slots the new dice will be equipped into.

The dice rolling uses the physics engine and detects once the dice have stopped moving, then determines which side is face up based on which of the normals is closest to straight up. It flags the die as cocked if that smallest angle is above a threshold. The dice sink into the table when not rolling to not interfere with any dice that are rolling.

During certain events like winning the game or having the face of a die broken, the players' portraits will flash an emotion for a second. After winning, a random living die from the winning player is chosen to play their "finisher move", a flashy and dramatic effect to end the game. Shown is the arcane mechana's finisher, "Missile Storm".

After development stopped, the project became Open Source - check it out here

',25),D=JSON.parse('{"title":"Dice Armor","description":"","frontmatter":{"public":"true","slug":"dice-armor","tags":["My Projects"],"title":"Dice Armor","prev":false,"next":false},"headers":[],"relativePath":"garden/dice-armor/index.md","filePath":"garden/dice-armor/index.md"}'),_={name:"garden/dice-armor/index.md"},B=Object.assign(_,{setup(k){const a=i();return(T,I)=>(r(),s("div",null,[b,e("p",null,[o("963 words, ~5 minute read. "),e("span",{innerHTML:t(y)[`site/${t(a).page.value.relativePath}`]},null,8,v)]),w]))}});export{D as __pageData,B as default}; +import{M as i,q as s,Q as e,K as o,u as t,ag as n,p as r,ai as l,aj as d,ak as h,al as c,am as m,an as p,ao as u,ap as g,aq as f}from"./chunks/framework.DvHfxfnp.js";import{d as y}from"./chunks/git.data.DG5NumsR.js";const b=e("h1",{class:"p-name"},"Dice Armor",-1),v=["innerHTML"],w=n('
Referenced by:Babble Buds
Tags:My Projects

Download it here

Dice Armor is a game that started development as a semester-long project by a team of nine: a producer, a creative director, a narrative writer, an artist, two programmers, and 3 game designers. The information here is about my contributions as the lead programmer over the semester because I can show off stuff like the editor scripts I wrote. I was doing everything from interface coding, editor scripts, integrating Babble Buds, and of course, everything related to the gameplay itself. To date I'm still the lead programmer for the game; for more up-to-date information on the current state of the game please visit the official site.

The build available here was created for showing off at the end of the semester, and as such has some buttons present to make the game easier to skip parts of the game to see all the content: You start with all the dice in the game already in the shop, there's a button to give yourself free money to buy these dice with, and in the duel, there are buttons to force a win or a loss, which can be used to skip the tutorial (not recommended for first-time players).

Dice Armor is a dice dueling game. Players can use abilities, flip dice, and attack each other to win in a dice game that puts chance into the hands of the players. This is what the dueling scene looks like, with a tutorial cutscene happening on top to guide the player through the basics. Also, all the dice are constructed dynamically, using quaternion math to figure out the placement of each component relative to the face it is going on. The die in the middle has one of the player' and opponents' portraits on each of its sides.

For many of the objects I've created, I've made scriptable objects so that game designers can add and modify them easily. Additionally, I would create custom inspectors for the objects to help make them as easy to understand and edit as possible. The opponent's artificial intelligence is made up of many strategies, in a prioritized list. When it is the opponents' turn they go through each strategy and check if they can be run, and if so then the opponent performs the strategy and starts back over at the top of the list of strategies. The + sign under the list of strategies opens an organized dropdown of all the various strategies.

In addition to custom inspector code, I've created new tools for the editor for our game designers to use. This is a duel simulator that will take two opponents and simulate an arbitrary number of duels between them, and output the results and summarize them for you, much much quicker than manually going through the duels, even with an absurdly high timeScale. This will become incredibly useful in making balance changes and testing new dice against existing sets. This is a screenshot of it in edit mode, but in play mode it removes the "Dueling Managers" field and will use whatever the current duel balance settings are, allowing for the GDs to test freely in play mode without worrying about undoing all their changes afterward.

I created the Babble Buds puppet editor and ported the rendering library I wrote for it to C# so it could be used in Unity. Dice Armor has a full campaign using cutscenes made using the Babble Buds cutscene editor, taking advantage of its support for custom commands and fields to control things like talking, giving the player dice and money, starting duels, and controlling player progression through the story.

When a cutscene ends, its final command is to either start a duel or set the next cutscene in the story. In the latter case, there is an additional field for what to call the next cutscene, and what location it takes place. The cutscene is then added to the player's save file, and when they visit the city locations are greyed out until they have at least one action to do there. Each location has a dynamically populated action wheel with a custom range of acceptable angles.

The dice shop is dynamically populated by a list of dice available to the player, which can be changed during cutscenes, and is checked against the dice owned by the player to generate sold-out indicators. On the left, the player can choose to filter the options down to a single dice effect, which also updates the "Buy All" button to buy only all the dice in the current filter.

The inventory works most the same as the shop, but for equipping dice. It also allows you to drag individual dice or entire sets to the equipped dice glyph. While dragging it will highlight all the slots the new dice will be equipped into.

The dice rolling uses the physics engine and detects once the dice have stopped moving, then determines which side is face up based on which of the normals is closest to straight up. It flags the die as cocked if that smallest angle is above a threshold. The dice sink into the table when not rolling to not interfere with any dice that are rolling.

During certain events like winning the game or having the face of a die broken, the players' portraits will flash an emotion for a second. After winning, a random living die from the winning player is chosen to play their "finisher move", a flashy and dramatic effect to end the game. Shown is the arcane mechana's finisher, "Missile Storm".

After development stopped, the project became Open Source - check it out here

',25),D=JSON.parse('{"title":"Dice Armor","description":"","frontmatter":{"public":"true","slug":"dice-armor","tags":["My Projects"],"title":"Dice Armor","prev":false,"next":false},"headers":[],"relativePath":"garden/dice-armor/index.md","filePath":"garden/dice-armor/index.md"}'),_={name:"garden/dice-armor/index.md"},B=Object.assign(_,{setup(k){const a=i();return(T,I)=>(r(),s("div",null,[b,e("p",null,[o("963 words, ~5 minute read. "),e("span",{innerHTML:t(y)[`site/${t(a).page.value.relativePath}`]},null,8,v)]),w]))}});export{D as __pageData,B as default}; diff --git a/assets/garden_dice-armor_index.md.CjnpEGDY.lean.js b/assets/garden_dice-armor_index.md.BE5P-PMF.lean.js similarity index 84% rename from assets/garden_dice-armor_index.md.CjnpEGDY.lean.js rename to assets/garden_dice-armor_index.md.BE5P-PMF.lean.js index 350fab09..52595e89 100644 --- a/assets/garden_dice-armor_index.md.CjnpEGDY.lean.js +++ b/assets/garden_dice-armor_index.md.BE5P-PMF.lean.js @@ -1 +1 @@ -import{u as i,c as s,j as e,a as o,k as t,ag as n,o as r,ai as l,aj as d,ak as h,al as c,am as m,an as p,ao as u,ap as g,aq as f}from"./chunks/framework.VBE0TPts.js";import{d as y}from"./chunks/git.data.DG5NumsR.js";const b=e("h1",{class:"p-name"},"Dice Armor",-1),v=["innerHTML"],w=n("",25),D=JSON.parse('{"title":"Dice Armor","description":"","frontmatter":{"public":"true","slug":"dice-armor","tags":["My Projects"],"title":"Dice Armor","prev":false,"next":false},"headers":[],"relativePath":"garden/dice-armor/index.md","filePath":"garden/dice-armor/index.md"}'),_={name:"garden/dice-armor/index.md"},B=Object.assign(_,{setup(k){const a=i();return(T,I)=>(r(),s("div",null,[b,e("p",null,[o("963 words, ~5 minute read. "),e("span",{innerHTML:t(y)[`site/${t(a).page.value.relativePath}`]},null,8,v)]),w]))}});export{D as __pageData,B as default}; +import{M as i,q as s,Q as e,K as o,u as t,ag as n,p as r,ai as l,aj as d,ak as h,al as c,am as m,an as p,ao as u,ap as g,aq as f}from"./chunks/framework.DvHfxfnp.js";import{d as y}from"./chunks/git.data.DG5NumsR.js";const b=e("h1",{class:"p-name"},"Dice Armor",-1),v=["innerHTML"],w=n("",25),D=JSON.parse('{"title":"Dice Armor","description":"","frontmatter":{"public":"true","slug":"dice-armor","tags":["My Projects"],"title":"Dice Armor","prev":false,"next":false},"headers":[],"relativePath":"garden/dice-armor/index.md","filePath":"garden/dice-armor/index.md"}'),_={name:"garden/dice-armor/index.md"},B=Object.assign(_,{setup(k){const a=i();return(T,I)=>(r(),s("div",null,[b,e("p",null,[o("963 words, ~5 minute read. "),e("span",{innerHTML:t(y)[`site/${t(a).page.value.relativePath}`]},null,8,v)]),w]))}});export{D as __pageData,B as default}; diff --git a/assets/garden_digital-gardens_index.md.BTOMV_DV.js b/assets/garden_digital-gardens_index.md.BTOMV_DV.js deleted file mode 100644 index 1358051f..00000000 --- a/assets/garden_digital-gardens_index.md.BTOMV_DV.js +++ /dev/null @@ -1 +0,0 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as i,j as e,a as d,k as a,ag as l,o}from"./chunks/framework.VBE0TPts.js";const s=e("h1",{class:"p-name"},"Digital Gardens",-1),g=["innerHTML"],h=l('
Referenced by:ChronologicalCommuneGarden-RSSThe Cozy WebThe Small WebThis Knowledge Hub

Digital Gardens are Freeform collections of information made by an individual or community

This Knowledge Hub is a digital garden

Collections of digital gardens and resources for creating them:

',7),b=JSON.parse('{"title":"Digital Gardens","description":"","frontmatter":{"alias":"Digital Garden, Second Brain, Personal Knowledge Management, The Zettelkasten Method","public":"true","slug":"digital-gardens","title":"Digital Gardens","prev":false,"next":false},"headers":[],"relativePath":"garden/digital-gardens/index.md","filePath":"garden/digital-gardens/index.md"}'),c={name:"garden/digital-gardens/index.md"},T=Object.assign(c,{setup(m){const r=n();return(u,f)=>(o(),i("div",null,[s,e("p",null,[d("67 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,g)]),h]))}});export{b as __pageData,T as default}; diff --git a/assets/garden_digital-gardens_index.md.BTOMV_DV.lean.js b/assets/garden_digital-gardens_index.md.BTOMV_DV.lean.js deleted file mode 100644 index f99267c7..00000000 --- a/assets/garden_digital-gardens_index.md.BTOMV_DV.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as i,j as e,a as d,k as a,ag as l,o}from"./chunks/framework.VBE0TPts.js";const s=e("h1",{class:"p-name"},"Digital Gardens",-1),g=["innerHTML"],h=l("",7),b=JSON.parse('{"title":"Digital Gardens","description":"","frontmatter":{"alias":"Digital Garden, Second Brain, Personal Knowledge Management, The Zettelkasten Method","public":"true","slug":"digital-gardens","title":"Digital Gardens","prev":false,"next":false},"headers":[],"relativePath":"garden/digital-gardens/index.md","filePath":"garden/digital-gardens/index.md"}'),c={name:"garden/digital-gardens/index.md"},T=Object.assign(c,{setup(m){const r=n();return(u,f)=>(o(),i("div",null,[s,e("p",null,[d("67 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,g)]),h]))}});export{b as __pageData,T as default}; diff --git a/assets/garden_digital-gardens_index.md.CWPuJsJg.js b/assets/garden_digital-gardens_index.md.CWPuJsJg.js new file mode 100644 index 00000000..37093152 --- /dev/null +++ b/assets/garden_digital-gardens_index.md.CWPuJsJg.js @@ -0,0 +1 @@ +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as i,Q as e,K as d,u as a,ag as l,p as o}from"./chunks/framework.DvHfxfnp.js";const s=e("h1",{class:"p-name"},"Digital Gardens",-1),g=["innerHTML"],h=l('
Referenced by:ChronologicalCommuneGarden-RSSThe Cozy WebThe Small WebThis Knowledge Hub

Digital Gardens are Freeform collections of information made by an individual or community

This Knowledge Hub is a digital garden

Collections of digital gardens and resources for creating them:

',7),b=JSON.parse('{"title":"Digital Gardens","description":"","frontmatter":{"alias":"Digital Garden, Second Brain, Personal Knowledge Management, The Zettelkasten Method","public":"true","slug":"digital-gardens","title":"Digital Gardens","prev":false,"next":false},"headers":[],"relativePath":"garden/digital-gardens/index.md","filePath":"garden/digital-gardens/index.md"}'),c={name:"garden/digital-gardens/index.md"},T=Object.assign(c,{setup(m){const r=n();return(u,f)=>(o(),i("div",null,[s,e("p",null,[d("67 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,g)]),h]))}});export{b as __pageData,T as default}; diff --git a/assets/garden_digital-gardens_index.md.CWPuJsJg.lean.js b/assets/garden_digital-gardens_index.md.CWPuJsJg.lean.js new file mode 100644 index 00000000..46536672 --- /dev/null +++ b/assets/garden_digital-gardens_index.md.CWPuJsJg.lean.js @@ -0,0 +1 @@ +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as i,Q as e,K as d,u as a,ag as l,p as o}from"./chunks/framework.DvHfxfnp.js";const s=e("h1",{class:"p-name"},"Digital Gardens",-1),g=["innerHTML"],h=l("",7),b=JSON.parse('{"title":"Digital Gardens","description":"","frontmatter":{"alias":"Digital Garden, Second Brain, Personal Knowledge Management, The Zettelkasten Method","public":"true","slug":"digital-gardens","title":"Digital Gardens","prev":false,"next":false},"headers":[],"relativePath":"garden/digital-gardens/index.md","filePath":"garden/digital-gardens/index.md"}'),c={name:"garden/digital-gardens/index.md"},T=Object.assign(c,{setup(m){const r=n();return(u,f)=>(o(),i("div",null,[s,e("p",null,[d("67 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,g)]),h]))}});export{b as __pageData,T as default}; diff --git a/assets/garden_federated-identity_index.md.Czr5VTIi.js b/assets/garden_federated-identity_index.md.-RBu4BIs.js similarity index 84% rename from assets/garden_federated-identity_index.md.Czr5VTIi.js rename to assets/garden_federated-identity_index.md.-RBu4BIs.js index f76886fd..07782917 100644 --- a/assets/garden_federated-identity_index.md.Czr5VTIi.js +++ b/assets/garden_federated-identity_index.md.-RBu4BIs.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as d,c as i,j as e,a as n,k as a,ag as l,o as s}from"./chunks/framework.VBE0TPts.js";const o=e("h1",{class:"p-name"},"Federated Identity",-1),c=["innerHTML"],u=l('
Referenced by:CommuneFedi v2Weird
Tags:Decentralized

Allow for validating one's identity without relying on a specific centralized server

Implementations:

Self hosted identity providers are NOT enough to be considered federated identity

  • OIDC and OAuth require the service owner to have pre-configured with explicitly allowed identity providers

Incremental Social uses Zitadel which does NOT support IndieAuth and probably won't

',9),y=JSON.parse('{"title":"Federated Identity","description":"","frontmatter":{"alias":"Decentralized Identity","public":"true","slug":"federated-identity","tags":["Decentralized"],"title":"Federated Identity","prev":false,"next":false},"headers":[],"relativePath":"garden/federated-identity/index.md","filePath":"garden/federated-identity/index.md"}'),h={name:"garden/federated-identity/index.md"},b=Object.assign(h,{setup(m){const t=d();return(p,f)=>(s(),i("div",null,[o,e("p",null,[n("68 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,c)]),u]))}});export{y as __pageData,b as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as d,q as i,Q as e,K as n,u as a,ag as l,p as s}from"./chunks/framework.DvHfxfnp.js";const o=e("h1",{class:"p-name"},"Federated Identity",-1),u=["innerHTML"],c=l('
Referenced by:CommuneFedi v2Weird
Tags:Decentralized

Allow for validating one's identity without relying on a specific centralized server

Implementations:

Self hosted identity providers are NOT enough to be considered federated identity

  • OIDC and OAuth require the service owner to have pre-configured with explicitly allowed identity providers

Incremental Social uses Zitadel which does NOT support IndieAuth and probably won't

',9),y=JSON.parse('{"title":"Federated Identity","description":"","frontmatter":{"alias":"Decentralized Identity","public":"true","slug":"federated-identity","tags":["Decentralized"],"title":"Federated Identity","prev":false,"next":false},"headers":[],"relativePath":"garden/federated-identity/index.md","filePath":"garden/federated-identity/index.md"}'),h={name:"garden/federated-identity/index.md"},b=Object.assign(h,{setup(m){const t=d();return(p,f)=>(s(),i("div",null,[o,e("p",null,[n("68 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,u)]),c]))}});export{y as __pageData,b as default}; diff --git a/assets/garden_federated-identity_index.md.Czr5VTIi.lean.js b/assets/garden_federated-identity_index.md.-RBu4BIs.lean.js similarity index 63% rename from assets/garden_federated-identity_index.md.Czr5VTIi.lean.js rename to assets/garden_federated-identity_index.md.-RBu4BIs.lean.js index ad8f9882..8211666c 100644 --- a/assets/garden_federated-identity_index.md.Czr5VTIi.lean.js +++ b/assets/garden_federated-identity_index.md.-RBu4BIs.lean.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as d,c as i,j as e,a as n,k as a,ag as l,o as s}from"./chunks/framework.VBE0TPts.js";const o=e("h1",{class:"p-name"},"Federated Identity",-1),c=["innerHTML"],u=l("",9),y=JSON.parse('{"title":"Federated Identity","description":"","frontmatter":{"alias":"Decentralized Identity","public":"true","slug":"federated-identity","tags":["Decentralized"],"title":"Federated Identity","prev":false,"next":false},"headers":[],"relativePath":"garden/federated-identity/index.md","filePath":"garden/federated-identity/index.md"}'),h={name:"garden/federated-identity/index.md"},b=Object.assign(h,{setup(m){const t=d();return(p,f)=>(s(),i("div",null,[o,e("p",null,[n("68 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,c)]),u]))}});export{y as __pageData,b as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as d,q as i,Q as e,K as n,u as a,ag as l,p as s}from"./chunks/framework.DvHfxfnp.js";const o=e("h1",{class:"p-name"},"Federated Identity",-1),u=["innerHTML"],c=l("",9),y=JSON.parse('{"title":"Federated Identity","description":"","frontmatter":{"alias":"Decentralized Identity","public":"true","slug":"federated-identity","tags":["Decentralized"],"title":"Federated Identity","prev":false,"next":false},"headers":[],"relativePath":"garden/federated-identity/index.md","filePath":"garden/federated-identity/index.md"}'),h={name:"garden/federated-identity/index.md"},b=Object.assign(h,{setup(m){const t=d();return(p,f)=>(s(),i("div",null,[o,e("p",null,[n("68 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,u)]),c]))}});export{y as __pageData,b as default}; diff --git a/assets/garden_fedi-v2_index.md.BJxh2Je6.js b/assets/garden_fedi-v2_index.md.BPYmNsKX.js similarity index 98% rename from assets/garden_fedi-v2_index.md.BJxh2Je6.js rename to assets/garden_fedi-v2_index.md.BPYmNsKX.js index 04e1e493..d94244f4 100644 --- a/assets/garden_fedi-v2_index.md.BJxh2Je6.js +++ b/assets/garden_fedi-v2_index.md.BPYmNsKX.js @@ -1 +1 @@ -import{d as o}from"./chunks/git.data.DG5NumsR.js";import{u as i,c as s,j as e,a as r,k as t,ag as n,o as h}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"Fedi v2",-1),d=["innerHTML"],c=n('
Referenced by:Social MediaThe IndieWeb/Signature BlocksWeird

A placeholder name for a theoretical new federated network that is client-centric, in contrast to the server-centric Fediverse. Many of the ideas here will be implemented as described or similarly by people much smarter than me as part of Agentic Federation on Iroh, an initiative by the Weird developers.

Motivation

The current fediverse, while in theory fully Decentralized, in practice suffers many of the issues associated with centralization. This is primarily caused by the friction of having to pick a server and the non feasibility of individuals buying a domain and setting up a single user instance - both the causes lead to a handful of large servers with the bulk of the users. You can see this in action by looking up the relative sizes of lemmy and mastodon instances. Single-user Mastodon Instance is a Bad Idea goes over the non feasibility of self hosting and how it contributes to a handful of servers having the majority of the users.

The promise of federation is the ability to interact with the whole network, while being able to fully choose and customize how you yourself interact with the network. In practice though, clients are severely limited to what they can do based on the server software. Of particular note, Lemmy and Mastodon show content in different formats (threads vs microblogs), and no clients allow changing how they're displayed, or respecting the format of the source of the content. Clients also are unable to change sorting algorithms or how downvotes are handled - those are all dependent on the server. A Plan for Social Media - Rethinking Federation similarly criticizes how much of the decisions are dependent on the server, which most people won't be able to or willing to self host.

The pick a server problem is such a problem because not only do you have to pick what server has moderation policies you align with, but that you're also linking your identity with that server. Smaller servers tend to be more focused or niche, which is unlikely to fully encompass any person's entire identity. Why would I confine myself to being thepaperpilot@writinglovers.com if I'm more than a writing lover? Additionally, I'm risking that the community at that instance won't grow away from things I want to associate with, such as fascism or crypto. My identity could end up being associated with things I drastically don't want it to be.

Nostr fixes the pick a server problem with a properly decentralized identity, however it's done so by associating itself with crypto and the alt right, and fixing that culture problem is more effort than it's worth. It'll be difficult to gain broad adoption as anyone using the platform will have to take care to explain how they're using nostr but aren't alt right.

ATProto by bluesky offers a version of federation built for a handful of large instances, but allowing smaller servers to be spun up that can implement custom sorting algorithms, views, etc. This fixes a couple of the problems where you're unable to change certain things dictated by the servers, but doesn't quite go far enough - and of particular note, you still have to associate your identity with a specific server.

Identity

The new fediverse should have a fully Decentralized Identity, where it's completely attached to the client rather than any server(s). This means you don't have to pick a server, worry about your chosen server going down, or that yout identity will become associated with an undesired community. It can properly allow you to engage in your variety of interests without having to associate any as core enough to attach your identity to.

This identity can be accomplished by the client merely generating a private and public key, which can then be stored however the user pleases. Reasonably, there's be default options to back up the private key to Google drive or alternatives, as most users will not desire to go the extra effort of backing up their identity without relying on big storage websites. But for those who wish, you could keep the identity solely on the device, or choose your own method of storage and backup.

The client can sign messages using the private key and distribute it through whatever means they wish, and it can be verified as sent by that identity using the public key to decode the message. In this context, messages could also refer to any other signed information, such as a bundle of profile information.

For casual conversation, a nickname in the profile data should be sufficient. Once a client interacts with someone, they can be added as a contact as a way of verifying the next conversation with someone with that username is actually the same person as before. For situations where you want to verify an identity actually has a credentials they claim, you can query a nameserver that vouches for them. For example, whitehouse.gov would have a nameserver that specifies which identity is the actual president of the United States (and other government officials). There could be nameservers that allow you to openly "register" your identity with them to get a unique human readable username you can include on billboards or other visual media where you want someone to be able to memorize the identifier, rather than scan a QR code or something. For more details on how these decentralized usernames would work, check out Petnames.

Through cryptography, you can be confident messages are verifiably sent by someone with access to the private key, and that the message was not tampered with. These are guarantees you can't make with the current server centric fediverse.

If you lose access to your account, it's gone forever. That is why I think there should be defaults to backup your private key to existing reliable servers, even if they're owned by large corporations. Otherwise I would see someone have their phone stolen, lost, or upgraded and be surprised when their account is now inaccessible.

If you do lose your account and create a new identity, you could have others "vouch" for the new identity being an alias for the previous identity. You could verify your new identity with people IRL, and then other clients can see those vouches publicly and, after sufficient quantity, just implicitly assume they're the same (although with some sort of indicator, so if this gets abused, users are at least aware of the possibility of impersonation.

Servers

Servers would act as mere relays, whose job it is is to store messages and send them to any other clients or servers that have requested to hear about any new messages. Some relays may also display these messages in a web interface, so that you can still share links to messages online. Because your identity isn't attached to any specific server, you could send your messages out to any servers you wish, and change that list as often as you'd like. It's extremely resilient to individual servers going down.

If you want a private network, say for a school or job, you could setup a relay server that requires some sort of password when sending them messages, and then have that server not federate with the rest of the fediverse.

Servers would give clients ways to subscribe to subsets of all received messages - e.g. all messages, all messages from a specific user, any replies to messages from a specific user, or "shallow" subscriptions to a message, meaning it'll send you only 1 level of replies to that message.

Content

The protocol should be fairly content agnostic, and allow arbitrary metadata on messages that can be used by the community to come up with their own new forms of content to transmit over the protocol. For example, perhaps there's a body field that could include arbitrary text or binary data, and for binary data another field could clarify if its audio, video, an image, or something else.

The signature of the message acts as the de facto ID of that message, for replying purposes. Edits and reactions would be handled by "replying" to a message with a metadata flag indicating what the message actually represents. Edit messages should typically be ignored if they're not from the same author as the original message. We should assume some servers will always make an edit history fully public. Reactions should just be replies without any actual body, and a tag for what the reaction is - either binary image data or a code representing an emoji, like "+1" or "laughing". Upvotes and downvotes could be implemented via reactions.

Groups/communities could also be specially flagged messages, effectively allowing for subreddit-style content. Posting to the community is just replying to the message. Subscribing to that community is just subscribing to that message. The original message creator can send edits to update stuff like the description of the community. Perhaps they can also send a message detailing other identities to trust for editing or moderating the community.

A bot could fairly easily be setup to make IndieWeb posts and web mentions use this protocol. Indeed, this protocol is very POSSE-friendly because you could have your original content on the website, and the messages can be spread across the network while allowing clients to verify it was untampered with and definitely came from that website. I plan on writing a proposal for IndieWeb posts to include The IndieWeb/Signature Blocks to enable this. Within this framework, Fedi v2 would not just be a other social media silo. It would be the source of truth, fully controlled by the author. Even if the author cross posts to other social media (silos), we'd effectively still be the original copy.

Moderation

Anyone can send edit and delete requests as replies to messages, but they'll typically be ignored since they'd be coming from a different identity. However, you could have clients or even servers honor those requests based on various heuristics - deleting anything that's gotten X delete requests, or trust specific identities to act as moderators. Since individual clients could choose which identities to honor, the moderation is effectively fully decentralized. Clients will probably have a couple identities trusted by default, to check for illegal content or that would otherwise prevent the app from breaking the app store's TOS.

Anyone can spin up their own bots that just automatically send out delete requests based on custom logic, like checking for images that match the CSAM hash list, or messages that ChatGPT says are non-constructive. Through this, the ecosystem will over time allow people to further customize their experience by filtering out unwanted content more and more precisely.

Success

I believe the main benefits of this new fediverse are mostly going to apply to the techy power users who will appreciate the increased control over their identity and browsing experience. As far as the general public goes, I think the main benefit will be verified authorship and guaranteeing lack of tampering. Specifically, I think this will appeal to notable figures who have to be wary of concerns like that. Reddit and Twitter could edit your content or stifle it in the algorithm, or any other sort of malicious actions. So I think success of this platform will mostly come from seeing notable figures switching to it, and treating is as the source of truth (even if they cross post it to other platforms for increased outreach). Ideally, they even host their messages on their own website.

',31),b=JSON.parse('{"title":"Fedi v2","description":"","frontmatter":{"public":"true","slug":"fedi-v2","title":"Fedi v2","prev":false,"next":false},"headers":[],"relativePath":"garden/fedi-v2/index.md","filePath":"garden/fedi-v2/index.md"}'),u={name:"garden/fedi-v2/index.md"},w=Object.assign(u,{setup(m){const a=i();return(y,f)=>(h(),s("div",null,[l,e("p",null,[r("1835 words, ~10 minute read. "),e("span",{innerHTML:t(o)[`site/${t(a).page.value.relativePath}`]},null,8,d)]),c]))}});export{b as __pageData,w as default}; +import{d as o}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as s,Q as e,K as r,u as t,ag as n,p as h}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"Fedi v2",-1),d=["innerHTML"],c=n('
Referenced by:Social MediaThe IndieWeb/Signature BlocksWeird

A placeholder name for a theoretical new federated network that is client-centric, in contrast to the server-centric Fediverse. Many of the ideas here will be implemented as described or similarly by people much smarter than me as part of Agentic Federation on Iroh, an initiative by the Weird developers.

Motivation

The current fediverse, while in theory fully Decentralized, in practice suffers many of the issues associated with centralization. This is primarily caused by the friction of having to pick a server and the non feasibility of individuals buying a domain and setting up a single user instance - both the causes lead to a handful of large servers with the bulk of the users. You can see this in action by looking up the relative sizes of lemmy and mastodon instances. Single-user Mastodon Instance is a Bad Idea goes over the non feasibility of self hosting and how it contributes to a handful of servers having the majority of the users.

The promise of federation is the ability to interact with the whole network, while being able to fully choose and customize how you yourself interact with the network. In practice though, clients are severely limited to what they can do based on the server software. Of particular note, Lemmy and Mastodon show content in different formats (threads vs microblogs), and no clients allow changing how they're displayed, or respecting the format of the source of the content. Clients also are unable to change sorting algorithms or how downvotes are handled - those are all dependent on the server. A Plan for Social Media - Rethinking Federation similarly criticizes how much of the decisions are dependent on the server, which most people won't be able to or willing to self host.

The pick a server problem is such a problem because not only do you have to pick what server has moderation policies you align with, but that you're also linking your identity with that server. Smaller servers tend to be more focused or niche, which is unlikely to fully encompass any person's entire identity. Why would I confine myself to being thepaperpilot@writinglovers.com if I'm more than a writing lover? Additionally, I'm risking that the community at that instance won't grow away from things I want to associate with, such as fascism or crypto. My identity could end up being associated with things I drastically don't want it to be.

Nostr fixes the pick a server problem with a properly decentralized identity, however it's done so by associating itself with crypto and the alt right, and fixing that culture problem is more effort than it's worth. It'll be difficult to gain broad adoption as anyone using the platform will have to take care to explain how they're using nostr but aren't alt right.

ATProto by bluesky offers a version of federation built for a handful of large instances, but allowing smaller servers to be spun up that can implement custom sorting algorithms, views, etc. This fixes a couple of the problems where you're unable to change certain things dictated by the servers, but doesn't quite go far enough - and of particular note, you still have to associate your identity with a specific server.

Identity

The new fediverse should have a fully Decentralized Identity, where it's completely attached to the client rather than any server(s). This means you don't have to pick a server, worry about your chosen server going down, or that yout identity will become associated with an undesired community. It can properly allow you to engage in your variety of interests without having to associate any as core enough to attach your identity to.

This identity can be accomplished by the client merely generating a private and public key, which can then be stored however the user pleases. Reasonably, there's be default options to back up the private key to Google drive or alternatives, as most users will not desire to go the extra effort of backing up their identity without relying on big storage websites. But for those who wish, you could keep the identity solely on the device, or choose your own method of storage and backup.

The client can sign messages using the private key and distribute it through whatever means they wish, and it can be verified as sent by that identity using the public key to decode the message. In this context, messages could also refer to any other signed information, such as a bundle of profile information.

For casual conversation, a nickname in the profile data should be sufficient. Once a client interacts with someone, they can be added as a contact as a way of verifying the next conversation with someone with that username is actually the same person as before. For situations where you want to verify an identity actually has a credentials they claim, you can query a nameserver that vouches for them. For example, whitehouse.gov would have a nameserver that specifies which identity is the actual president of the United States (and other government officials). There could be nameservers that allow you to openly "register" your identity with them to get a unique human readable username you can include on billboards or other visual media where you want someone to be able to memorize the identifier, rather than scan a QR code or something. For more details on how these decentralized usernames would work, check out Petnames.

Through cryptography, you can be confident messages are verifiably sent by someone with access to the private key, and that the message was not tampered with. These are guarantees you can't make with the current server centric fediverse.

If you lose access to your account, it's gone forever. That is why I think there should be defaults to backup your private key to existing reliable servers, even if they're owned by large corporations. Otherwise I would see someone have their phone stolen, lost, or upgraded and be surprised when their account is now inaccessible.

If you do lose your account and create a new identity, you could have others "vouch" for the new identity being an alias for the previous identity. You could verify your new identity with people IRL, and then other clients can see those vouches publicly and, after sufficient quantity, just implicitly assume they're the same (although with some sort of indicator, so if this gets abused, users are at least aware of the possibility of impersonation.

Servers

Servers would act as mere relays, whose job it is is to store messages and send them to any other clients or servers that have requested to hear about any new messages. Some relays may also display these messages in a web interface, so that you can still share links to messages online. Because your identity isn't attached to any specific server, you could send your messages out to any servers you wish, and change that list as often as you'd like. It's extremely resilient to individual servers going down.

If you want a private network, say for a school or job, you could setup a relay server that requires some sort of password when sending them messages, and then have that server not federate with the rest of the fediverse.

Servers would give clients ways to subscribe to subsets of all received messages - e.g. all messages, all messages from a specific user, any replies to messages from a specific user, or "shallow" subscriptions to a message, meaning it'll send you only 1 level of replies to that message.

Content

The protocol should be fairly content agnostic, and allow arbitrary metadata on messages that can be used by the community to come up with their own new forms of content to transmit over the protocol. For example, perhaps there's a body field that could include arbitrary text or binary data, and for binary data another field could clarify if its audio, video, an image, or something else.

The signature of the message acts as the de facto ID of that message, for replying purposes. Edits and reactions would be handled by "replying" to a message with a metadata flag indicating what the message actually represents. Edit messages should typically be ignored if they're not from the same author as the original message. We should assume some servers will always make an edit history fully public. Reactions should just be replies without any actual body, and a tag for what the reaction is - either binary image data or a code representing an emoji, like "+1" or "laughing". Upvotes and downvotes could be implemented via reactions.

Groups/communities could also be specially flagged messages, effectively allowing for subreddit-style content. Posting to the community is just replying to the message. Subscribing to that community is just subscribing to that message. The original message creator can send edits to update stuff like the description of the community. Perhaps they can also send a message detailing other identities to trust for editing or moderating the community.

A bot could fairly easily be setup to make IndieWeb posts and web mentions use this protocol. Indeed, this protocol is very POSSE-friendly because you could have your original content on the website, and the messages can be spread across the network while allowing clients to verify it was untampered with and definitely came from that website. I plan on writing a proposal for IndieWeb posts to include The IndieWeb/Signature Blocks to enable this. Within this framework, Fedi v2 would not just be a other social media silo. It would be the source of truth, fully controlled by the author. Even if the author cross posts to other social media (silos), we'd effectively still be the original copy.

Moderation

Anyone can send edit and delete requests as replies to messages, but they'll typically be ignored since they'd be coming from a different identity. However, you could have clients or even servers honor those requests based on various heuristics - deleting anything that's gotten X delete requests, or trust specific identities to act as moderators. Since individual clients could choose which identities to honor, the moderation is effectively fully decentralized. Clients will probably have a couple identities trusted by default, to check for illegal content or that would otherwise prevent the app from breaking the app store's TOS.

Anyone can spin up their own bots that just automatically send out delete requests based on custom logic, like checking for images that match the CSAM hash list, or messages that ChatGPT says are non-constructive. Through this, the ecosystem will over time allow people to further customize their experience by filtering out unwanted content more and more precisely.

Success

I believe the main benefits of this new fediverse are mostly going to apply to the techy power users who will appreciate the increased control over their identity and browsing experience. As far as the general public goes, I think the main benefit will be verified authorship and guaranteeing lack of tampering. Specifically, I think this will appeal to notable figures who have to be wary of concerns like that. Reddit and Twitter could edit your content or stifle it in the algorithm, or any other sort of malicious actions. So I think success of this platform will mostly come from seeing notable figures switching to it, and treating is as the source of truth (even if they cross post it to other platforms for increased outreach). Ideally, they even host their messages on their own website.

',31),b=JSON.parse('{"title":"Fedi v2","description":"","frontmatter":{"public":"true","slug":"fedi-v2","title":"Fedi v2","prev":false,"next":false},"headers":[],"relativePath":"garden/fedi-v2/index.md","filePath":"garden/fedi-v2/index.md"}'),u={name:"garden/fedi-v2/index.md"},w=Object.assign(u,{setup(m){const a=i();return(y,f)=>(h(),s("div",null,[l,e("p",null,[r("1835 words, ~10 minute read. "),e("span",{innerHTML:t(o)[`site/${t(a).page.value.relativePath}`]},null,8,d)]),c]))}});export{b as __pageData,w as default}; diff --git a/assets/garden_fedi-v2_index.md.BJxh2Je6.lean.js b/assets/garden_fedi-v2_index.md.BPYmNsKX.lean.js similarity index 73% rename from assets/garden_fedi-v2_index.md.BJxh2Je6.lean.js rename to assets/garden_fedi-v2_index.md.BPYmNsKX.lean.js index 9a9e12d5..9f544ebb 100644 --- a/assets/garden_fedi-v2_index.md.BJxh2Je6.lean.js +++ b/assets/garden_fedi-v2_index.md.BPYmNsKX.lean.js @@ -1 +1 @@ -import{d as o}from"./chunks/git.data.DG5NumsR.js";import{u as i,c as s,j as e,a as r,k as t,ag as n,o as h}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"Fedi v2",-1),d=["innerHTML"],c=n("",31),b=JSON.parse('{"title":"Fedi v2","description":"","frontmatter":{"public":"true","slug":"fedi-v2","title":"Fedi v2","prev":false,"next":false},"headers":[],"relativePath":"garden/fedi-v2/index.md","filePath":"garden/fedi-v2/index.md"}'),u={name:"garden/fedi-v2/index.md"},w=Object.assign(u,{setup(m){const a=i();return(y,f)=>(h(),s("div",null,[l,e("p",null,[r("1835 words, ~10 minute read. "),e("span",{innerHTML:t(o)[`site/${t(a).page.value.relativePath}`]},null,8,d)]),c]))}});export{b as __pageData,w as default}; +import{d as o}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as s,Q as e,K as r,u as t,ag as n,p as h}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"Fedi v2",-1),d=["innerHTML"],c=n("",31),b=JSON.parse('{"title":"Fedi v2","description":"","frontmatter":{"public":"true","slug":"fedi-v2","title":"Fedi v2","prev":false,"next":false},"headers":[],"relativePath":"garden/fedi-v2/index.md","filePath":"garden/fedi-v2/index.md"}'),u={name:"garden/fedi-v2/index.md"},w=Object.assign(u,{setup(m){const a=i();return(y,f)=>(h(),s("div",null,[l,e("p",null,[r("1835 words, ~10 minute read. "),e("span",{innerHTML:t(o)[`site/${t(a).page.value.relativePath}`]},null,8,d)]),c]))}});export{b as __pageData,w as default}; diff --git a/assets/garden_fediverse_index.md.BoF29t1o.js b/assets/garden_fediverse_index.md.CexXroKb.js similarity index 86% rename from assets/garden_fediverse_index.md.BoF29t1o.js rename to assets/garden_fediverse_index.md.CexXroKb.js index 610406db..ac4269d9 100644 --- a/assets/garden_fediverse_index.md.BoF29t1o.js +++ b/assets/garden_fediverse_index.md.CexXroKb.js @@ -1 +1 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as i,c as d,j as e,a as n,k as a,ag as s,o as l}from"./chunks/framework.VBE0TPts.js";const o=e("h1",{class:"p-name"},"Fediverse",-1),c=["innerHTML"],m=s('
Referenced by:ATProtoActivityPubDecentralizedFedi v2Incremental SocialMbinNostrSocial MediaThe Small WebWeird
Tags:Decentralized

A collection of Social Media websites that can all talk to each other by virtue of a shared protocol

Typically refers to sites implementing ActivityPub

Implementations:

',7),v=JSON.parse('{"title":"Fediverse","description":"","frontmatter":{"alias":"Federated Social Media","public":"true","slug":"fediverse","tags":["Decentralized"],"title":"Fediverse","prev":false,"next":false},"headers":[],"relativePath":"garden/fediverse/index.md","filePath":"garden/fediverse/index.md"}'),f={name:"garden/fediverse/index.md"},x=Object.assign(f,{setup(h){const r=i();return(p,_)=>(l(),d("div",null,[o,e("p",null,[n("29 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,c)]),m]))}});export{v as __pageData,x as default}; +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as d,Q as e,K as n,u as a,ag as s,p as l}from"./chunks/framework.DvHfxfnp.js";const o=e("h1",{class:"p-name"},"Fediverse",-1),c=["innerHTML"],m=s('
Referenced by:ATProtoActivityPubDecentralizedFedi v2Incremental SocialMbinNostrSocial MediaThe Small WebWeird
Tags:Decentralized

A collection of Social Media websites that can all talk to each other by virtue of a shared protocol

Typically refers to sites implementing ActivityPub

Implementations:

',7),v=JSON.parse('{"title":"Fediverse","description":"","frontmatter":{"alias":"Federated Social Media","public":"true","slug":"fediverse","tags":["Decentralized"],"title":"Fediverse","prev":false,"next":false},"headers":[],"relativePath":"garden/fediverse/index.md","filePath":"garden/fediverse/index.md"}'),f={name:"garden/fediverse/index.md"},x=Object.assign(f,{setup(p){const r=i();return(h,_)=>(l(),d("div",null,[o,e("p",null,[n("29 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,c)]),m]))}});export{v as __pageData,x as default}; diff --git a/assets/garden_fediverse_index.md.BoF29t1o.lean.js b/assets/garden_fediverse_index.md.CexXroKb.lean.js similarity index 68% rename from assets/garden_fediverse_index.md.BoF29t1o.lean.js rename to assets/garden_fediverse_index.md.CexXroKb.lean.js index ced530ee..9c17a308 100644 --- a/assets/garden_fediverse_index.md.BoF29t1o.lean.js +++ b/assets/garden_fediverse_index.md.CexXroKb.lean.js @@ -1 +1 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as i,c as d,j as e,a as n,k as a,ag as s,o as l}from"./chunks/framework.VBE0TPts.js";const o=e("h1",{class:"p-name"},"Fediverse",-1),c=["innerHTML"],m=s("",7),v=JSON.parse('{"title":"Fediverse","description":"","frontmatter":{"alias":"Federated Social Media","public":"true","slug":"fediverse","tags":["Decentralized"],"title":"Fediverse","prev":false,"next":false},"headers":[],"relativePath":"garden/fediverse/index.md","filePath":"garden/fediverse/index.md"}'),f={name:"garden/fediverse/index.md"},x=Object.assign(f,{setup(h){const r=i();return(p,_)=>(l(),d("div",null,[o,e("p",null,[n("29 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,c)]),m]))}});export{v as __pageData,x as default}; +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as d,Q as e,K as n,u as a,ag as s,p as l}from"./chunks/framework.DvHfxfnp.js";const o=e("h1",{class:"p-name"},"Fediverse",-1),c=["innerHTML"],m=s("",7),v=JSON.parse('{"title":"Fediverse","description":"","frontmatter":{"alias":"Federated Social Media","public":"true","slug":"fediverse","tags":["Decentralized"],"title":"Fediverse","prev":false,"next":false},"headers":[],"relativePath":"garden/fediverse/index.md","filePath":"garden/fediverse/index.md"}'),f={name:"garden/fediverse/index.md"},x=Object.assign(f,{setup(p){const r=i();return(h,_)=>(l(),d("div",null,[o,e("p",null,[n("29 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,c)]),m]))}});export{v as __pageData,x as default}; diff --git a/assets/garden_forgejo_index.md.-Mf7Kiyr.js b/assets/garden_forgejo_index.md.-Mf7Kiyr.js new file mode 100644 index 00000000..a924b055 --- /dev/null +++ b/assets/garden_forgejo_index.md.-Mf7Kiyr.js @@ -0,0 +1 @@ +import{d as o}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as s,Q as e,K as a,u as r,p as l}from"./chunks/framework.DvHfxfnp.js";const i=e("h1",{class:"p-name"},"Forgejo",-1),d=["innerHTML"],c=e("hr",null,null,-1),u=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/incremental-social/index.md"},"Incremental Social")],-1),p=e("p",null,[e("a",{href:"https://forgejo.org",target:"_blank",rel:"noreferrer"},"Forgejo"),a(" is an "),e("a",{href:"/garden/open-source/"},"Open Source"),a(" code repository hosting software")],-1),x=JSON.parse('{"title":"Forgejo","description":"","frontmatter":{"public":"true","slug":"forgejo","title":"Forgejo","prev":false,"next":false},"headers":[],"relativePath":"garden/forgejo/index.md","filePath":"garden/forgejo/index.md"}'),_={name:"garden/forgejo/index.md"},v=Object.assign(_,{setup(g){const t=n();return(f,m)=>(l(),s("div",null,[i,e("p",null,[a("5 words, ~0 minute read. "),e("span",{innerHTML:r(o)[`site/${r(t).page.value.relativePath}`]},null,8,d)]),c,u,p]))}});export{x as __pageData,v as default}; diff --git a/assets/garden_forgejo_index.md.-Mf7Kiyr.lean.js b/assets/garden_forgejo_index.md.-Mf7Kiyr.lean.js new file mode 100644 index 00000000..a924b055 --- /dev/null +++ b/assets/garden_forgejo_index.md.-Mf7Kiyr.lean.js @@ -0,0 +1 @@ +import{d as o}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as s,Q as e,K as a,u as r,p as l}from"./chunks/framework.DvHfxfnp.js";const i=e("h1",{class:"p-name"},"Forgejo",-1),d=["innerHTML"],c=e("hr",null,null,-1),u=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/incremental-social/index.md"},"Incremental Social")],-1),p=e("p",null,[e("a",{href:"https://forgejo.org",target:"_blank",rel:"noreferrer"},"Forgejo"),a(" is an "),e("a",{href:"/garden/open-source/"},"Open Source"),a(" code repository hosting software")],-1),x=JSON.parse('{"title":"Forgejo","description":"","frontmatter":{"public":"true","slug":"forgejo","title":"Forgejo","prev":false,"next":false},"headers":[],"relativePath":"garden/forgejo/index.md","filePath":"garden/forgejo/index.md"}'),_={name:"garden/forgejo/index.md"},v=Object.assign(_,{setup(g){const t=n();return(f,m)=>(l(),s("div",null,[i,e("p",null,[a("5 words, ~0 minute read. "),e("span",{innerHTML:r(o)[`site/${r(t).page.value.relativePath}`]},null,8,d)]),c,u,p]))}});export{x as __pageData,v as default}; diff --git a/assets/garden_forgejo_index.md.DjFZ67LJ.js b/assets/garden_forgejo_index.md.DjFZ67LJ.js deleted file mode 100644 index 1ce9fcf8..00000000 --- a/assets/garden_forgejo_index.md.DjFZ67LJ.js +++ /dev/null @@ -1 +0,0 @@ -import{d as o}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as s,j as e,a,k as r,o as l}from"./chunks/framework.VBE0TPts.js";const i=e("h1",{class:"p-name"},"Forgejo",-1),d=["innerHTML"],c=e("hr",null,null,-1),u=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/incremental-social/index.md"},"Incremental Social")],-1),_=e("p",null,[e("a",{href:"https://forgejo.org",target:"_blank",rel:"noreferrer"},"Forgejo"),a(" is an "),e("a",{href:"/garden/open-source/"},"Open Source"),a(" code repository hosting software")],-1),x=JSON.parse('{"title":"Forgejo","description":"","frontmatter":{"public":"true","slug":"forgejo","title":"Forgejo","prev":false,"next":false},"headers":[],"relativePath":"garden/forgejo/index.md","filePath":"garden/forgejo/index.md"}'),g={name:"garden/forgejo/index.md"},v=Object.assign(g,{setup(p){const t=n();return(f,m)=>(l(),s("div",null,[i,e("p",null,[a("5 words, ~0 minute read. "),e("span",{innerHTML:r(o)[`site/${r(t).page.value.relativePath}`]},null,8,d)]),c,u,_]))}});export{x as __pageData,v as default}; diff --git a/assets/garden_forgejo_index.md.DjFZ67LJ.lean.js b/assets/garden_forgejo_index.md.DjFZ67LJ.lean.js deleted file mode 100644 index 1ce9fcf8..00000000 --- a/assets/garden_forgejo_index.md.DjFZ67LJ.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{d as o}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as s,j as e,a,k as r,o as l}from"./chunks/framework.VBE0TPts.js";const i=e("h1",{class:"p-name"},"Forgejo",-1),d=["innerHTML"],c=e("hr",null,null,-1),u=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/incremental-social/index.md"},"Incremental Social")],-1),_=e("p",null,[e("a",{href:"https://forgejo.org",target:"_blank",rel:"noreferrer"},"Forgejo"),a(" is an "),e("a",{href:"/garden/open-source/"},"Open Source"),a(" code repository hosting software")],-1),x=JSON.parse('{"title":"Forgejo","description":"","frontmatter":{"public":"true","slug":"forgejo","title":"Forgejo","prev":false,"next":false},"headers":[],"relativePath":"garden/forgejo/index.md","filePath":"garden/forgejo/index.md"}'),g={name:"garden/forgejo/index.md"},v=Object.assign(g,{setup(p){const t=n();return(f,m)=>(l(),s("div",null,[i,e("p",null,[a("5 words, ~0 minute read. "),e("span",{innerHTML:r(o)[`site/${r(t).page.value.relativePath}`]},null,8,d)]),c,u,_]))}});export{x as __pageData,v as default}; diff --git a/assets/garden_freeform-vs-chronological-dichotomy_index.md.D64deYnh.js b/assets/garden_freeform-vs-chronological-dichotomy_index.md.PROF6kb-.js similarity index 85% rename from assets/garden_freeform-vs-chronological-dichotomy_index.md.D64deYnh.js rename to assets/garden_freeform-vs-chronological-dichotomy_index.md.PROF6kb-.js index fc07ed72..0dc7d01a 100644 --- a/assets/garden_freeform-vs-chronological-dichotomy_index.md.D64deYnh.js +++ b/assets/garden_freeform-vs-chronological-dichotomy_index.md.PROF6kb-.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as t,c as l,j as e,a as o,k as r,o as i}from"./chunks/framework.VBE0TPts.js";const s=e("h1",{class:"p-name"},"Freeform vs Chronological Dichotomy",-1),c=["innerHTML"],d=e("hr",null,null,-1),m=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/chronological/index.md"},"Chronological"),e("a",{href:"/garden/freeform/index.md"},"Freeform")],-1),h=e("p",null,[o("Describes a dichotomy between displaying information in a "),e("a",{href:"/garden/freeform/"},"Freeform"),o(" vs "),e("a",{href:"/garden/chronological/"},"Chronological"),o(" manner")],-1),y=JSON.parse('{"title":"Freeform vs Chronological Dichotomy","description":"","frontmatter":{"public":"true","slug":"freeform-vs-chronological-dichotomy","title":"Freeform vs Chronological Dichotomy","prev":false,"next":false},"headers":[],"relativePath":"garden/freeform-vs-chronological-dichotomy/index.md","filePath":"garden/freeform-vs-chronological-dichotomy/index.md"}'),f={name:"garden/freeform-vs-chronological-dichotomy/index.md"},x=Object.assign(f,{setup(g){const a=t();return(u,_)=>(i(),l("div",null,[s,e("p",null,[o("10 words, ~0 minute read. "),e("span",{innerHTML:r(n)[`site/${r(a).page.value.relativePath}`]},null,8,c)]),d,m,h]))}});export{y as __pageData,x as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as t,q as l,Q as e,K as o,u as r,p as i}from"./chunks/framework.DvHfxfnp.js";const s=e("h1",{class:"p-name"},"Freeform vs Chronological Dichotomy",-1),c=["innerHTML"],d=e("hr",null,null,-1),m=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/chronological/index.md"},"Chronological"),e("a",{href:"/garden/freeform/index.md"},"Freeform")],-1),h=e("p",null,[o("Describes a dichotomy between displaying information in a "),e("a",{href:"/garden/freeform/"},"Freeform"),o(" vs "),e("a",{href:"/garden/chronological/"},"Chronological"),o(" manner")],-1),y=JSON.parse('{"title":"Freeform vs Chronological Dichotomy","description":"","frontmatter":{"public":"true","slug":"freeform-vs-chronological-dichotomy","title":"Freeform vs Chronological Dichotomy","prev":false,"next":false},"headers":[],"relativePath":"garden/freeform-vs-chronological-dichotomy/index.md","filePath":"garden/freeform-vs-chronological-dichotomy/index.md"}'),f={name:"garden/freeform-vs-chronological-dichotomy/index.md"},x=Object.assign(f,{setup(g){const a=t();return(u,_)=>(i(),l("div",null,[s,e("p",null,[o("10 words, ~0 minute read. "),e("span",{innerHTML:r(n)[`site/${r(a).page.value.relativePath}`]},null,8,c)]),d,m,h]))}});export{y as __pageData,x as default}; diff --git a/assets/garden_freeform-vs-chronological-dichotomy_index.md.D64deYnh.lean.js b/assets/garden_freeform-vs-chronological-dichotomy_index.md.PROF6kb-.lean.js similarity index 85% rename from assets/garden_freeform-vs-chronological-dichotomy_index.md.D64deYnh.lean.js rename to assets/garden_freeform-vs-chronological-dichotomy_index.md.PROF6kb-.lean.js index fc07ed72..0dc7d01a 100644 --- a/assets/garden_freeform-vs-chronological-dichotomy_index.md.D64deYnh.lean.js +++ b/assets/garden_freeform-vs-chronological-dichotomy_index.md.PROF6kb-.lean.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as t,c as l,j as e,a as o,k as r,o as i}from"./chunks/framework.VBE0TPts.js";const s=e("h1",{class:"p-name"},"Freeform vs Chronological Dichotomy",-1),c=["innerHTML"],d=e("hr",null,null,-1),m=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/chronological/index.md"},"Chronological"),e("a",{href:"/garden/freeform/index.md"},"Freeform")],-1),h=e("p",null,[o("Describes a dichotomy between displaying information in a "),e("a",{href:"/garden/freeform/"},"Freeform"),o(" vs "),e("a",{href:"/garden/chronological/"},"Chronological"),o(" manner")],-1),y=JSON.parse('{"title":"Freeform vs Chronological Dichotomy","description":"","frontmatter":{"public":"true","slug":"freeform-vs-chronological-dichotomy","title":"Freeform vs Chronological Dichotomy","prev":false,"next":false},"headers":[],"relativePath":"garden/freeform-vs-chronological-dichotomy/index.md","filePath":"garden/freeform-vs-chronological-dichotomy/index.md"}'),f={name:"garden/freeform-vs-chronological-dichotomy/index.md"},x=Object.assign(f,{setup(g){const a=t();return(u,_)=>(i(),l("div",null,[s,e("p",null,[o("10 words, ~0 minute read. "),e("span",{innerHTML:r(n)[`site/${r(a).page.value.relativePath}`]},null,8,c)]),d,m,h]))}});export{y as __pageData,x as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as t,q as l,Q as e,K as o,u as r,p as i}from"./chunks/framework.DvHfxfnp.js";const s=e("h1",{class:"p-name"},"Freeform vs Chronological Dichotomy",-1),c=["innerHTML"],d=e("hr",null,null,-1),m=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/chronological/index.md"},"Chronological"),e("a",{href:"/garden/freeform/index.md"},"Freeform")],-1),h=e("p",null,[o("Describes a dichotomy between displaying information in a "),e("a",{href:"/garden/freeform/"},"Freeform"),o(" vs "),e("a",{href:"/garden/chronological/"},"Chronological"),o(" manner")],-1),y=JSON.parse('{"title":"Freeform vs Chronological Dichotomy","description":"","frontmatter":{"public":"true","slug":"freeform-vs-chronological-dichotomy","title":"Freeform vs Chronological Dichotomy","prev":false,"next":false},"headers":[],"relativePath":"garden/freeform-vs-chronological-dichotomy/index.md","filePath":"garden/freeform-vs-chronological-dichotomy/index.md"}'),f={name:"garden/freeform-vs-chronological-dichotomy/index.md"},x=Object.assign(f,{setup(g){const a=t();return(u,_)=>(i(),l("div",null,[s,e("p",null,[o("10 words, ~0 minute read. "),e("span",{innerHTML:r(n)[`site/${r(a).page.value.relativePath}`]},null,8,c)]),d,m,h]))}});export{y as __pageData,x as default}; diff --git a/assets/garden_freeform_index.md.Cm941aMp.js b/assets/garden_freeform_index.md.BGHRpas3.js similarity index 78% rename from assets/garden_freeform_index.md.Cm941aMp.js rename to assets/garden_freeform_index.md.BGHRpas3.js index 045ce9a6..a52cdb96 100644 --- a/assets/garden_freeform_index.md.Cm941aMp.js +++ b/assets/garden_freeform_index.md.BGHRpas3.js @@ -1 +1 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as o,c as n,j as e,a as i,k as a,ag as s,o as d}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"Freeform",-1),c=["innerHTML"],m=s('
Referenced by:CommuneDigital GardensFreeform vs Chronological DichotomyGarden-RSS

A collection of information that is not tied to when it was created or edited

Part of the Freeform vs Chronological Dichotomy

Anything wiki-style is considered freeform

  • A collection of living documents

Garden-RSS, a theoretical alternative to RSS that's better for freeform content

',7),v=JSON.parse('{"title":"Freeform","description":"","frontmatter":{"public":"true","slug":"freeform","title":"Freeform","prev":false,"next":false},"headers":[],"relativePath":"garden/freeform/index.md","filePath":"garden/freeform/index.md"}'),f={name:"garden/freeform/index.md"},x=Object.assign(f,{setup(h){const r=o();return(_,g)=>(d(),n("div",null,[l,e("p",null,[i("46 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,c)]),m]))}});export{v as __pageData,x as default}; +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as o,q as n,Q as e,K as i,u as a,ag as s,p as d}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"Freeform",-1),m=["innerHTML"],c=s('
Referenced by:CommuneDigital GardensFreeform vs Chronological DichotomyGarden-RSS

A collection of information that is not tied to when it was created or edited

Part of the Freeform vs Chronological Dichotomy

Anything wiki-style is considered freeform

  • A collection of living documents

Garden-RSS, a theoretical alternative to RSS that's better for freeform content

',7),v=JSON.parse('{"title":"Freeform","description":"","frontmatter":{"public":"true","slug":"freeform","title":"Freeform","prev":false,"next":false},"headers":[],"relativePath":"garden/freeform/index.md","filePath":"garden/freeform/index.md"}'),f={name:"garden/freeform/index.md"},x=Object.assign(f,{setup(h){const r=o();return(_,g)=>(d(),n("div",null,[l,e("p",null,[i("46 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,m)]),c]))}});export{v as __pageData,x as default}; diff --git a/assets/garden_freeform_index.md.Cm941aMp.lean.js b/assets/garden_freeform_index.md.BGHRpas3.lean.js similarity index 56% rename from assets/garden_freeform_index.md.Cm941aMp.lean.js rename to assets/garden_freeform_index.md.BGHRpas3.lean.js index a5ef0806..a20d979f 100644 --- a/assets/garden_freeform_index.md.Cm941aMp.lean.js +++ b/assets/garden_freeform_index.md.BGHRpas3.lean.js @@ -1 +1 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as o,c as n,j as e,a as i,k as a,ag as s,o as d}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"Freeform",-1),c=["innerHTML"],m=s("",7),v=JSON.parse('{"title":"Freeform","description":"","frontmatter":{"public":"true","slug":"freeform","title":"Freeform","prev":false,"next":false},"headers":[],"relativePath":"garden/freeform/index.md","filePath":"garden/freeform/index.md"}'),f={name:"garden/freeform/index.md"},x=Object.assign(f,{setup(h){const r=o();return(_,g)=>(d(),n("div",null,[l,e("p",null,[i("46 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,c)]),m]))}});export{v as __pageData,x as default}; +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as o,q as n,Q as e,K as i,u as a,ag as s,p as d}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"Freeform",-1),m=["innerHTML"],c=s("",7),v=JSON.parse('{"title":"Freeform","description":"","frontmatter":{"public":"true","slug":"freeform","title":"Freeform","prev":false,"next":false},"headers":[],"relativePath":"garden/freeform/index.md","filePath":"garden/freeform/index.md"}'),f={name:"garden/freeform/index.md"},x=Object.assign(f,{setup(h){const r=o();return(_,g)=>(d(),n("div",null,[l,e("p",null,[i("46 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,m)]),c]))}});export{v as __pageData,x as default}; diff --git a/assets/garden_game-dev-tree_index.md.DYS7_xxo.js b/assets/garden_game-dev-tree_index.md.NAi3ceZ1.js similarity index 86% rename from assets/garden_game-dev-tree_index.md.DYS7_xxo.js rename to assets/garden_game-dev-tree_index.md.NAi3ceZ1.js index 55e93128..c1f42fb6 100644 --- a/assets/garden_game-dev-tree_index.md.DYS7_xxo.js +++ b/assets/garden_game-dev-tree_index.md.NAi3ceZ1.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as o,j as e,a as n,k as a,ag as p,o as i}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Game Dev Tree",-1),m=["innerHTML"],l=p('
Tags:My Projects

Play it here!

My first (good) incremental game! (My actual first was Shape Tycoon - I don't recommend it!)

It's Open Source!

The TV Tropes page on this game mentions some of the cool things about this game

',6),T=JSON.parse('{"title":"Game Dev Tree","description":"","frontmatter":{"public":"true","slug":"game-dev-tree","tags":["My Projects"],"title":"Game Dev Tree","prev":false,"next":false},"headers":[],"relativePath":"garden/game-dev-tree/index.md","filePath":"garden/game-dev-tree/index.md"}'),c={name:"garden/game-dev-tree/index.md"},v=Object.assign(c,{setup(_){const t=s();return(h,g)=>(i(),o("div",null,[d,e("p",null,[n("34 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),l]))}});export{T as __pageData,v as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as o,Q as e,K as n,u as a,ag as p,p as i}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Game Dev Tree",-1),m=["innerHTML"],l=p('
Tags:My Projects

Play it here!

My first (good) incremental game! (My actual first was Shape Tycoon - I don't recommend it!)

It's Open Source!

The TV Tropes page on this game mentions some of the cool things about this game

',6),T=JSON.parse('{"title":"Game Dev Tree","description":"","frontmatter":{"public":"true","slug":"game-dev-tree","tags":["My Projects"],"title":"Game Dev Tree","prev":false,"next":false},"headers":[],"relativePath":"garden/game-dev-tree/index.md","filePath":"garden/game-dev-tree/index.md"}'),c={name:"garden/game-dev-tree/index.md"},v=Object.assign(c,{setup(_){const t=s();return(h,g)=>(i(),o("div",null,[d,e("p",null,[n("34 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),l]))}});export{T as __pageData,v as default}; diff --git a/assets/garden_game-dev-tree_index.md.DYS7_xxo.lean.js b/assets/garden_game-dev-tree_index.md.NAi3ceZ1.lean.js similarity index 75% rename from assets/garden_game-dev-tree_index.md.DYS7_xxo.lean.js rename to assets/garden_game-dev-tree_index.md.NAi3ceZ1.lean.js index 0279bbd3..878a5a61 100644 --- a/assets/garden_game-dev-tree_index.md.DYS7_xxo.lean.js +++ b/assets/garden_game-dev-tree_index.md.NAi3ceZ1.lean.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as o,j as e,a as n,k as a,ag as p,o as i}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Game Dev Tree",-1),m=["innerHTML"],l=p("",6),T=JSON.parse('{"title":"Game Dev Tree","description":"","frontmatter":{"public":"true","slug":"game-dev-tree","tags":["My Projects"],"title":"Game Dev Tree","prev":false,"next":false},"headers":[],"relativePath":"garden/game-dev-tree/index.md","filePath":"garden/game-dev-tree/index.md"}'),c={name:"garden/game-dev-tree/index.md"},v=Object.assign(c,{setup(_){const t=s();return(h,g)=>(i(),o("div",null,[d,e("p",null,[n("34 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),l]))}});export{T as __pageData,v as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as o,Q as e,K as n,u as a,ag as p,p as i}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Game Dev Tree",-1),m=["innerHTML"],l=p("",6),T=JSON.parse('{"title":"Game Dev Tree","description":"","frontmatter":{"public":"true","slug":"game-dev-tree","tags":["My Projects"],"title":"Game Dev Tree","prev":false,"next":false},"headers":[],"relativePath":"garden/game-dev-tree/index.md","filePath":"garden/game-dev-tree/index.md"}'),c={name:"garden/game-dev-tree/index.md"},v=Object.assign(c,{setup(_){const t=s();return(h,g)=>(i(),o("div",null,[d,e("p",null,[n("34 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),l]))}});export{T as __pageData,v as default}; diff --git a/assets/garden_garden-rss_index.md.DGe30PZV.js b/assets/garden_garden-rss_index.md.DGe30PZV.js new file mode 100644 index 00000000..b15c22a2 --- /dev/null +++ b/assets/garden_garden-rss_index.md.DGe30PZV.js @@ -0,0 +1 @@ +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as i,Q as e,K as n,u as a,ag as l,p as d}from"./chunks/framework.DvHfxfnp.js";const o=e("h1",{class:"p-name"},"Garden-RSS",-1),c=["innerHTML"],f=l('
Referenced by:FreeformThe Small WebThis Knowledge Hub

A theoretical alternative to RSS that's better for Freeform websites (and Digital Gardens specifically )

Why is it useful?

How should it work?

  • Could display changes similar to git diffs

Existing Work

',9),S=JSON.parse('{"title":"Garden-RSS","description":"","frontmatter":{"public":"true","slug":"garden-rss","title":"Garden-RSS","prev":false,"next":false},"headers":[],"relativePath":"garden/garden-rss/index.md","filePath":"garden/garden-rss/index.md"}'),g={name:"garden/garden-rss/index.md"},b=Object.assign(g,{setup(h){const r=s();return(u,p)=>(d(),i("div",null,[o,e("p",null,[n("59 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,c)]),f]))}});export{S as __pageData,b as default}; diff --git a/assets/garden_garden-rss_index.md.DGe30PZV.lean.js b/assets/garden_garden-rss_index.md.DGe30PZV.lean.js new file mode 100644 index 00000000..c48f78cd --- /dev/null +++ b/assets/garden_garden-rss_index.md.DGe30PZV.lean.js @@ -0,0 +1 @@ +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as i,Q as e,K as n,u as a,ag as l,p as d}from"./chunks/framework.DvHfxfnp.js";const o=e("h1",{class:"p-name"},"Garden-RSS",-1),c=["innerHTML"],f=l("",9),S=JSON.parse('{"title":"Garden-RSS","description":"","frontmatter":{"public":"true","slug":"garden-rss","title":"Garden-RSS","prev":false,"next":false},"headers":[],"relativePath":"garden/garden-rss/index.md","filePath":"garden/garden-rss/index.md"}'),g={name:"garden/garden-rss/index.md"},b=Object.assign(g,{setup(h){const r=s();return(u,p)=>(d(),i("div",null,[o,e("p",null,[n("59 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,c)]),f]))}});export{S as __pageData,b as default}; diff --git a/assets/garden_garden-rss_index.md.FzV6pCp6.js b/assets/garden_garden-rss_index.md.FzV6pCp6.js deleted file mode 100644 index 5b38b8a0..00000000 --- a/assets/garden_garden-rss_index.md.FzV6pCp6.js +++ /dev/null @@ -1 +0,0 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as i,j as e,a as n,k as a,ag as l,o}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Garden-RSS",-1),c=["innerHTML"],f=l('
Referenced by:FreeformThe Small WebThis Knowledge Hub

A theoretical alternative to RSS that's better for Freeform websites (and Digital Gardens specifically )

Why is it useful?

How should it work?

  • Could display changes similar to git diffs

Existing Work

',9),S=JSON.parse('{"title":"Garden-RSS","description":"","frontmatter":{"public":"true","slug":"garden-rss","title":"Garden-RSS","prev":false,"next":false},"headers":[],"relativePath":"garden/garden-rss/index.md","filePath":"garden/garden-rss/index.md"}'),g={name:"garden/garden-rss/index.md"},b=Object.assign(g,{setup(h){const r=s();return(u,m)=>(o(),i("div",null,[d,e("p",null,[n("59 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,c)]),f]))}});export{S as __pageData,b as default}; diff --git a/assets/garden_garden-rss_index.md.FzV6pCp6.lean.js b/assets/garden_garden-rss_index.md.FzV6pCp6.lean.js deleted file mode 100644 index 3e42bcf6..00000000 --- a/assets/garden_garden-rss_index.md.FzV6pCp6.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as i,j as e,a as n,k as a,ag as l,o}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Garden-RSS",-1),c=["innerHTML"],f=l("",9),S=JSON.parse('{"title":"Garden-RSS","description":"","frontmatter":{"public":"true","slug":"garden-rss","title":"Garden-RSS","prev":false,"next":false},"headers":[],"relativePath":"garden/garden-rss/index.md","filePath":"garden/garden-rss/index.md"}'),g={name:"garden/garden-rss/index.md"},b=Object.assign(g,{setup(h){const r=s();return(u,m)=>(o(),i("div",null,[d,e("p",null,[n("59 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,c)]),f]))}});export{S as __pageData,b as default}; diff --git a/assets/garden_guide-to-incrementals_appeal-to-developers_index.md.C9QEK0j6.js b/assets/garden_guide-to-incrementals_appeal-to-developers_index.md.BoP7bn3q.js similarity index 96% rename from assets/garden_guide-to-incrementals_appeal-to-developers_index.md.C9QEK0j6.js rename to assets/garden_guide-to-incrementals_appeal-to-developers_index.md.BoP7bn3q.js index edb80eb3..064b850b 100644 --- a/assets/garden_guide-to-incrementals_appeal-to-developers_index.md.C9QEK0j6.js +++ b/assets/garden_guide-to-incrementals_appeal-to-developers_index.md.BoP7bn3q.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as o,c as i,j as e,a as r,k as a,ag as s,o as l}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals___Appeal to Developers",-1),m=["innerHTML"],c=s('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

There are a lot of developers in the incremental games community - the genre seems to draw them in, and convert a lot of players into developers. Let's explore the reasons why this genre appeals to developers.

Incrementals are Easy to Make

Compared to other genres, incrementals have quite low expectations. You don't need to make fancy art, or music, or lay things out nicely. If you can make a button and learn the few lines of code necessary to make a number go up, you can make an incremental. This low threshold makes the genre perfect for those who are actively learning to code and haven't developed any gamedev-related skills yet.

Additionally, unlike other genres incrementals are uniquely easy to implement in a normal web page - no need to worry about rendering sprites, moving them around, implementing physics, etc. New developers can just use HTML to add a button, and the game is now available in your browser. You don't need to choose an engine, have admin privileges, or hell for the dedicated you don't even need a computer - there are tools for web development that run in the browser itself, so you can technically use your phone if that's all you have.

Javascript is a perfectly viable language for making web games, whereas other genres are typically going to require using other more difficult languages to learn. There are countless javascript tutorials that start from 0 knowledge of programming, making it incredibly accessible to beginners.

Players are Easy to Find

Once you've finished your game and uploaded it on github pages or itch or just copied the link if you're using glitch or replit (all of which are easy to do), anyone can now play the game in their browser. This low barrier to entry has shown tremendous success in getting completely unknown developers to have thousands of plays.

The incremental games community, which mostly centers around r/incremental_games, is always looking for new games and tends to flood any new ones posted with initial players.

Having your games be played can be incredibly motivating, and the community makes it quite clear that you can expect players to play your game. These communities - both for incremental games in general as well as game-specific communities - tend to be very developer friendly as well. A lot of the developers know each other, and welcome new developers with open arms, often with dedicated channels for programming help and discussions.

Monetization

I'd like to clarify that everything I've said above mainly applies to web-based incrementals. Incremental games are also incredibly popular on mobile, but with a much different culture and community. Many mobile gamers will still participate in the web-focused community for the culture. This web-focused community has a culture that has been criticized for being "anti-monetization". Ads, IAPs, and similar forms of monetization are often criticized, mainly due to the abundance of completely non-monetized games available from hobbyist developers. There are exceptions, like paid games often being considered fine, like Increlution or Stuck in Time, or donation ware games like kittens game, but even popular games that have IAP see some level of regular criticism, like NGU Idle, Idle Skilling, or Idle Pins. A large part of this can be explained by the community being hyper-aware of the addictive) nature of this genre and its susceptibility to exploiting players.

On mobile, however, monetization is the norm and expected. If an incremental game is available on mobile, it almost certainly will be monetized, and mobile players are aware and accepting of that. Mobile incremental games, due to their addictive nature, tend to make a lot of money. It's very lucrative, and therefore these games are quite abundant on mobile storefronts.

',14),b=JSON.parse('{"title":"Guide to Incrementals/Appeal to Developers","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/appeal-to-developers","title":"Guide to Incrementals/Appeal to Developers","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/appeal-to-developers/index.md","filePath":"garden/guide-to-incrementals/appeal-to-developers/index.md"}'),p={name:"garden/guide-to-incrementals/appeal-to-developers/index.md"},v=Object.assign(p,{setup(h){const t=o();return(u,g)=>(l(),i("div",null,[d,e("p",null,[r("636 words, ~3 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),c]))}});export{b as __pageData,v as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as o,q as i,Q as e,K as r,u as a,ag as s,p as l}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals___Appeal to Developers",-1),m=["innerHTML"],c=s('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

There are a lot of developers in the incremental games community - the genre seems to draw them in, and convert a lot of players into developers. Let's explore the reasons why this genre appeals to developers.

Incrementals are Easy to Make

Compared to other genres, incrementals have quite low expectations. You don't need to make fancy art, or music, or lay things out nicely. If you can make a button and learn the few lines of code necessary to make a number go up, you can make an incremental. This low threshold makes the genre perfect for those who are actively learning to code and haven't developed any gamedev-related skills yet.

Additionally, unlike other genres incrementals are uniquely easy to implement in a normal web page - no need to worry about rendering sprites, moving them around, implementing physics, etc. New developers can just use HTML to add a button, and the game is now available in your browser. You don't need to choose an engine, have admin privileges, or hell for the dedicated you don't even need a computer - there are tools for web development that run in the browser itself, so you can technically use your phone if that's all you have.

Javascript is a perfectly viable language for making web games, whereas other genres are typically going to require using other more difficult languages to learn. There are countless javascript tutorials that start from 0 knowledge of programming, making it incredibly accessible to beginners.

Players are Easy to Find

Once you've finished your game and uploaded it on github pages or itch or just copied the link if you're using glitch or replit (all of which are easy to do), anyone can now play the game in their browser. This low barrier to entry has shown tremendous success in getting completely unknown developers to have thousands of plays.

The incremental games community, which mostly centers around r/incremental_games, is always looking for new games and tends to flood any new ones posted with initial players.

Having your games be played can be incredibly motivating, and the community makes it quite clear that you can expect players to play your game. These communities - both for incremental games in general as well as game-specific communities - tend to be very developer friendly as well. A lot of the developers know each other, and welcome new developers with open arms, often with dedicated channels for programming help and discussions.

Monetization

I'd like to clarify that everything I've said above mainly applies to web-based incrementals. Incremental games are also incredibly popular on mobile, but with a much different culture and community. Many mobile gamers will still participate in the web-focused community for the culture. This web-focused community has a culture that has been criticized for being "anti-monetization". Ads, IAPs, and similar forms of monetization are often criticized, mainly due to the abundance of completely non-monetized games available from hobbyist developers. There are exceptions, like paid games often being considered fine, like Increlution or Stuck in Time, or donation ware games like kittens game, but even popular games that have IAP see some level of regular criticism, like NGU Idle, Idle Skilling, or Idle Pins. A large part of this can be explained by the community being hyper-aware of the addictive) nature of this genre and its susceptibility to exploiting players.

On mobile, however, monetization is the norm and expected. If an incremental game is available on mobile, it almost certainly will be monetized, and mobile players are aware and accepting of that. Mobile incremental games, due to their addictive nature, tend to make a lot of money. It's very lucrative, and therefore these games are quite abundant on mobile storefronts.

',14),b=JSON.parse('{"title":"Guide to Incrementals/Appeal to Developers","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/appeal-to-developers","title":"Guide to Incrementals/Appeal to Developers","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/appeal-to-developers/index.md","filePath":"garden/guide-to-incrementals/appeal-to-developers/index.md"}'),p={name:"garden/guide-to-incrementals/appeal-to-developers/index.md"},v=Object.assign(p,{setup(h){const t=o();return(u,g)=>(l(),i("div",null,[d,e("p",null,[r("636 words, ~3 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),c]))}});export{b as __pageData,v as default}; diff --git a/assets/garden_guide-to-incrementals_appeal-to-developers_index.md.C9QEK0j6.lean.js b/assets/garden_guide-to-incrementals_appeal-to-developers_index.md.BoP7bn3q.lean.js similarity index 80% rename from assets/garden_guide-to-incrementals_appeal-to-developers_index.md.C9QEK0j6.lean.js rename to assets/garden_guide-to-incrementals_appeal-to-developers_index.md.BoP7bn3q.lean.js index 14cb820c..0e13ebcd 100644 --- a/assets/garden_guide-to-incrementals_appeal-to-developers_index.md.C9QEK0j6.lean.js +++ b/assets/garden_guide-to-incrementals_appeal-to-developers_index.md.BoP7bn3q.lean.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as o,c as i,j as e,a as r,k as a,ag as s,o as l}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals___Appeal to Developers",-1),m=["innerHTML"],c=s("",14),b=JSON.parse('{"title":"Guide to Incrementals/Appeal to Developers","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/appeal-to-developers","title":"Guide to Incrementals/Appeal to Developers","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/appeal-to-developers/index.md","filePath":"garden/guide-to-incrementals/appeal-to-developers/index.md"}'),p={name:"garden/guide-to-incrementals/appeal-to-developers/index.md"},v=Object.assign(p,{setup(h){const t=o();return(u,g)=>(l(),i("div",null,[d,e("p",null,[r("636 words, ~3 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),c]))}});export{b as __pageData,v as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as o,q as i,Q as e,K as r,u as a,ag as s,p as l}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals___Appeal to Developers",-1),m=["innerHTML"],c=s("",14),b=JSON.parse('{"title":"Guide to Incrementals/Appeal to Developers","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/appeal-to-developers","title":"Guide to Incrementals/Appeal to Developers","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/appeal-to-developers/index.md","filePath":"garden/guide-to-incrementals/appeal-to-developers/index.md"}'),p={name:"garden/guide-to-incrementals/appeal-to-developers/index.md"},v=Object.assign(p,{setup(h){const t=o();return(u,g)=>(l(),i("div",null,[d,e("p",null,[r("636 words, ~3 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),c]))}});export{b as __pageData,v as default}; diff --git a/assets/garden_guide-to-incrementals_appeal-to-players_index.md.tNU97J-Z.js b/assets/garden_guide-to-incrementals_appeal-to-players_index.md.CXnADb0-.js similarity index 98% rename from assets/garden_guide-to-incrementals_appeal-to-players_index.md.tNU97J-Z.js rename to assets/garden_guide-to-incrementals_appeal-to-players_index.md.CXnADb0-.js index 116109ef..056fd610 100644 --- a/assets/garden_guide-to-incrementals_appeal-to-players_index.md.tNU97J-Z.js +++ b/assets/garden_guide-to-incrementals_appeal-to-players_index.md.CXnADb0-.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as i,c as o,j as e,a as s,k as a,ag as r,o as l}from"./chunks/framework.VBE0TPts.js";const h=e("h1",{class:"p-name"},"Guide to Incrementals___Appeal to Players",-1),m=["innerHTML"],g=r('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

This is something that has been discussed and analyzed by many people, and to some extent, I feel like everything that can be said on the topic already has. However, a lot of these analyses are from the perspective of those with not as much experience and involvement within the genre as I'd argue would be necessary for a fully contextualized answer. I'm interested in ludology and part of that includes interpreting games as art, and to that end what constitutes a game, let alone a "good game". Incremental games are oft criticized, unfairly in my biased opinion, of not even constituting games, such as was posited by this polygon article.

Numbers Going Up

This is a very common response to why people enjoy incremental games, although it's not one I find compels me personally, and I suspect it might be a stand-in for progression) or Guide to Incrementals/What is Content?. But reportedly, some people do just like seeing big numbers. I must reiterate I suspect the actual cause is seeing big numbers in context though - if you start at 1e1000 of a currency and get to 1e1001, that isn't going to feel as satisfying as going from 1e10 to 1e100, and in any case, I don't think a button that just adds a zero to your number will feel quite satisfying - I believe its the sense of having made progress, and comparing where you are to where you started and feeling like you've earned your way here that is enjoyable.

Progression

I think a strong sense of progression is seen as very enjoyable to many players of all sorts of genres - engine builder board games, RPGs, rogue_lites_, etc. Incremental games tend to have an extremely exaggerated sense of progression, which makes them very appealing.

Meta-progression is when games have some sort of progression that persists when other progress gets lost - for example, upgrades that persist between runs of a roguelite game. These are common mechanics in incremental games - in fact, its not uncommon to have multiple of these reset mechanics nested on top of each other, each with their own meta-progression. These are satisfying to players, although they can be a bit controversial. These mechanics can often be seen as an optional crutch, and in roguelite games, players often challenge themselves to win without any meta progression. Essentially these challenges argue that meta-progression de-emphasizes player skill by replacing it with time served. Incremental games, through their exaggerated progression, eschew that possibility though - they make it impossible to beat without the meta progression systems, as the meta-progression becomes an entire chapter of the gameplay. I'd argue this does not detract from the game, however, and is actually a part of what makes incremental games, and roguelikes, enjoyable to many players: meta-progression augments the increases in skill the player is naturally gaining as they play. In effect, it's not replacing the skill increase, but exaggerating it to make it feel more real to the player.

Effortlessness

Incremental games are so easy, a lot of them even have you progress while you're not playing! Part of the appeal is being able to feel like you're making progress while doing something actually productive - multitasking, in a way. In this sense, the game is more of a fidget toy - not something to think hard about and play actively, but something to click a few buttons every so often while you're paying attention to a lecture or studying or working. Of course, not all incremental games lend themselves to being played this way - it's specifically "idle" games that work like this. These are games that take an incredibly long amount of time to see all the content, stretching it as thin as possible, but they aren't expecting you to be sitting at your device playing it the entire time. They expect you to leave and come back later to make a bit of progress and repeat the cycle.

If you look at the higher-level play of most games, you'll see them perform difficult feats with ease and speed. They'll achieve a "flow state" that takes all their knowledge and experience of the game and uses it to play the game as instinctively as possible. It's incredible to watch things like Slay the Spire speed runs or competitive DDR-likes. I'd argue the goal of a lot of games with a competitive scene is to get so good that the game becomes effortless. In that sense, a game that allows you to reach that point earlier isn't any less legitimate, but rather lowers the barrier to entry by allowing more people to get "really good" at the game. And to be clear, (most) incremental games aren't trivially easy - they, and to an extent, every game will have some level of learning and improvement over time.

Addiction

A lot of these reasons for why incremental games appeal may have reminded you of why gambling appeals to people, particularly those prone to addiction. Indeed, incremental games are quite often criticized for their similarity to a skinner box. Some have gone as far as to say incremental games as a genre are commenting that all games are skinner boxes). The argument goes that some games are not fun, but rather condition players into continuing to play without actually getting anything from the experience. When tied to real-world money this is seen as predatory, and to a lesser extent, even free games may be feeding the addictive sides of people and making them more prone to seek out gambling or micro-transaction heavy games.

While incremental games can be fun and even healthy in certain contexts, they can exacerbate video game addiction more than other genres. If you feel like playing incremental games is taking priority over other things in your life, or manipulating your sleep schedule, it may be prudent to seek help. See r/StopGaming for resources.

Since incremental games are often built on extrinsic motivations in the form of progression systems, it's hard to argue whether players continue to play because they are enjoying the gameplay, or if they are just conditioned to keep doing it because the game keeps rewarding them. Unfortunately, it can often feel like it's the latter, as there isn't typically anything compelling about the "gameplay" of clicking a button and waiting. There may be a significant overlap between those who enjoy incremental games and those who are most prone to addiction, and there are often posts on r/incremental_games about someone either struggling with or overcoming video game addiction.

Strategy

Incremental games could be considered a subset of strategy games), and inherit the appeals of strategy games. This includes the appeal of feeling like you've found a good solution to a puzzle, or that you're learning more about the game and are improving at making decisions within it.

Note that strategy games are not all the same difficulty, as well. Cookie Clicker is probably easier than Starcraft 2 (although late game may beg to differ). Plenty of incremental games can be used as evidence that "easier" strategies may have their separate appeal to harder strategy games - players like to feel smart and that they figured the game out and have optimized or mastered it, and the game being easier doesn't detract from that sense of accomplishment as much as it allows more and more users to be able to reach the point where they gain that sense.

Avoiding Staleness

Incremental games tend to have "paradigm shifts", where the gameplay changes in a meaningful way at various times throughout the progression of the game. These upset and change the gameplay loop, which helps keep them from stagnating. This constant "freshness" to the gameplay can keep players engaged for longer, compared to a game with a repetitive and static gameplay loop.

Good Game Design

Incremental games tend to show their game design "plainly", so it's more readily apparent if a game has good game design while playing, even if you're not looking for it. While different players have different preferences and might enjoy different types of games more than others, there are underlying good and bad game design principles that players will notice the effects of. To be clear, this isn't talking about stuff like big numbers being enjoyable, where I can comfortably agree to disagree with other players. They don't intrinsically make my experience better, but I'm aware of those for whom it does and I won't argue against their feelings. However, the game designer in me does feel like there are some extremely clear-cut examples of good and bad game design philosophies.

Let's start by giving an example of a mechanic I think can be easily and strongly argued is good game design. There are of course many examples, but a personal favorite of mine is how DOOM encourages aggressive gameplay by linking health drops to melee attacks. It has an intended experience it's trying to give the player - immersing themselves as DOOM guy, who would not hide behind cover when low on health - and this mechanic does a great job at encouraging and effectively teaching players to behave properly. This is in sharp contrast to shooters like Call of Duty, which have you regen health passively, encouraging players to hide behind cover and wait after getting hit. Note that I'm not arguing CoD is poorly designed, as the games have different intended experiences. I'm specifically praising DOOM for having a mechanic that does a good job at ensuring the player has that intended experience.

To contrast with an example I think is bad game design, let's talk about shields in souls-likes. This is a bit of a famous example, and I highly recommend this video essay which spends quite a good bit of time on this topic. Essentially, the argument boils down to players of earlier games in the souls games using shields too much - playing slowly, conservatively, and ultimately having less fun. Players wanted to feel safe, so they ended up playing in a way that ruined the experience for them. The developers solved this by removing shields, apart from an intentionally bad one effectively mocking the playstyle, and it did its job at getting players to play more aggressively, and often have more fun.

To bring the conversation back to incrementals, I'm incredibly opinionated on what makes a good incremental game, which I'll discuss in the game design section. Suffice it to say, incremental games rely more on good game design than other genres, due to not having much to distract from bad game design. This helps (although imperfectly - gamers are a bit too tolerant of bad game design!) well-designed games rise to the top within the genre.

Artistic Merit

The discussion of whether video games are art has resulted in a pretty universal "yes, they are", but with some games the argument may still crop up. The reason why Incremental games are sometimes questioned is due to their perceived lack of complexity. However, even setting aside the fact that if players are having fun then it's not time wasted, I think games can have artistic merit that supersedes the necessity of having (any / engaging / "deep") gameplay. Incremental games are no less legitimate of a game or the "art" label because of any lack perceived lack of depth. For what it's worth, most art can be consumed with more ease than any video game - any painting, movie, sculpture, etc.

A lot of incrementals have a narrative context that can similarly qualify them as art. Cookie Clicker is, as has been pointed out numerous times before, commenting on excess and increasing production beyond any reasonable limits - devolving into increasing production for its own sake. Indeed, a lot of incremental games are written to comment upon various concepts like capitalism or tropes in games, as discussed when defining Incrementals). However, I'd like to argue most incremental games are still art, even without any narrative context. "Art" as a concept is pretty nebulous already, but I personally like those who define it as an act of expression more than any physical result. The creator and the context within which they created the art, and any meaning they put into it, are all relevant and a part of the art itself. Most incremental games have artistic merit from things like why the creator made it, why they chose to make it an incremental game, and why they made any particular design decision. Hell, even if you play through an entire incremental game without a single thought or feeling, that very fact it elicited nothing can itself be artistic merit!

I'm not an art major, and I may be taking a somewhat extreme take on what is art and what has artistic merit, but I'd argue the overall point stands that games, and incremental games specifically, can have artistic merit, which appeals to many gamers.

',29),b=JSON.parse('{"title":"Guide to Incrementals/Appeal to Players","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/appeal-to-players","title":"Guide to Incrementals/Appeal to Players","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/appeal-to-players/index.md","filePath":"garden/guide-to-incrementals/appeal-to-players/index.md"}'),d={name:"garden/guide-to-incrementals/appeal-to-players/index.md"},w=Object.assign(d,{setup(c){const t=i();return(p,u)=>(l(),o("div",null,[h,e("p",null,[s("2166 words, ~12 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),g]))}});export{b as __pageData,w as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as o,Q as e,K as s,u as a,ag as r,p as l}from"./chunks/framework.DvHfxfnp.js";const h=e("h1",{class:"p-name"},"Guide to Incrementals___Appeal to Players",-1),m=["innerHTML"],g=r('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

This is something that has been discussed and analyzed by many people, and to some extent, I feel like everything that can be said on the topic already has. However, a lot of these analyses are from the perspective of those with not as much experience and involvement within the genre as I'd argue would be necessary for a fully contextualized answer. I'm interested in ludology and part of that includes interpreting games as art, and to that end what constitutes a game, let alone a "good game". Incremental games are oft criticized, unfairly in my biased opinion, of not even constituting games, such as was posited by this polygon article.

Numbers Going Up

This is a very common response to why people enjoy incremental games, although it's not one I find compels me personally, and I suspect it might be a stand-in for progression) or Guide to Incrementals/What is Content?. But reportedly, some people do just like seeing big numbers. I must reiterate I suspect the actual cause is seeing big numbers in context though - if you start at 1e1000 of a currency and get to 1e1001, that isn't going to feel as satisfying as going from 1e10 to 1e100, and in any case, I don't think a button that just adds a zero to your number will feel quite satisfying - I believe its the sense of having made progress, and comparing where you are to where you started and feeling like you've earned your way here that is enjoyable.

Progression

I think a strong sense of progression is seen as very enjoyable to many players of all sorts of genres - engine builder board games, RPGs, rogue_lites_, etc. Incremental games tend to have an extremely exaggerated sense of progression, which makes them very appealing.

Meta-progression is when games have some sort of progression that persists when other progress gets lost - for example, upgrades that persist between runs of a roguelite game. These are common mechanics in incremental games - in fact, its not uncommon to have multiple of these reset mechanics nested on top of each other, each with their own meta-progression. These are satisfying to players, although they can be a bit controversial. These mechanics can often be seen as an optional crutch, and in roguelite games, players often challenge themselves to win without any meta progression. Essentially these challenges argue that meta-progression de-emphasizes player skill by replacing it with time served. Incremental games, through their exaggerated progression, eschew that possibility though - they make it impossible to beat without the meta progression systems, as the meta-progression becomes an entire chapter of the gameplay. I'd argue this does not detract from the game, however, and is actually a part of what makes incremental games, and roguelikes, enjoyable to many players: meta-progression augments the increases in skill the player is naturally gaining as they play. In effect, it's not replacing the skill increase, but exaggerating it to make it feel more real to the player.

Effortlessness

Incremental games are so easy, a lot of them even have you progress while you're not playing! Part of the appeal is being able to feel like you're making progress while doing something actually productive - multitasking, in a way. In this sense, the game is more of a fidget toy - not something to think hard about and play actively, but something to click a few buttons every so often while you're paying attention to a lecture or studying or working. Of course, not all incremental games lend themselves to being played this way - it's specifically "idle" games that work like this. These are games that take an incredibly long amount of time to see all the content, stretching it as thin as possible, but they aren't expecting you to be sitting at your device playing it the entire time. They expect you to leave and come back later to make a bit of progress and repeat the cycle.

If you look at the higher-level play of most games, you'll see them perform difficult feats with ease and speed. They'll achieve a "flow state" that takes all their knowledge and experience of the game and uses it to play the game as instinctively as possible. It's incredible to watch things like Slay the Spire speed runs or competitive DDR-likes. I'd argue the goal of a lot of games with a competitive scene is to get so good that the game becomes effortless. In that sense, a game that allows you to reach that point earlier isn't any less legitimate, but rather lowers the barrier to entry by allowing more people to get "really good" at the game. And to be clear, (most) incremental games aren't trivially easy - they, and to an extent, every game will have some level of learning and improvement over time.

Addiction

A lot of these reasons for why incremental games appeal may have reminded you of why gambling appeals to people, particularly those prone to addiction. Indeed, incremental games are quite often criticized for their similarity to a skinner box. Some have gone as far as to say incremental games as a genre are commenting that all games are skinner boxes). The argument goes that some games are not fun, but rather condition players into continuing to play without actually getting anything from the experience. When tied to real-world money this is seen as predatory, and to a lesser extent, even free games may be feeding the addictive sides of people and making them more prone to seek out gambling or micro-transaction heavy games.

While incremental games can be fun and even healthy in certain contexts, they can exacerbate video game addiction more than other genres. If you feel like playing incremental games is taking priority over other things in your life, or manipulating your sleep schedule, it may be prudent to seek help. See r/StopGaming for resources.

Since incremental games are often built on extrinsic motivations in the form of progression systems, it's hard to argue whether players continue to play because they are enjoying the gameplay, or if they are just conditioned to keep doing it because the game keeps rewarding them. Unfortunately, it can often feel like it's the latter, as there isn't typically anything compelling about the "gameplay" of clicking a button and waiting. There may be a significant overlap between those who enjoy incremental games and those who are most prone to addiction, and there are often posts on r/incremental_games about someone either struggling with or overcoming video game addiction.

Strategy

Incremental games could be considered a subset of strategy games), and inherit the appeals of strategy games. This includes the appeal of feeling like you've found a good solution to a puzzle, or that you're learning more about the game and are improving at making decisions within it.

Note that strategy games are not all the same difficulty, as well. Cookie Clicker is probably easier than Starcraft 2 (although late game may beg to differ). Plenty of incremental games can be used as evidence that "easier" strategies may have their separate appeal to harder strategy games - players like to feel smart and that they figured the game out and have optimized or mastered it, and the game being easier doesn't detract from that sense of accomplishment as much as it allows more and more users to be able to reach the point where they gain that sense.

Avoiding Staleness

Incremental games tend to have "paradigm shifts", where the gameplay changes in a meaningful way at various times throughout the progression of the game. These upset and change the gameplay loop, which helps keep them from stagnating. This constant "freshness" to the gameplay can keep players engaged for longer, compared to a game with a repetitive and static gameplay loop.

Good Game Design

Incremental games tend to show their game design "plainly", so it's more readily apparent if a game has good game design while playing, even if you're not looking for it. While different players have different preferences and might enjoy different types of games more than others, there are underlying good and bad game design principles that players will notice the effects of. To be clear, this isn't talking about stuff like big numbers being enjoyable, where I can comfortably agree to disagree with other players. They don't intrinsically make my experience better, but I'm aware of those for whom it does and I won't argue against their feelings. However, the game designer in me does feel like there are some extremely clear-cut examples of good and bad game design philosophies.

Let's start by giving an example of a mechanic I think can be easily and strongly argued is good game design. There are of course many examples, but a personal favorite of mine is how DOOM encourages aggressive gameplay by linking health drops to melee attacks. It has an intended experience it's trying to give the player - immersing themselves as DOOM guy, who would not hide behind cover when low on health - and this mechanic does a great job at encouraging and effectively teaching players to behave properly. This is in sharp contrast to shooters like Call of Duty, which have you regen health passively, encouraging players to hide behind cover and wait after getting hit. Note that I'm not arguing CoD is poorly designed, as the games have different intended experiences. I'm specifically praising DOOM for having a mechanic that does a good job at ensuring the player has that intended experience.

To contrast with an example I think is bad game design, let's talk about shields in souls-likes. This is a bit of a famous example, and I highly recommend this video essay which spends quite a good bit of time on this topic. Essentially, the argument boils down to players of earlier games in the souls games using shields too much - playing slowly, conservatively, and ultimately having less fun. Players wanted to feel safe, so they ended up playing in a way that ruined the experience for them. The developers solved this by removing shields, apart from an intentionally bad one effectively mocking the playstyle, and it did its job at getting players to play more aggressively, and often have more fun.

To bring the conversation back to incrementals, I'm incredibly opinionated on what makes a good incremental game, which I'll discuss in the game design section. Suffice it to say, incremental games rely more on good game design than other genres, due to not having much to distract from bad game design. This helps (although imperfectly - gamers are a bit too tolerant of bad game design!) well-designed games rise to the top within the genre.

Artistic Merit

The discussion of whether video games are art has resulted in a pretty universal "yes, they are", but with some games the argument may still crop up. The reason why Incremental games are sometimes questioned is due to their perceived lack of complexity. However, even setting aside the fact that if players are having fun then it's not time wasted, I think games can have artistic merit that supersedes the necessity of having (any / engaging / "deep") gameplay. Incremental games are no less legitimate of a game or the "art" label because of any lack perceived lack of depth. For what it's worth, most art can be consumed with more ease than any video game - any painting, movie, sculpture, etc.

A lot of incrementals have a narrative context that can similarly qualify them as art. Cookie Clicker is, as has been pointed out numerous times before, commenting on excess and increasing production beyond any reasonable limits - devolving into increasing production for its own sake. Indeed, a lot of incremental games are written to comment upon various concepts like capitalism or tropes in games, as discussed when defining Incrementals). However, I'd like to argue most incremental games are still art, even without any narrative context. "Art" as a concept is pretty nebulous already, but I personally like those who define it as an act of expression more than any physical result. The creator and the context within which they created the art, and any meaning they put into it, are all relevant and a part of the art itself. Most incremental games have artistic merit from things like why the creator made it, why they chose to make it an incremental game, and why they made any particular design decision. Hell, even if you play through an entire incremental game without a single thought or feeling, that very fact it elicited nothing can itself be artistic merit!

I'm not an art major, and I may be taking a somewhat extreme take on what is art and what has artistic merit, but I'd argue the overall point stands that games, and incremental games specifically, can have artistic merit, which appeals to many gamers.

',29),b=JSON.parse('{"title":"Guide to Incrementals/Appeal to Players","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/appeal-to-players","title":"Guide to Incrementals/Appeal to Players","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/appeal-to-players/index.md","filePath":"garden/guide-to-incrementals/appeal-to-players/index.md"}'),d={name:"garden/guide-to-incrementals/appeal-to-players/index.md"},w=Object.assign(d,{setup(c){const t=i();return(p,u)=>(l(),o("div",null,[h,e("p",null,[s("2166 words, ~12 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),g]))}});export{b as __pageData,w as default}; diff --git a/assets/garden_guide-to-incrementals_appeal-to-players_index.md.tNU97J-Z.lean.js b/assets/garden_guide-to-incrementals_appeal-to-players_index.md.CXnADb0-.lean.js similarity index 80% rename from assets/garden_guide-to-incrementals_appeal-to-players_index.md.tNU97J-Z.lean.js rename to assets/garden_guide-to-incrementals_appeal-to-players_index.md.CXnADb0-.lean.js index 33b5a5a4..23676ae2 100644 --- a/assets/garden_guide-to-incrementals_appeal-to-players_index.md.tNU97J-Z.lean.js +++ b/assets/garden_guide-to-incrementals_appeal-to-players_index.md.CXnADb0-.lean.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as i,c as o,j as e,a as s,k as a,ag as r,o as l}from"./chunks/framework.VBE0TPts.js";const h=e("h1",{class:"p-name"},"Guide to Incrementals___Appeal to Players",-1),m=["innerHTML"],g=r("",29),b=JSON.parse('{"title":"Guide to Incrementals/Appeal to Players","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/appeal-to-players","title":"Guide to Incrementals/Appeal to Players","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/appeal-to-players/index.md","filePath":"garden/guide-to-incrementals/appeal-to-players/index.md"}'),d={name:"garden/guide-to-incrementals/appeal-to-players/index.md"},w=Object.assign(d,{setup(c){const t=i();return(p,u)=>(l(),o("div",null,[h,e("p",null,[s("2166 words, ~12 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),g]))}});export{b as __pageData,w as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as o,Q as e,K as s,u as a,ag as r,p as l}from"./chunks/framework.DvHfxfnp.js";const h=e("h1",{class:"p-name"},"Guide to Incrementals___Appeal to Players",-1),m=["innerHTML"],g=r("",29),b=JSON.parse('{"title":"Guide to Incrementals/Appeal to Players","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/appeal-to-players","title":"Guide to Incrementals/Appeal to Players","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/appeal-to-players/index.md","filePath":"garden/guide-to-incrementals/appeal-to-players/index.md"}'),d={name:"garden/guide-to-incrementals/appeal-to-players/index.md"},w=Object.assign(d,{setup(c){const t=i();return(p,u)=>(l(),o("div",null,[h,e("p",null,[s("2166 words, ~12 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),g]))}});export{b as __pageData,w as default}; diff --git a/assets/garden_guide-to-incrementals_defining-the-genre_index.md.CnpSquU9.js b/assets/garden_guide-to-incrementals_defining-the-genre_index.md.DwYrHYrF.js similarity index 99% rename from assets/garden_guide-to-incrementals_defining-the-genre_index.md.CnpSquU9.js rename to assets/garden_guide-to-incrementals_defining-the-genre_index.md.DwYrHYrF.js index 2d5ae07b..d2acef7b 100644 --- a/assets/garden_guide-to-incrementals_defining-the-genre_index.md.CnpSquU9.js +++ b/assets/garden_guide-to-incrementals_defining-the-genre_index.md.DwYrHYrF.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as o,j as e,a as i,k as t,ag as s,o as l}from"./chunks/framework.VBE0TPts.js";const h=e("h1",{class:"p-name"},"Guide to Incrementals___Defining the Genre",-1),m=["innerHTML"],g=s('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

Video games are placed into genres for a variety of reasons. They can give a mental shorthand to set the player's expectations up, they can help a game market itself by its similarities to other, already popular games, and honestly, people just love categorization for its own sake. For this guide, it's important to define the genre so it is clear what games it's even talking about.

This poses a problem. "Incremental" is a horribly vague way to define games. Most games have numbers going up in some form or another. We need a more specific definition - similar to how "strategy" can't just mean any game with any amount of strategy because that would be most games. What specifically differentiates incremental games from the rest?

"Incremental" implies it's a genre defined by a game mechanic, but all those game mechanics it could imply exist in many other games. Having a skill tree or upgrades doesn't make you incremental, and if a reset mechanic is all it takes then every roguelite would be an incremental as well. So clearly there's more to it than that - what makes an incremental an incremental?

I'd like to go over a couple of popular suggestions I've seen on defining the genre here. I have my personal preferences and will state them here, but I don't think there's a truly perfect answer here.

Disclaimer: I mostly play incremental games on my computer, and my definitions will be heavily biased towards the games I'm familiar with.

Incrementals vs Idlers vs Clickers

Oftentimes people refer to this genre as idle games and/or clicker games. You'll even find a trend of oxymoronic game titles that contain both terms. "Incremental games" is the umbrella term both those terms fall under. However, I'd like to argue that not only is it better to just use the term "incremental games", but calling them "idle games" or "clicker games" is wrong. Almost universally, these terms are used interchangeably to refer to the same kind of game, where you start the game click spamming and eventually automate the process. Frankly, that kind of game deserves neither title, and the genre of incremental games has trended away from ever requiring click spamming, as it's a bad mechanic, anyways.

While these games do span a spectrum of how active it requires you to be, and sorting games by that metric can be useful for those looking for a particular experience, the borders of when an incremental game counts as an "idler" is too blurry for the term to be useful. "Incremental games" may not be a great descriptive term for the genre (hence this many thousands of words long page on defining what the genre even is), but it's strictly better than calling them "idler" or "clicker" games. This guide will always use the term "incremental games" unless quoting someone else, as it is the term you typically see on all modern games in the genre.

Incrementals as Parodies

Let's start with one of the most interesting definitions of incremental games. Incremental games appear to be distilled versions of games or genres, "revealing" the naked game design at the core of these games or genres not unlike how parodies comment upon their source material.

To understand what that means, think of how a casino uses skinner boxes to emotionally manipulate its customers to keep playing, but "dressing" up the skinner box with tons of stimuli to hide that ultimately the goal is to condition you into coming back compulsively. The idea that incremental games are parodies means taking the stance that at some level all games are similarly manipulating you, giving dopamine rewards in a way that manipulates you to keep playing while not necessarily giving you any value or fulfillment. Incremental games, then, are any games that plainly display the skinner box, and the manipulative core of the game, at the forefront of the experience.

While incremental games can be fun and even healthy in certain contexts, they can exacerbate video game addiction more than other genres. If you feel like playing incremental games is taking priority over other things in your life, or manipulating your sleep schedule, it may be prudent to seek help. See r/StopGaming for resources.

This "undressing" tends to go hand in hand with a reduced focus on aesthetics, often just printing the game state directly to the screen as text. This makes incremental games much easier to develop, particularly for those with programming skills but not art skills, but that's a tangent for why Incremental Games Guide to Incrementals/Appeal to Developers.

Before I continue, I'd like to make my stance clear that I love games and incremental games, and do not think they should be considered inherently bad or manipulative with the above logic. Skinner boxes are just a way of manipulating behavior via rewards. The games are still fun - that's the reward! I'd believe the real criticism here is that it is "empty fun", or "empty dopamine", that doesn't offer any additional value or sense of fulfillment. I don't think that's inherently bad in moderation, although it can become a problem if the game is manipulating you for profit-seeking, or if you play the game to the detriment of the other parts of your life.

Another interpretation of incremental games as parodies comes from several mainstream incremental games that are also parodies of capitalism, such as cookie clicker and adventure capitalist. It's a very common framework for incremental games to portray the ever-increasing numbers as an insatiable hunger for resources, like the ones observed within capitalism. Therefore, these games are used as evidence that the genre as a whole is about parody and commentary.

Popular videos on incremental games that portray the genre as parodies are Why Idle games make good satire, and how it was ruined. and Bad Game Design - Clicker Games. You may also be interested in this response to the latter video from a fan of incremental games: BadGood Game Design - Clicker Games.

I think that this definition ultimately ascribes a motive to the genre as a whole that only happens to apply to some of the more mainstream titles. There certainly are incremental games commenting on different things, including the genre itself as in the case of The Prestige Tree Classic, The Ascension Tree, or Omega Layers, but certainly not all. And of course, not all games that comment on something or parody something are incremental games! Additionally, a very large majority of incremental games are mobile games using these manipulative strategies to get players to spend as much money as possible - hell, Adventure Capitalist is ostensibly a critique on capitalism but features microtransactions and gameplay that manipulates you into buying them! These profit-seeking incremental games certainly belong within the genre but are hardly parodies when they too use manipulation to serve their interests. Also, from my own anecdotal experience, those who use this definition seem to do so from a fairly surface-level familiarity with the genre, and often in the context of criticizing the genre or the fans thereof.

Incrementals as NGU

Another broad definition often used is that incremental games are games where the focus of the game is "numbers going up". This definition proposes that other genres simply use increasing numbers as a means to an end, but incremental games uniquely only care about the numbers themselves going up. Put another way, it implies there should be no narrative justification for the numbers going up other than "why shouldn't they be going up?"

While this definition is common because it feels easy to understand, it is difficult to formally define. Often phrases are used to describe games using this framework, such as having an "exaggerated sense of progression" or "big" numbers. These terms are vague and don't demonstrate an actual threshold between non-incrementals and incrementals. Most games have a sense of progression, so when is it "exaggerated"? How big are "big" numbers? Most notably, RPGs that are typically not considered incrementals will often pass this definition.

Additionally, a lot of incrementals tend to have some theme guiding the gameplay, or at least the names of mechanics. This makes the line blurred between when numbers are going up for their own sake versus for a contextual reason. I believe this point is best illustrated that, while most RPGs are not considered incremental games, there is a sub-genre of "incremental RPGs" that typically relates to RPGs that perform combat automatically. This definition of incremental games does not support RPGs and "incremental RPGs" being on distinct sides of the line if the only difference between them is manual vs automatic combat.

Incrementals as Strategies

This is a rarer interpretation, but there are similarities between incremental games and strategy games, implying incrementals might just be a sub-genre of strategy games. By this approach, incremental games would be defined by their relation to strategy games, and how they involve player strategy. Incremental games are often large optimization problems - above all else, the actual gameplay the player is performing is deciding what to do next. The consequences of wrong decisions are typically more lenient in incremental games - such as just not making optimal progress - but they certainly get complex.

So if we accept the premise that incrementals could fall under strategy, we still need to define what makes a strategy game an incremental versus some other strategy sub-genre. This is a bit tricky due to one particular sub-genre of strategy games: Factory Builders.

Factory builders, such as Factorio or Satisfactory, are games about gaining ever increasing resources, optimizing production, and expanding more and more. That... sounds pretty similar, doesn't it? In fact, there's been some debate on whether factory builders would fall under the "incremental" umbrella. I think it's safe to say the two are certainly related, and probably have quite a bit of overlap in playerbase.

Roguelites as Incrementals?

Earlier on, I mentioned reset mechanics shouldn't be used in the definition because that could make all roguelites incrementals... But what if it does? A lot of incrementals can be described as games with a strong sense of progression, often with layers of meta-progression. Roguelites fit that bill to a T. What would make roguelites not incremental? I honestly don't think there's a good explanation here, but many fans of incremental games will state they do believe the two genres to be unrelated, even if there's a significant overlap between their player bases due to having similar appealing traits.

At this point, it'd be appropriate to consider what part of the definition of roguelites precludes them from also being incrementals, but that reveals a new problem: What are roguelites? They're usually defined as rogue_likes with meta-progression, but that just pushes the problem back a step: Incrementals aren't the only genre to have difficulties defining themselves, it seems! Roguelikes are another genre where the community argues over the formal definition of their genre, although that means we can borrow from their process of coming to a consensus, and maybe come across a viable definition for incremental games.

The Berlin Interpretation

By far the most popular way of defining roguelikes is the "Berlin Interpretation", which acknowledged the diversity of games within the genre and argued the definition should not be based on any ideals about what the genre ought to be, but rather defined by "its canon". They argued there are a handful of games that can be used to define the canon for roguelikes, and from those games, a list of factors can be derived to determine a game's "roguelikeness". The more factors a game has, the more of a roguelike it is. This strategy is very lenient, allowing a game to not present any specific factor so long as it shows enough, and accounts for the blurriness of any genre definition by not explicitly stating how many factors a game must have to qualify as a definite roguelike.

I believe this strategy for defining genres can be applied to other genres as well. A handful of games can be argued to be the incremental games canon, and a list of factors derived from them can be used to judge any game based on its "incrementalness". I'll propose such a canon and list of factors here, but by no means should it be considered the end-all-be-all.

Note: The "Temple of the roguelike", an authority within the genre, has since replaced the Berlin Interpretation with a new set of factors here: https://blog.roguetemple.com/what-is-a-traditional-roguelike/

The Incremental Games Canon

Alright, time to get controversial. Up til now, I've been trying my best to stay objective and analytical, but now it's time to start making some opinionated decisions. Here is a list of games I think could justifiably make up an Incremental Games Canon:

I chose a variety of games here, biasing towards newer games, purposefully to avoid making a narrow or "traditional" definition. The genre is growing and shouldn't be constrained by the traits of the early popular titles. A lot of these could easily be replaced with other games that are mechanically congruent, so ultimately I'm sure if you asked 10 people for their canon list you'd just get 10 different answers, but I think this should sufficiently allow us to determine what factors make a game have higher "incrementalness".

The Paradigm Shift

The Paradigm Shift is probably the highest possible value factor for an incremental. It's so common that for a while people referred to incrementals that exhibit this trait as "unfolding" games, to the point of trying to replace the term incremental due to their popularity. Paradigm shifts refer to when the gameplay significantly changes. There are too many examples to list here, but notably, every single reset mechanic is typically going to be a paradigm shift. Examples of games with paradigm shifts that aren't tied to reset mechanics include Universal Paperclips and A Dark Room.

There are many reasons for the appeal of paradigm shifts. Oftentimes each mechanic builds on top of the existing mechanics, increasing the complexity of the game in steps so the player can follow along. They provide a sense of mystery, with the player anticipating what will happen next. They shake up the gameplay before it gets too stale - allowing the game to entertain for longer before the sense of Guide to Incrementals/What is Content? dissipates. Of the canon games selected above, I would argue every single one contains a paradigm shift (although I could see someone disagreeing with that statement wrt Increlution).

I should take a moment to say that while I'm hyping up this specific factor, we cannot just reduce the genre definition to "does it have paradigm shifts". Many games have paradigm shifts that are not incremental, so it's just an indicator of incrementalness. Additionally, it can become quite hard to determine how large of a shift is a "paradigm" shift. Take, for example, any game with a skill tree. In some games, each skill node might have a large impact on how you play with the game, and qualify as a paradigm shift for some players. In other games, each skill node might just be a small percentage modifier on some stat that doesn't really impact much more than a slight bias towards an already established mechanic that's newly buffed. Every single canon game may show that it's common amongst incremental games, but could just as easily indicate that they're common in games in general.

High-Value Factors

I won't take as long to discuss the high and low-value factors, as you've already seen most of them brought up earlier on this page. As a reminder, a game does NOT need all of these to be an incremental game, but these are factors that each indicate a strong possibility the game is an incremental, so having several of these means they probably are. These factors apply to most of the canon incremental games.

"Pure UI" Display. Incrementals typically have a textual presentation of the game state - there isn't a visual representation of the entities within the game. The interface is closer to what would be just the UI of a game in another genre or the control panel of a plane. If there is a visual representation, the player is often still interacting with non-diegetic game elements.

Reduced Consequences. Incrementals tend to have reduced repurcussions for misplaying. They very rarely have fail states, where often the largest consequence is simply not progressing - never losing progress.

Optimization Problems. The predominant gameplay of incrementals is typically solving optimization problems, from deciding which purchase to save up for to reasoning and deciding between different mutually exclusive options the game presents.

Resource Management. Incrementals tend to have a lot of resources within the game to keep track of.

Low-Value Factors

These are low-value factors, meaning they aren't as strongly correlated with incremental games. Incremental games may have none of these, and non-incrementals may have several of these - if a game only has low-value factors, they're probably not an incremental.

Fast Numeric Growth. Numbers in incremental games tend to grow faster than in other genres. There are more instances of superlinear growth. The larger the numbers get, the stronger of a signal this factor is.

Automation. As an incremental game progresses, the player often no longer has to deal with earlier mechanics, by having them either happen automatically or otherwise be replaced with an alternative that requires less player interaction.

Goal-Oriented. Incrementals are often heavily reliant on extrinsic motivation to guide the player. Typically this is through some sort of in-game goal to work towards, such as a certain amount of a resource being required to unlock or purchase something new.

Waiting is a Mechanic. In incremental games, the player may come across times where there is no action they can take, and the game will progress automatically instead. The player must wait for some amount of this automatic progress to occur before they can resume interaction with the game.

Are Roguelites Incrementals?

Having made our variation of the Berlin Interpretation for incremental games, we can compare it to the Berlin Interpretation to determine if there's enough overlap that any game that "passes" the Berlin Interpretation would also pass the incremental variant. That is to say, whether any roguelite would also be considered an incremental game.

The meta-progression of an incremental game could arguably be considered a paradigm shift, and certainly adds some resource management. Goal-oriented would probably also apply. I think anything other than those would be a stretch, and in my opinion that just isn't enough to qualify. To be totally honest, I was never expecting to conclude otherwise though 😉

Sub-Genres

There are some trends in incremental games that go beyond just being a commonly used mechanic, such that they deeply affect the rest of the game design. These trends can be used to determine sub-genres within the incremental games umbrella:

Loops games are a sub-genre defined by having a core mechanic related to a loop, where the player is deciding the actions taken per loop. Notable examples include Idle Loops, Stuck in Time, Cavernous II, and Increlution. You may also argue Groundhog Life and Progress Knight fall into this sub-genre.

ITRTG-like games are a sub-genre defined by having a core mechanic based on clearing increasingly difficult battles and often tend to have a lot of different mechanics to become progressively stronger. Notable examples include Idling to Rule the Gods, NGU Idle, and Wizard and Minion Idle.

Polynomial Growth games are a sub-genre defined by having a core mechanic related to a higher degree polynomial. Notable examples include the base layer of Antimatter Dimensions and Swarm Simulator.

Upgrades Games is a category popular on flash games websites that featured games focused on buying upgrades that would allow you to attain more currency in some sort of minigame that would earn you more money to buy more upgrades, which I'd argue now belong under the fold of incremental games. Notable examples include the Learn to Fly series and Upgrade Complete.

Cultivation RPGs are a genre of games, books, and anime popular in China that center around being in a fantasy world with characters getting stronger over time. While few of them get translated into English, a fan of incremental games may find the available games interesting.

',65),y=JSON.parse('{"title":"Guide to Incrementals/Defining the Genre","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/defining-the-genre","title":"Guide to Incrementals/Defining the Genre","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/defining-the-genre/index.md","filePath":"garden/guide-to-incrementals/defining-the-genre/index.md"}'),c={name:"garden/guide-to-incrementals/defining-the-genre/index.md"},w=Object.assign(c,{setup(u){const a=n();return(d,p)=>(l(),o("div",null,[h,e("p",null,[i("3429 words, ~19 minute read. "),e("span",{innerHTML:t(r)[`site/${t(a).page.value.relativePath}`]},null,8,m)]),g]))}});export{y as __pageData,w as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as o,Q as e,K as i,u as t,ag as s,p as l}from"./chunks/framework.DvHfxfnp.js";const h=e("h1",{class:"p-name"},"Guide to Incrementals___Defining the Genre",-1),m=["innerHTML"],g=s('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

Video games are placed into genres for a variety of reasons. They can give a mental shorthand to set the player's expectations up, they can help a game market itself by its similarities to other, already popular games, and honestly, people just love categorization for its own sake. For this guide, it's important to define the genre so it is clear what games it's even talking about.

This poses a problem. "Incremental" is a horribly vague way to define games. Most games have numbers going up in some form or another. We need a more specific definition - similar to how "strategy" can't just mean any game with any amount of strategy because that would be most games. What specifically differentiates incremental games from the rest?

"Incremental" implies it's a genre defined by a game mechanic, but all those game mechanics it could imply exist in many other games. Having a skill tree or upgrades doesn't make you incremental, and if a reset mechanic is all it takes then every roguelite would be an incremental as well. So clearly there's more to it than that - what makes an incremental an incremental?

I'd like to go over a couple of popular suggestions I've seen on defining the genre here. I have my personal preferences and will state them here, but I don't think there's a truly perfect answer here.

Disclaimer: I mostly play incremental games on my computer, and my definitions will be heavily biased towards the games I'm familiar with.

Incrementals vs Idlers vs Clickers

Oftentimes people refer to this genre as idle games and/or clicker games. You'll even find a trend of oxymoronic game titles that contain both terms. "Incremental games" is the umbrella term both those terms fall under. However, I'd like to argue that not only is it better to just use the term "incremental games", but calling them "idle games" or "clicker games" is wrong. Almost universally, these terms are used interchangeably to refer to the same kind of game, where you start the game click spamming and eventually automate the process. Frankly, that kind of game deserves neither title, and the genre of incremental games has trended away from ever requiring click spamming, as it's a bad mechanic, anyways.

While these games do span a spectrum of how active it requires you to be, and sorting games by that metric can be useful for those looking for a particular experience, the borders of when an incremental game counts as an "idler" is too blurry for the term to be useful. "Incremental games" may not be a great descriptive term for the genre (hence this many thousands of words long page on defining what the genre even is), but it's strictly better than calling them "idler" or "clicker" games. This guide will always use the term "incremental games" unless quoting someone else, as it is the term you typically see on all modern games in the genre.

Incrementals as Parodies

Let's start with one of the most interesting definitions of incremental games. Incremental games appear to be distilled versions of games or genres, "revealing" the naked game design at the core of these games or genres not unlike how parodies comment upon their source material.

To understand what that means, think of how a casino uses skinner boxes to emotionally manipulate its customers to keep playing, but "dressing" up the skinner box with tons of stimuli to hide that ultimately the goal is to condition you into coming back compulsively. The idea that incremental games are parodies means taking the stance that at some level all games are similarly manipulating you, giving dopamine rewards in a way that manipulates you to keep playing while not necessarily giving you any value or fulfillment. Incremental games, then, are any games that plainly display the skinner box, and the manipulative core of the game, at the forefront of the experience.

While incremental games can be fun and even healthy in certain contexts, they can exacerbate video game addiction more than other genres. If you feel like playing incremental games is taking priority over other things in your life, or manipulating your sleep schedule, it may be prudent to seek help. See r/StopGaming for resources.

This "undressing" tends to go hand in hand with a reduced focus on aesthetics, often just printing the game state directly to the screen as text. This makes incremental games much easier to develop, particularly for those with programming skills but not art skills, but that's a tangent for why Incremental Games Guide to Incrementals/Appeal to Developers.

Before I continue, I'd like to make my stance clear that I love games and incremental games, and do not think they should be considered inherently bad or manipulative with the above logic. Skinner boxes are just a way of manipulating behavior via rewards. The games are still fun - that's the reward! I'd believe the real criticism here is that it is "empty fun", or "empty dopamine", that doesn't offer any additional value or sense of fulfillment. I don't think that's inherently bad in moderation, although it can become a problem if the game is manipulating you for profit-seeking, or if you play the game to the detriment of the other parts of your life.

Another interpretation of incremental games as parodies comes from several mainstream incremental games that are also parodies of capitalism, such as cookie clicker and adventure capitalist. It's a very common framework for incremental games to portray the ever-increasing numbers as an insatiable hunger for resources, like the ones observed within capitalism. Therefore, these games are used as evidence that the genre as a whole is about parody and commentary.

Popular videos on incremental games that portray the genre as parodies are Why Idle games make good satire, and how it was ruined. and Bad Game Design - Clicker Games. You may also be interested in this response to the latter video from a fan of incremental games: BadGood Game Design - Clicker Games.

I think that this definition ultimately ascribes a motive to the genre as a whole that only happens to apply to some of the more mainstream titles. There certainly are incremental games commenting on different things, including the genre itself as in the case of The Prestige Tree Classic, The Ascension Tree, or Omega Layers, but certainly not all. And of course, not all games that comment on something or parody something are incremental games! Additionally, a very large majority of incremental games are mobile games using these manipulative strategies to get players to spend as much money as possible - hell, Adventure Capitalist is ostensibly a critique on capitalism but features microtransactions and gameplay that manipulates you into buying them! These profit-seeking incremental games certainly belong within the genre but are hardly parodies when they too use manipulation to serve their interests. Also, from my own anecdotal experience, those who use this definition seem to do so from a fairly surface-level familiarity with the genre, and often in the context of criticizing the genre or the fans thereof.

Incrementals as NGU

Another broad definition often used is that incremental games are games where the focus of the game is "numbers going up". This definition proposes that other genres simply use increasing numbers as a means to an end, but incremental games uniquely only care about the numbers themselves going up. Put another way, it implies there should be no narrative justification for the numbers going up other than "why shouldn't they be going up?"

While this definition is common because it feels easy to understand, it is difficult to formally define. Often phrases are used to describe games using this framework, such as having an "exaggerated sense of progression" or "big" numbers. These terms are vague and don't demonstrate an actual threshold between non-incrementals and incrementals. Most games have a sense of progression, so when is it "exaggerated"? How big are "big" numbers? Most notably, RPGs that are typically not considered incrementals will often pass this definition.

Additionally, a lot of incrementals tend to have some theme guiding the gameplay, or at least the names of mechanics. This makes the line blurred between when numbers are going up for their own sake versus for a contextual reason. I believe this point is best illustrated that, while most RPGs are not considered incremental games, there is a sub-genre of "incremental RPGs" that typically relates to RPGs that perform combat automatically. This definition of incremental games does not support RPGs and "incremental RPGs" being on distinct sides of the line if the only difference between them is manual vs automatic combat.

Incrementals as Strategies

This is a rarer interpretation, but there are similarities between incremental games and strategy games, implying incrementals might just be a sub-genre of strategy games. By this approach, incremental games would be defined by their relation to strategy games, and how they involve player strategy. Incremental games are often large optimization problems - above all else, the actual gameplay the player is performing is deciding what to do next. The consequences of wrong decisions are typically more lenient in incremental games - such as just not making optimal progress - but they certainly get complex.

So if we accept the premise that incrementals could fall under strategy, we still need to define what makes a strategy game an incremental versus some other strategy sub-genre. This is a bit tricky due to one particular sub-genre of strategy games: Factory Builders.

Factory builders, such as Factorio or Satisfactory, are games about gaining ever increasing resources, optimizing production, and expanding more and more. That... sounds pretty similar, doesn't it? In fact, there's been some debate on whether factory builders would fall under the "incremental" umbrella. I think it's safe to say the two are certainly related, and probably have quite a bit of overlap in playerbase.

Roguelites as Incrementals?

Earlier on, I mentioned reset mechanics shouldn't be used in the definition because that could make all roguelites incrementals... But what if it does? A lot of incrementals can be described as games with a strong sense of progression, often with layers of meta-progression. Roguelites fit that bill to a T. What would make roguelites not incremental? I honestly don't think there's a good explanation here, but many fans of incremental games will state they do believe the two genres to be unrelated, even if there's a significant overlap between their player bases due to having similar appealing traits.

At this point, it'd be appropriate to consider what part of the definition of roguelites precludes them from also being incrementals, but that reveals a new problem: What are roguelites? They're usually defined as rogue_likes with meta-progression, but that just pushes the problem back a step: Incrementals aren't the only genre to have difficulties defining themselves, it seems! Roguelikes are another genre where the community argues over the formal definition of their genre, although that means we can borrow from their process of coming to a consensus, and maybe come across a viable definition for incremental games.

The Berlin Interpretation

By far the most popular way of defining roguelikes is the "Berlin Interpretation", which acknowledged the diversity of games within the genre and argued the definition should not be based on any ideals about what the genre ought to be, but rather defined by "its canon". They argued there are a handful of games that can be used to define the canon for roguelikes, and from those games, a list of factors can be derived to determine a game's "roguelikeness". The more factors a game has, the more of a roguelike it is. This strategy is very lenient, allowing a game to not present any specific factor so long as it shows enough, and accounts for the blurriness of any genre definition by not explicitly stating how many factors a game must have to qualify as a definite roguelike.

I believe this strategy for defining genres can be applied to other genres as well. A handful of games can be argued to be the incremental games canon, and a list of factors derived from them can be used to judge any game based on its "incrementalness". I'll propose such a canon and list of factors here, but by no means should it be considered the end-all-be-all.

Note: The "Temple of the roguelike", an authority within the genre, has since replaced the Berlin Interpretation with a new set of factors here: https://blog.roguetemple.com/what-is-a-traditional-roguelike/

The Incremental Games Canon

Alright, time to get controversial. Up til now, I've been trying my best to stay objective and analytical, but now it's time to start making some opinionated decisions. Here is a list of games I think could justifiably make up an Incremental Games Canon:

I chose a variety of games here, biasing towards newer games, purposefully to avoid making a narrow or "traditional" definition. The genre is growing and shouldn't be constrained by the traits of the early popular titles. A lot of these could easily be replaced with other games that are mechanically congruent, so ultimately I'm sure if you asked 10 people for their canon list you'd just get 10 different answers, but I think this should sufficiently allow us to determine what factors make a game have higher "incrementalness".

The Paradigm Shift

The Paradigm Shift is probably the highest possible value factor for an incremental. It's so common that for a while people referred to incrementals that exhibit this trait as "unfolding" games, to the point of trying to replace the term incremental due to their popularity. Paradigm shifts refer to when the gameplay significantly changes. There are too many examples to list here, but notably, every single reset mechanic is typically going to be a paradigm shift. Examples of games with paradigm shifts that aren't tied to reset mechanics include Universal Paperclips and A Dark Room.

There are many reasons for the appeal of paradigm shifts. Oftentimes each mechanic builds on top of the existing mechanics, increasing the complexity of the game in steps so the player can follow along. They provide a sense of mystery, with the player anticipating what will happen next. They shake up the gameplay before it gets too stale - allowing the game to entertain for longer before the sense of Guide to Incrementals/What is Content? dissipates. Of the canon games selected above, I would argue every single one contains a paradigm shift (although I could see someone disagreeing with that statement wrt Increlution).

I should take a moment to say that while I'm hyping up this specific factor, we cannot just reduce the genre definition to "does it have paradigm shifts". Many games have paradigm shifts that are not incremental, so it's just an indicator of incrementalness. Additionally, it can become quite hard to determine how large of a shift is a "paradigm" shift. Take, for example, any game with a skill tree. In some games, each skill node might have a large impact on how you play with the game, and qualify as a paradigm shift for some players. In other games, each skill node might just be a small percentage modifier on some stat that doesn't really impact much more than a slight bias towards an already established mechanic that's newly buffed. Every single canon game may show that it's common amongst incremental games, but could just as easily indicate that they're common in games in general.

High-Value Factors

I won't take as long to discuss the high and low-value factors, as you've already seen most of them brought up earlier on this page. As a reminder, a game does NOT need all of these to be an incremental game, but these are factors that each indicate a strong possibility the game is an incremental, so having several of these means they probably are. These factors apply to most of the canon incremental games.

"Pure UI" Display. Incrementals typically have a textual presentation of the game state - there isn't a visual representation of the entities within the game. The interface is closer to what would be just the UI of a game in another genre or the control panel of a plane. If there is a visual representation, the player is often still interacting with non-diegetic game elements.

Reduced Consequences. Incrementals tend to have reduced repurcussions for misplaying. They very rarely have fail states, where often the largest consequence is simply not progressing - never losing progress.

Optimization Problems. The predominant gameplay of incrementals is typically solving optimization problems, from deciding which purchase to save up for to reasoning and deciding between different mutually exclusive options the game presents.

Resource Management. Incrementals tend to have a lot of resources within the game to keep track of.

Low-Value Factors

These are low-value factors, meaning they aren't as strongly correlated with incremental games. Incremental games may have none of these, and non-incrementals may have several of these - if a game only has low-value factors, they're probably not an incremental.

Fast Numeric Growth. Numbers in incremental games tend to grow faster than in other genres. There are more instances of superlinear growth. The larger the numbers get, the stronger of a signal this factor is.

Automation. As an incremental game progresses, the player often no longer has to deal with earlier mechanics, by having them either happen automatically or otherwise be replaced with an alternative that requires less player interaction.

Goal-Oriented. Incrementals are often heavily reliant on extrinsic motivation to guide the player. Typically this is through some sort of in-game goal to work towards, such as a certain amount of a resource being required to unlock or purchase something new.

Waiting is a Mechanic. In incremental games, the player may come across times where there is no action they can take, and the game will progress automatically instead. The player must wait for some amount of this automatic progress to occur before they can resume interaction with the game.

Are Roguelites Incrementals?

Having made our variation of the Berlin Interpretation for incremental games, we can compare it to the Berlin Interpretation to determine if there's enough overlap that any game that "passes" the Berlin Interpretation would also pass the incremental variant. That is to say, whether any roguelite would also be considered an incremental game.

The meta-progression of an incremental game could arguably be considered a paradigm shift, and certainly adds some resource management. Goal-oriented would probably also apply. I think anything other than those would be a stretch, and in my opinion that just isn't enough to qualify. To be totally honest, I was never expecting to conclude otherwise though 😉

Sub-Genres

There are some trends in incremental games that go beyond just being a commonly used mechanic, such that they deeply affect the rest of the game design. These trends can be used to determine sub-genres within the incremental games umbrella:

Loops games are a sub-genre defined by having a core mechanic related to a loop, where the player is deciding the actions taken per loop. Notable examples include Idle Loops, Stuck in Time, Cavernous II, and Increlution. You may also argue Groundhog Life and Progress Knight fall into this sub-genre.

ITRTG-like games are a sub-genre defined by having a core mechanic based on clearing increasingly difficult battles and often tend to have a lot of different mechanics to become progressively stronger. Notable examples include Idling to Rule the Gods, NGU Idle, and Wizard and Minion Idle.

Polynomial Growth games are a sub-genre defined by having a core mechanic related to a higher degree polynomial. Notable examples include the base layer of Antimatter Dimensions and Swarm Simulator.

Upgrades Games is a category popular on flash games websites that featured games focused on buying upgrades that would allow you to attain more currency in some sort of minigame that would earn you more money to buy more upgrades, which I'd argue now belong under the fold of incremental games. Notable examples include the Learn to Fly series and Upgrade Complete.

Cultivation RPGs are a genre of games, books, and anime popular in China that center around being in a fantasy world with characters getting stronger over time. While few of them get translated into English, a fan of incremental games may find the available games interesting.

',65),y=JSON.parse('{"title":"Guide to Incrementals/Defining the Genre","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/defining-the-genre","title":"Guide to Incrementals/Defining the Genre","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/defining-the-genre/index.md","filePath":"garden/guide-to-incrementals/defining-the-genre/index.md"}'),c={name:"garden/guide-to-incrementals/defining-the-genre/index.md"},w=Object.assign(c,{setup(u){const a=n();return(d,p)=>(l(),o("div",null,[h,e("p",null,[i("3429 words, ~19 minute read. "),e("span",{innerHTML:t(r)[`site/${t(a).page.value.relativePath}`]},null,8,m)]),g]))}});export{y as __pageData,w as default}; diff --git a/assets/garden_guide-to-incrementals_defining-the-genre_index.md.CnpSquU9.lean.js b/assets/garden_guide-to-incrementals_defining-the-genre_index.md.DwYrHYrF.lean.js similarity index 80% rename from assets/garden_guide-to-incrementals_defining-the-genre_index.md.CnpSquU9.lean.js rename to assets/garden_guide-to-incrementals_defining-the-genre_index.md.DwYrHYrF.lean.js index a9d29d88..c000004c 100644 --- a/assets/garden_guide-to-incrementals_defining-the-genre_index.md.CnpSquU9.lean.js +++ b/assets/garden_guide-to-incrementals_defining-the-genre_index.md.DwYrHYrF.lean.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as o,j as e,a as i,k as t,ag as s,o as l}from"./chunks/framework.VBE0TPts.js";const h=e("h1",{class:"p-name"},"Guide to Incrementals___Defining the Genre",-1),m=["innerHTML"],g=s("",65),y=JSON.parse('{"title":"Guide to Incrementals/Defining the Genre","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/defining-the-genre","title":"Guide to Incrementals/Defining the Genre","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/defining-the-genre/index.md","filePath":"garden/guide-to-incrementals/defining-the-genre/index.md"}'),c={name:"garden/guide-to-incrementals/defining-the-genre/index.md"},w=Object.assign(c,{setup(u){const a=n();return(d,p)=>(l(),o("div",null,[h,e("p",null,[i("3429 words, ~19 minute read. "),e("span",{innerHTML:t(r)[`site/${t(a).page.value.relativePath}`]},null,8,m)]),g]))}});export{y as __pageData,w as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as o,Q as e,K as i,u as t,ag as s,p as l}from"./chunks/framework.DvHfxfnp.js";const h=e("h1",{class:"p-name"},"Guide to Incrementals___Defining the Genre",-1),m=["innerHTML"],g=s("",65),y=JSON.parse('{"title":"Guide to Incrementals/Defining the Genre","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/defining-the-genre","title":"Guide to Incrementals/Defining the Genre","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/defining-the-genre/index.md","filePath":"garden/guide-to-incrementals/defining-the-genre/index.md"}'),c={name:"garden/guide-to-incrementals/defining-the-genre/index.md"},w=Object.assign(c,{setup(u){const a=n();return(d,p)=>(l(),o("div",null,[h,e("p",null,[i("3429 words, ~19 minute read. "),e("span",{innerHTML:t(r)[`site/${t(a).page.value.relativePath}`]},null,8,m)]),g]))}});export{y as __pageData,w as default}; diff --git a/assets/garden_guide-to-incrementals_index.md.DEblpv1O.js b/assets/garden_guide-to-incrementals_index.md.BQydin-1.js similarity index 94% rename from assets/garden_guide-to-incrementals_index.md.DEblpv1O.js rename to assets/garden_guide-to-incrementals_index.md.BQydin-1.js index daeb4de3..8d18b60f 100644 --- a/assets/garden_guide-to-incrementals_index.md.DEblpv1O.js +++ b/assets/garden_guide-to-incrementals_index.md.BQydin-1.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as i,c as o,j as e,a as r,k as a,ag as s,o as l}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals",-1),m=["innerHTML"],c=s('
Referenced by:My Personal Website

This is a comprehensive guide to Incremental Games, a genre of video games. It will explore defining the genre, why it's appealing, and how to design and build your own incremental game. Along the way will be interactive examples, snippets from other creators, and relevant material to contextualize everything.

Note: This is an incomplete document. I want to keep adding opinions and opposing views from other incremental games developers, and add interactive examples to illustrate various points regarding game design and balancing. Consider this a living document - and see the changelog at the end.

Why am I making this?

That's a good question! What authority do I have to be making this guide? I haven't made the best incremental games, nor the most incremental games, certainly not the most popular ones either. But I do have some formal education in game development, know a lot of incremental game devs (as well as other game devs), and have a passionate interest in ludology, classifying genres, etc. I've also made a couple of incremental games) myself.

If you have any additional questions about my credentials or anything on this site, feel free to reach out!

Ludology

Making an Incremental

',11),y=JSON.parse('{"title":"Guide to Incrementals","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals","title":"Guide to Incrementals","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/index.md","filePath":"garden/guide-to-incrementals/index.md"}'),g={name:"garden/guide-to-incrementals/index.md"},v=Object.assign(g,{setup(h){const t=i();return(u,p)=>(l(),o("div",null,[d,e("p",null,[r("230 words, ~1 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),c]))}});export{y as __pageData,v as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as o,Q as e,K as r,u as a,ag as s,p as l}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals",-1),m=["innerHTML"],c=s('
Referenced by:My Personal Website

This is a comprehensive guide to Incremental Games, a genre of video games. It will explore defining the genre, why it's appealing, and how to design and build your own incremental game. Along the way will be interactive examples, snippets from other creators, and relevant material to contextualize everything.

Note: This is an incomplete document. I want to keep adding opinions and opposing views from other incremental games developers, and add interactive examples to illustrate various points regarding game design and balancing. Consider this a living document - and see the changelog at the end.

Why am I making this?

That's a good question! What authority do I have to be making this guide? I haven't made the best incremental games, nor the most incremental games, certainly not the most popular ones either. But I do have some formal education in game development, know a lot of incremental game devs (as well as other game devs), and have a passionate interest in ludology, classifying genres, etc. I've also made a couple of incremental games) myself.

If you have any additional questions about my credentials or anything on this site, feel free to reach out!

Ludology

Making an Incremental

',11),y=JSON.parse('{"title":"Guide to Incrementals","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals","title":"Guide to Incrementals","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/index.md","filePath":"garden/guide-to-incrementals/index.md"}'),g={name:"garden/guide-to-incrementals/index.md"},v=Object.assign(g,{setup(h){const t=i();return(u,p)=>(l(),o("div",null,[d,e("p",null,[r("230 words, ~1 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),c]))}});export{y as __pageData,v as default}; diff --git a/assets/garden_guide-to-incrementals_index.md.DEblpv1O.lean.js b/assets/garden_guide-to-incrementals_index.md.BQydin-1.lean.js similarity index 76% rename from assets/garden_guide-to-incrementals_index.md.DEblpv1O.lean.js rename to assets/garden_guide-to-incrementals_index.md.BQydin-1.lean.js index 25b7ea44..fbc1bb95 100644 --- a/assets/garden_guide-to-incrementals_index.md.DEblpv1O.lean.js +++ b/assets/garden_guide-to-incrementals_index.md.BQydin-1.lean.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as i,c as o,j as e,a as r,k as a,ag as s,o as l}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals",-1),m=["innerHTML"],c=s("",11),y=JSON.parse('{"title":"Guide to Incrementals","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals","title":"Guide to Incrementals","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/index.md","filePath":"garden/guide-to-incrementals/index.md"}'),g={name:"garden/guide-to-incrementals/index.md"},v=Object.assign(g,{setup(h){const t=i();return(u,p)=>(l(),o("div",null,[d,e("p",null,[r("230 words, ~1 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),c]))}});export{y as __pageData,v as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as o,Q as e,K as r,u as a,ag as s,p as l}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals",-1),m=["innerHTML"],c=s("",11),y=JSON.parse('{"title":"Guide to Incrementals","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals","title":"Guide to Incrementals","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/index.md","filePath":"garden/guide-to-incrementals/index.md"}'),g={name:"garden/guide-to-incrementals/index.md"},v=Object.assign(g,{setup(h){const t=i();return(u,p)=>(l(),o("div",null,[d,e("p",null,[r("230 words, ~1 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),c]))}});export{y as __pageData,v as default}; diff --git a/assets/garden_guide-to-incrementals_navigating-criticism_index.md.CvIMd3Io.js b/assets/garden_guide-to-incrementals_navigating-criticism_index.md.Cma7NB5L.js similarity index 97% rename from assets/garden_guide-to-incrementals_navigating-criticism_index.md.CvIMd3Io.js rename to assets/garden_guide-to-incrementals_navigating-criticism_index.md.Cma7NB5L.js index 7c2bf3fb..ea10a27b 100644 --- a/assets/garden_guide-to-incrementals_navigating-criticism_index.md.CvIMd3Io.js +++ b/assets/garden_guide-to-incrementals_navigating-criticism_index.md.Cma7NB5L.js @@ -1 +1 @@ -import{d as i}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as o,j as e,a as r,k as t,ag as s,o as l}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals___Navigating Criticism",-1),c=["innerHTML"],u=s('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

Developing games is fun and exciting and teaches a lot of wonderful skills - I enthusiastically encourage anyone with an interest in game development to try it out - and incremental games are a wonderful way to get started. However, there are many challenges young and inexperienced developers have to face, and I think the hardest one - harder than coding, debugging, balancing, etc. - is handling criticism. When you put your heart and soul into a game it is natural to feel very vulnerable. While I think there's a lot communities can do to ensure they're welcoming, positive and constructive with their criticisms, inevitably you will eventually read some, and potentially a lot, of comments that can deeply affect you. No one is immune to this, from young incremental game developers to the largest content creators you can think of. That's why it's important to be able to process and navigate criticism, because ultimately collecting feedback is essential to the journey to becoming a better developer. On this page, we'll explore how to embrace criticism, grow from it, and continue to post your games publicly with confidence.

Reading Feedback

Game development is a skill that takes time and practice to get truly great at. Criticism and other constructive feedback are vital to continually improving. It's useful to look at the criticism as solely a tool for improving this game and future games - that is to say, it should never be used against you as a person. Insults towards the developer(s) themselves are never okay and should not be allowed within whatever community you're sharing your works in. If you do come across a comment you interpret as an attack upon your person, you should report it. For other negative comments, try not to internalize them; instead, focus on improving the game. By distancing your own identity from your work emotionally, you can better analyze the game and use the feedback to your advantage.

Not all feedback is made equal, and you don't need to feel compelled to read and obey every piece of feedback you receive. Learn to distinguish between constructive feedback and unhelpful comments. Constructive feedback typically offers specific suggestions for improvement, while unhelpful comments are often vague or hurtful. Prioritize the former and disregard the latter. That said, most feedback you get will not be from game developers, so take specific suggestions with a grain of salt. Determine the actual problem they're experiencing, and design what you believe the best solution to that problem would be, regardless if that's the specific solution the player asked for. And keep in mind, due to different player preferences you'll never satisfy everyone, and you don't need to. Ultimately if even just you find the game fun, then that's a success.

Seeking Feedback

When deciding where to share your game, consider the type of players you anticipate getting, and the kind of feedback you can anticipate receiving. Different communities will have different levels of support for learning developers, and certain communities may prefer certain types of games or mechanics. It's important to get a diverse set of feedback focused on players you think will enjoy the specific game you're making.

Collecting feedback from other game developers is incredibly helpful. They've trained themselves to recognize good and bad game design and how to articulate the differences, and from my experience are much more likely to leave positive and constructive comments since they've been in your shoes before! They understand the struggles and can offer guidance and emotional support.

Responding to Feedback

Negative feedback can naturally feel like an attack, and it's okay to get angry. However, lashing back is never the appropriate response. It's best to cool off IRL, and keep in mind all the positive comments you've received. There's a concept in Psychology called negative bias that explains how negative feedback tends to stick with us much more prominently than positive feedback, so it's useful to regularly remind yourself of all the positive feedback you've received. Celebrate your successes, no matter how small they may seem - getting a game to a state you can publicly share it with people is an accomplishment in and of itself!

Remember your passion and your initial reasons for getting into game development. The journey will have its ups and downs, but staying true to your vision and passion will keep you motivated.

',12),v=JSON.parse('{"title":"Guide to Incrementals/Navigating Criticism","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/navigating-criticism","title":"Guide to Incrementals/Navigating Criticism","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/navigating-criticism/index.md","filePath":"garden/guide-to-incrementals/navigating-criticism/index.md"}'),m={name:"garden/guide-to-incrementals/navigating-criticism/index.md"},b=Object.assign(m,{setup(h){const a=n();return(g,p)=>(l(),o("div",null,[d,e("p",null,[r("747 words, ~4 minute read. "),e("span",{innerHTML:t(i)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),u]))}});export{v as __pageData,b as default}; +import{d as i}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as o,Q as e,K as r,u as t,ag as s,p as l}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals___Navigating Criticism",-1),c=["innerHTML"],u=s('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

Developing games is fun and exciting and teaches a lot of wonderful skills - I enthusiastically encourage anyone with an interest in game development to try it out - and incremental games are a wonderful way to get started. However, there are many challenges young and inexperienced developers have to face, and I think the hardest one - harder than coding, debugging, balancing, etc. - is handling criticism. When you put your heart and soul into a game it is natural to feel very vulnerable. While I think there's a lot communities can do to ensure they're welcoming, positive and constructive with their criticisms, inevitably you will eventually read some, and potentially a lot, of comments that can deeply affect you. No one is immune to this, from young incremental game developers to the largest content creators you can think of. That's why it's important to be able to process and navigate criticism, because ultimately collecting feedback is essential to the journey to becoming a better developer. On this page, we'll explore how to embrace criticism, grow from it, and continue to post your games publicly with confidence.

Reading Feedback

Game development is a skill that takes time and practice to get truly great at. Criticism and other constructive feedback are vital to continually improving. It's useful to look at the criticism as solely a tool for improving this game and future games - that is to say, it should never be used against you as a person. Insults towards the developer(s) themselves are never okay and should not be allowed within whatever community you're sharing your works in. If you do come across a comment you interpret as an attack upon your person, you should report it. For other negative comments, try not to internalize them; instead, focus on improving the game. By distancing your own identity from your work emotionally, you can better analyze the game and use the feedback to your advantage.

Not all feedback is made equal, and you don't need to feel compelled to read and obey every piece of feedback you receive. Learn to distinguish between constructive feedback and unhelpful comments. Constructive feedback typically offers specific suggestions for improvement, while unhelpful comments are often vague or hurtful. Prioritize the former and disregard the latter. That said, most feedback you get will not be from game developers, so take specific suggestions with a grain of salt. Determine the actual problem they're experiencing, and design what you believe the best solution to that problem would be, regardless if that's the specific solution the player asked for. And keep in mind, due to different player preferences you'll never satisfy everyone, and you don't need to. Ultimately if even just you find the game fun, then that's a success.

Seeking Feedback

When deciding where to share your game, consider the type of players you anticipate getting, and the kind of feedback you can anticipate receiving. Different communities will have different levels of support for learning developers, and certain communities may prefer certain types of games or mechanics. It's important to get a diverse set of feedback focused on players you think will enjoy the specific game you're making.

Collecting feedback from other game developers is incredibly helpful. They've trained themselves to recognize good and bad game design and how to articulate the differences, and from my experience are much more likely to leave positive and constructive comments since they've been in your shoes before! They understand the struggles and can offer guidance and emotional support.

Responding to Feedback

Negative feedback can naturally feel like an attack, and it's okay to get angry. However, lashing back is never the appropriate response. It's best to cool off IRL, and keep in mind all the positive comments you've received. There's a concept in Psychology called negative bias that explains how negative feedback tends to stick with us much more prominently than positive feedback, so it's useful to regularly remind yourself of all the positive feedback you've received. Celebrate your successes, no matter how small they may seem - getting a game to a state you can publicly share it with people is an accomplishment in and of itself!

Remember your passion and your initial reasons for getting into game development. The journey will have its ups and downs, but staying true to your vision and passion will keep you motivated.

',12),v=JSON.parse('{"title":"Guide to Incrementals/Navigating Criticism","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/navigating-criticism","title":"Guide to Incrementals/Navigating Criticism","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/navigating-criticism/index.md","filePath":"garden/guide-to-incrementals/navigating-criticism/index.md"}'),m={name:"garden/guide-to-incrementals/navigating-criticism/index.md"},b=Object.assign(m,{setup(h){const a=n();return(g,p)=>(l(),o("div",null,[d,e("p",null,[r("747 words, ~4 minute read. "),e("span",{innerHTML:t(i)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),u]))}});export{v as __pageData,b as default}; diff --git a/assets/garden_guide-to-incrementals_navigating-criticism_index.md.CvIMd3Io.lean.js b/assets/garden_guide-to-incrementals_navigating-criticism_index.md.Cma7NB5L.lean.js similarity index 80% rename from assets/garden_guide-to-incrementals_navigating-criticism_index.md.CvIMd3Io.lean.js rename to assets/garden_guide-to-incrementals_navigating-criticism_index.md.Cma7NB5L.lean.js index 60334d18..deb981aa 100644 --- a/assets/garden_guide-to-incrementals_navigating-criticism_index.md.CvIMd3Io.lean.js +++ b/assets/garden_guide-to-incrementals_navigating-criticism_index.md.Cma7NB5L.lean.js @@ -1 +1 @@ -import{d as i}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as o,j as e,a as r,k as t,ag as s,o as l}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals___Navigating Criticism",-1),c=["innerHTML"],u=s("",12),v=JSON.parse('{"title":"Guide to Incrementals/Navigating Criticism","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/navigating-criticism","title":"Guide to Incrementals/Navigating Criticism","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/navigating-criticism/index.md","filePath":"garden/guide-to-incrementals/navigating-criticism/index.md"}'),m={name:"garden/guide-to-incrementals/navigating-criticism/index.md"},b=Object.assign(m,{setup(h){const a=n();return(g,p)=>(l(),o("div",null,[d,e("p",null,[r("747 words, ~4 minute read. "),e("span",{innerHTML:t(i)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),u]))}});export{v as __pageData,b as default}; +import{d as i}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as o,Q as e,K as r,u as t,ag as s,p as l}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals___Navigating Criticism",-1),c=["innerHTML"],u=s("",12),v=JSON.parse('{"title":"Guide to Incrementals/Navigating Criticism","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/navigating-criticism","title":"Guide to Incrementals/Navigating Criticism","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/navigating-criticism/index.md","filePath":"garden/guide-to-incrementals/navigating-criticism/index.md"}'),m={name:"garden/guide-to-incrementals/navigating-criticism/index.md"},b=Object.assign(m,{setup(h){const a=n();return(g,p)=>(l(),o("div",null,[d,e("p",null,[r("747 words, ~4 minute read. "),e("span",{innerHTML:t(i)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),u]))}});export{v as __pageData,b as default}; diff --git a/assets/garden_guide-to-incrementals_what-is-content_index.md.BdP15SmB.js b/assets/garden_guide-to-incrementals_what-is-content_index.md.DXGnOHrD.js similarity index 98% rename from assets/garden_guide-to-incrementals_what-is-content_index.md.BdP15SmB.js rename to assets/garden_guide-to-incrementals_what-is-content_index.md.DXGnOHrD.js index 9b27f139..30275f2e 100644 --- a/assets/garden_guide-to-incrementals_what-is-content_index.md.BdP15SmB.js +++ b/assets/garden_guide-to-incrementals_what-is-content_index.md.DXGnOHrD.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as o,c as i,j as e,a as s,k as t,ag as r,o as h}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"Guide to Incrementals___What is Content?",-1),c=["innerHTML"],u=r('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

If you've been in the incremental games community for any amount of time, you'll quickly find the number one thing players want is content. They want as much of it as possible! The most popular incremental games have tons of content, so they just keep stretching on and on and on, introducing mechanic after mechanic, and players love it. In fact, players seem to value the amount of content over the quality of any specific content. However, there's a bit of a lack of understanding concerning what content is, and I'd like to explore what counts as content, and how we measure it. As a baseline definition, I think "content" can just be described as the parts of the game that engage the player, but to truly understand it we need to contextualize what that means and how it affects the gameplay experience.

To clarify the purpose of this page, my goal is not to get (too) nitpicky or to attack games with "low content". There's nothing wrong with short / low-content games - I'm quite a big fan of those games myself! This is mostly targeted toward those who ask for content and settle for "long" games, and those who want to provide content but want to make sure they're not just artificially inflating the game. Ultimately, I suppose the goal is to just reduce the amount of artificially inflated content for the sake of having a "longer" game.

Interaction

I think it should be a fairly non-controversial opinion that time spent solely waiting should not count towards content. That is not including the time reading various effects or making decisions in your head, but rather time spent waiting for a condition to be met so you can re-engage with the game.

That is not to say games should necessarily try to minimize this time. Plenty of games lead towards more infrequent interaction and still get popular. In fact, these games appeal to many gamers who want to have something to check up on in between bursts of working on some other activity. These games seem to have fallen slightly out of fashion amongst modern incremental games, but they're still fully valid. The point I'm trying to make here is just that this time is not content. As an extreme example, a game with no interactions and just a counter that goes up every second could safely be said to have 0 content beyond the time it takes to understand what's going on. If it has a list of "goals" to hit, then the time understanding those goals and a short time after achieving each one could be considered content, but not the idle times in between.

Let's take a look at the opposite end of the spectrum - interaction that is so frequent as to become mindless. This is any mechanic where you need to spam-click something to progress. This may be a more controversial take, but I do not believe this constitutes content either. It does not engage the player, because each consecutive click blends together and they do not individually change the gameplay experience. That is to say, a single click and 100 clicks are not meaningfully different in terms of engaging the player. I'd go as far as to say clicking 100 times would be actively worse, as it's artificially delaying the next piece of actual content, alongside the issues of accessibility and potentially causing RSI.

Repeatable Purchases

Imagine an entity in a game that you can purchase multiple times, each time it performs the same thing but for a higher cost. These are incredibly common, from the buildings in cookie clicker to the units in swarm sim to the IP and EP multipliers in antimatter dimensions. However, how much content is each specific purchase? Is it content beyond the first purchase? Does it have diminishing returns? What if you are oscillating between two different repeatable purchases? How much content is lost when you automate) away a repeatable purchase?

I don't want to take too harsh a stance against repeatable purchases. They're useful tools and can be used in a myriad of interesting ways. I feel they do become "stale" or less meaningful content over time, and this happens exponentially quickly the more frequently it can be purchased. A classic example that I believe goes too far is the IP/EP multipliers in Antimatter Dimensions. I would go as far as to say they are a chore and do not provide any meaningful content after you've bought them a couple of times. It's a method for inflating numbers (effectively making every OOM a 5x step instead of 10x), that punishes the player progression-wise whenever they forget to max it again, and eventually gets automated away as a reward to the player for making enough progress.

Just to voice the other side of this argument, Acamaeda defended the IP multiplier as giving the player a "good" upgrade every OOM. I can understand that to a point and need to clarify I'm mainly criticizing IP/EP multipliers after they've been introduced for a while. In fact, I would defend the multipliers for a short while after they're introduced using the same logic I would use to defend normal dimensions as repeatable purchases, at least pre-infinity. There's "content" to be had in looking at what dimensions will become affordable next, and then choosing which to buy amongst those. The IP/EP multipliers, early into infinity or eternity respectively, provide another option that gets put into that mental queue of things to buy with each OOM reached - although the optimal order is often quite trivial and not particularly engaging.

The IP/EP multipliers are not the only repeatable purchase in antimatter dimensions I take offense to. The time dimensions are also a series of repeatable purchases, that are all so similar and static that it doesn't take long before you never need to put any thought into buying them, how much you're buying at once, or the order you buy them in - you just press max all and move on. The entire tab could've been just the max all button and it would not have made a difference beyond the start of the eternity layer. The normal dimensions technically have this problem as well, but since you're constantly getting antimatter the order feels like it has a larger impact and it's more meaningful content, right up until they're automated away. Infinity dimensions are a compromise between the two, so I'm highlighting time dimensions here as the most egregious.

Following Instructions

We're getting more and more controversial as we go along! Let's talk about how linear content is not content now (in some circumstances). A trend in incremental games is adding difficulty by adding a web of effects that abstract the true change you can expect from any specific purchase or decision you make. If a game is both linear and sufficiently abstracts the effect of player decisions, then the player will no longer be engaging with the content - they'll simply be clicking on things as they become available. This isn't necessarily a bad thing, as plenty of players don't mind this style of gameplay, but I'd argue once you reach a point where players don't bother reading the effects, those interactions are no longer truly content. Note that unlike the previous qualifiers mentioned, this qualifier is based on the player, and therefore subjective. In effect, it's a spectrum where the more complicated the web of effects becomes, the more likely it is to disengage the player.

This over-complicatedness leading to disengaging the player can also happen from non-linear gameplay. If the web of effects becomes sufficiently complicated and finding the optimal progression route too time-consuming to discover, players will seek out guides from other players who've completed the game. The second they do this, the game effectively becomes linearly following the instructions of the guide and all the above criticisms apply. Similarly to as before, though, this is a spectrum and not everyone will seek out a guide at the same level of difficulty.

Automation

Automation is a staple of the genre, but it has certain implications for the design of the game. Why, when new content is introduced, must the older content be automated away - why is it a chore and it feels rewarding to not have to do it again? Why does the new mechanic have such appeal if we know it too will just be automated away later on, and we'll be happy when that happens? It honestly begs the question of why this framework of introducing content and automating the old content is even enjoyable - and nearly nonexistent in other genres. You're not going to reach a point in a platformer game where they just automate the jumping part - that's the core mechanic! Instead, platformers either add new mechanics that build on the core mechanic or at least re-contextualize the core mechanic. However, in incremental games new content very frequently means replacing older content, as opposed to augmenting it.

Admittedly, the above paragraph ignores the obvious answer that separates incremental games in this regard. These mechanics become chores as their frequency increases. The frequency increases to give a sense of progression, and automation is seen as a reward because it now manages what was becoming unmanageable. The new content then comes in and continues the loop to give a stronger sense of progression. That's all good and a fine justification for automating content instead of building upon the base mechanic. It's also much easier to design, as each layer essentially lets you start over instead of needing to think of ideas that conform to the original core mechanic.

So, what's the problem? Even if this trend is justified and easy to implement, there are some other effects it has on the game design. First off, and this is probably a neutral point, incremental games with this cycle of replacing old mechanics with new ones trend towards more and more abstract and further away from any narrative throughline as they add layers. There are only so many justifications for resetting progress, so if a game wants to have several of these layers they're inevitably going to become generic or increasingly loosely associated with the original content. It's most unfortunate, in my opinion when an interesting or innovative core mechanic gets fully automated once a generic "prestige" layer is unlocked.

A recent example is Really Grass Cutting Incremental, an incremental game about cutting grass (although I'm really criticizing the Roblox game it's based on). Except, it doesn't continue to be about cutting grass. After you buy enough upgrades to increase your grass cutting and level up sufficiently you "prestige", an abstract term that in this case means you reset all your progress to get some currency to buy upgrades that do the same things as the original upgrades, but these won't reset on future prestiges. You'll eventually be able to "crystallize", which means you reset all your progress to get some currency to buy upgrades that do the same things as the original upgrades (and a couple of new ones) and won't reset on future crystallizes. Fine. You'll progress a bit, complete some challenges, and finally get to... grasshop? Grasshopping is this mechanic where you reset all your progress to get some resource that isn't for buying upgrades - this time you just unlock different modifiers on everything based on their amount. You may have gotten the point by now, but there are also "steelie" resets which give you steel for some reason, before unlocking a factory with various machines - none of which are directly tied to cutting grass, and start gathering things like oil and reset for rocket parts and reset to go to space and so on and so on. Throughout all of this there is absolutely no narrative justification or throughline for the direction the game is going, or why cutting grass is still relevant when we're collecting things like rocket parts. I may be going a little hard on GCI, but it is far from alone.

Tips for Developers

If you're a developer, by this point you should have a pretty decent idea of how to create "true" content in your game. Here are some other specific tips I'd suggest:

An upgrade that simply unlocks another upgrade trivially isn't content. However, many games have an upgrade that just unlocks a feature, which then has a wait or other requirements before it can be used. Try to make sure when you unlock a feature, there is immediately something to do with the feature - for example, perhaps give them a small amount of the new currency it unlocks, if applicable.

If you don't have a large web of effects, and can definitively say the impact of a purchase is to multiply the gain of the cost currency by N, and the next purchase costs N times the amount of that same currency, then this purchase effectively made no difference and it may have made more sense to just go directly to the next upgrade. That said, having effects based on things like the number of purchases made will quickly invalidate this tip.

',25),b=JSON.parse('{"title":"Guide to Incrementals/What is Content?","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/what-is-content-","title":"Guide to Incrementals/What is Content?","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/what-is-content/index.md","filePath":"garden/guide-to-incrementals/what-is-content/index.md"}'),m={name:"garden/guide-to-incrementals/what-is-content/index.md"},w=Object.assign(m,{setup(d){const a=o();return(g,p)=>(h(),i("div",null,[l,e("p",null,[s("2092 words, ~11 minute read. "),e("span",{innerHTML:t(n)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),u]))}});export{b as __pageData,w as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as o,q as i,Q as e,K as s,u as t,ag as r,p as h}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"Guide to Incrementals___What is Content?",-1),c=["innerHTML"],u=r('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

If you've been in the incremental games community for any amount of time, you'll quickly find the number one thing players want is content. They want as much of it as possible! The most popular incremental games have tons of content, so they just keep stretching on and on and on, introducing mechanic after mechanic, and players love it. In fact, players seem to value the amount of content over the quality of any specific content. However, there's a bit of a lack of understanding concerning what content is, and I'd like to explore what counts as content, and how we measure it. As a baseline definition, I think "content" can just be described as the parts of the game that engage the player, but to truly understand it we need to contextualize what that means and how it affects the gameplay experience.

To clarify the purpose of this page, my goal is not to get (too) nitpicky or to attack games with "low content". There's nothing wrong with short / low-content games - I'm quite a big fan of those games myself! This is mostly targeted toward those who ask for content and settle for "long" games, and those who want to provide content but want to make sure they're not just artificially inflating the game. Ultimately, I suppose the goal is to just reduce the amount of artificially inflated content for the sake of having a "longer" game.

Interaction

I think it should be a fairly non-controversial opinion that time spent solely waiting should not count towards content. That is not including the time reading various effects or making decisions in your head, but rather time spent waiting for a condition to be met so you can re-engage with the game.

That is not to say games should necessarily try to minimize this time. Plenty of games lead towards more infrequent interaction and still get popular. In fact, these games appeal to many gamers who want to have something to check up on in between bursts of working on some other activity. These games seem to have fallen slightly out of fashion amongst modern incremental games, but they're still fully valid. The point I'm trying to make here is just that this time is not content. As an extreme example, a game with no interactions and just a counter that goes up every second could safely be said to have 0 content beyond the time it takes to understand what's going on. If it has a list of "goals" to hit, then the time understanding those goals and a short time after achieving each one could be considered content, but not the idle times in between.

Let's take a look at the opposite end of the spectrum - interaction that is so frequent as to become mindless. This is any mechanic where you need to spam-click something to progress. This may be a more controversial take, but I do not believe this constitutes content either. It does not engage the player, because each consecutive click blends together and they do not individually change the gameplay experience. That is to say, a single click and 100 clicks are not meaningfully different in terms of engaging the player. I'd go as far as to say clicking 100 times would be actively worse, as it's artificially delaying the next piece of actual content, alongside the issues of accessibility and potentially causing RSI.

Repeatable Purchases

Imagine an entity in a game that you can purchase multiple times, each time it performs the same thing but for a higher cost. These are incredibly common, from the buildings in cookie clicker to the units in swarm sim to the IP and EP multipliers in antimatter dimensions. However, how much content is each specific purchase? Is it content beyond the first purchase? Does it have diminishing returns? What if you are oscillating between two different repeatable purchases? How much content is lost when you automate) away a repeatable purchase?

I don't want to take too harsh a stance against repeatable purchases. They're useful tools and can be used in a myriad of interesting ways. I feel they do become "stale" or less meaningful content over time, and this happens exponentially quickly the more frequently it can be purchased. A classic example that I believe goes too far is the IP/EP multipliers in Antimatter Dimensions. I would go as far as to say they are a chore and do not provide any meaningful content after you've bought them a couple of times. It's a method for inflating numbers (effectively making every OOM a 5x step instead of 10x), that punishes the player progression-wise whenever they forget to max it again, and eventually gets automated away as a reward to the player for making enough progress.

Just to voice the other side of this argument, Acamaeda defended the IP multiplier as giving the player a "good" upgrade every OOM. I can understand that to a point and need to clarify I'm mainly criticizing IP/EP multipliers after they've been introduced for a while. In fact, I would defend the multipliers for a short while after they're introduced using the same logic I would use to defend normal dimensions as repeatable purchases, at least pre-infinity. There's "content" to be had in looking at what dimensions will become affordable next, and then choosing which to buy amongst those. The IP/EP multipliers, early into infinity or eternity respectively, provide another option that gets put into that mental queue of things to buy with each OOM reached - although the optimal order is often quite trivial and not particularly engaging.

The IP/EP multipliers are not the only repeatable purchase in antimatter dimensions I take offense to. The time dimensions are also a series of repeatable purchases, that are all so similar and static that it doesn't take long before you never need to put any thought into buying them, how much you're buying at once, or the order you buy them in - you just press max all and move on. The entire tab could've been just the max all button and it would not have made a difference beyond the start of the eternity layer. The normal dimensions technically have this problem as well, but since you're constantly getting antimatter the order feels like it has a larger impact and it's more meaningful content, right up until they're automated away. Infinity dimensions are a compromise between the two, so I'm highlighting time dimensions here as the most egregious.

Following Instructions

We're getting more and more controversial as we go along! Let's talk about how linear content is not content now (in some circumstances). A trend in incremental games is adding difficulty by adding a web of effects that abstract the true change you can expect from any specific purchase or decision you make. If a game is both linear and sufficiently abstracts the effect of player decisions, then the player will no longer be engaging with the content - they'll simply be clicking on things as they become available. This isn't necessarily a bad thing, as plenty of players don't mind this style of gameplay, but I'd argue once you reach a point where players don't bother reading the effects, those interactions are no longer truly content. Note that unlike the previous qualifiers mentioned, this qualifier is based on the player, and therefore subjective. In effect, it's a spectrum where the more complicated the web of effects becomes, the more likely it is to disengage the player.

This over-complicatedness leading to disengaging the player can also happen from non-linear gameplay. If the web of effects becomes sufficiently complicated and finding the optimal progression route too time-consuming to discover, players will seek out guides from other players who've completed the game. The second they do this, the game effectively becomes linearly following the instructions of the guide and all the above criticisms apply. Similarly to as before, though, this is a spectrum and not everyone will seek out a guide at the same level of difficulty.

Automation

Automation is a staple of the genre, but it has certain implications for the design of the game. Why, when new content is introduced, must the older content be automated away - why is it a chore and it feels rewarding to not have to do it again? Why does the new mechanic have such appeal if we know it too will just be automated away later on, and we'll be happy when that happens? It honestly begs the question of why this framework of introducing content and automating the old content is even enjoyable - and nearly nonexistent in other genres. You're not going to reach a point in a platformer game where they just automate the jumping part - that's the core mechanic! Instead, platformers either add new mechanics that build on the core mechanic or at least re-contextualize the core mechanic. However, in incremental games new content very frequently means replacing older content, as opposed to augmenting it.

Admittedly, the above paragraph ignores the obvious answer that separates incremental games in this regard. These mechanics become chores as their frequency increases. The frequency increases to give a sense of progression, and automation is seen as a reward because it now manages what was becoming unmanageable. The new content then comes in and continues the loop to give a stronger sense of progression. That's all good and a fine justification for automating content instead of building upon the base mechanic. It's also much easier to design, as each layer essentially lets you start over instead of needing to think of ideas that conform to the original core mechanic.

So, what's the problem? Even if this trend is justified and easy to implement, there are some other effects it has on the game design. First off, and this is probably a neutral point, incremental games with this cycle of replacing old mechanics with new ones trend towards more and more abstract and further away from any narrative throughline as they add layers. There are only so many justifications for resetting progress, so if a game wants to have several of these layers they're inevitably going to become generic or increasingly loosely associated with the original content. It's most unfortunate, in my opinion when an interesting or innovative core mechanic gets fully automated once a generic "prestige" layer is unlocked.

A recent example is Really Grass Cutting Incremental, an incremental game about cutting grass (although I'm really criticizing the Roblox game it's based on). Except, it doesn't continue to be about cutting grass. After you buy enough upgrades to increase your grass cutting and level up sufficiently you "prestige", an abstract term that in this case means you reset all your progress to get some currency to buy upgrades that do the same things as the original upgrades, but these won't reset on future prestiges. You'll eventually be able to "crystallize", which means you reset all your progress to get some currency to buy upgrades that do the same things as the original upgrades (and a couple of new ones) and won't reset on future crystallizes. Fine. You'll progress a bit, complete some challenges, and finally get to... grasshop? Grasshopping is this mechanic where you reset all your progress to get some resource that isn't for buying upgrades - this time you just unlock different modifiers on everything based on their amount. You may have gotten the point by now, but there are also "steelie" resets which give you steel for some reason, before unlocking a factory with various machines - none of which are directly tied to cutting grass, and start gathering things like oil and reset for rocket parts and reset to go to space and so on and so on. Throughout all of this there is absolutely no narrative justification or throughline for the direction the game is going, or why cutting grass is still relevant when we're collecting things like rocket parts. I may be going a little hard on GCI, but it is far from alone.

Tips for Developers

If you're a developer, by this point you should have a pretty decent idea of how to create "true" content in your game. Here are some other specific tips I'd suggest:

An upgrade that simply unlocks another upgrade trivially isn't content. However, many games have an upgrade that just unlocks a feature, which then has a wait or other requirements before it can be used. Try to make sure when you unlock a feature, there is immediately something to do with the feature - for example, perhaps give them a small amount of the new currency it unlocks, if applicable.

If you don't have a large web of effects, and can definitively say the impact of a purchase is to multiply the gain of the cost currency by N, and the next purchase costs N times the amount of that same currency, then this purchase effectively made no difference and it may have made more sense to just go directly to the next upgrade. That said, having effects based on things like the number of purchases made will quickly invalidate this tip.

',25),b=JSON.parse('{"title":"Guide to Incrementals/What is Content?","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/what-is-content-","title":"Guide to Incrementals/What is Content?","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/what-is-content/index.md","filePath":"garden/guide-to-incrementals/what-is-content/index.md"}'),m={name:"garden/guide-to-incrementals/what-is-content/index.md"},w=Object.assign(m,{setup(d){const a=o();return(g,p)=>(h(),i("div",null,[l,e("p",null,[s("2092 words, ~11 minute read. "),e("span",{innerHTML:t(n)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),u]))}});export{b as __pageData,w as default}; diff --git a/assets/garden_guide-to-incrementals_what-is-content_index.md.BdP15SmB.lean.js b/assets/garden_guide-to-incrementals_what-is-content_index.md.DXGnOHrD.lean.js similarity index 79% rename from assets/garden_guide-to-incrementals_what-is-content_index.md.BdP15SmB.lean.js rename to assets/garden_guide-to-incrementals_what-is-content_index.md.DXGnOHrD.lean.js index 09092cd1..dcd1cc13 100644 --- a/assets/garden_guide-to-incrementals_what-is-content_index.md.BdP15SmB.lean.js +++ b/assets/garden_guide-to-incrementals_what-is-content_index.md.DXGnOHrD.lean.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as o,c as i,j as e,a as s,k as t,ag as r,o as h}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"Guide to Incrementals___What is Content?",-1),c=["innerHTML"],u=r("",25),b=JSON.parse('{"title":"Guide to Incrementals/What is Content?","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/what-is-content-","title":"Guide to Incrementals/What is Content?","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/what-is-content/index.md","filePath":"garden/guide-to-incrementals/what-is-content/index.md"}'),m={name:"garden/guide-to-incrementals/what-is-content/index.md"},w=Object.assign(m,{setup(d){const a=o();return(g,p)=>(h(),i("div",null,[l,e("p",null,[s("2092 words, ~11 minute read. "),e("span",{innerHTML:t(n)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),u]))}});export{b as __pageData,w as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as o,q as i,Q as e,K as s,u as t,ag as r,p as h}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"Guide to Incrementals___What is Content?",-1),c=["innerHTML"],u=r("",25),b=JSON.parse('{"title":"Guide to Incrementals/What is Content?","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/what-is-content-","title":"Guide to Incrementals/What is Content?","prev":false,"next":false},"headers":[],"relativePath":"garden/guide-to-incrementals/what-is-content/index.md","filePath":"garden/guide-to-incrementals/what-is-content/index.md"}'),m={name:"garden/guide-to-incrementals/what-is-content/index.md"},w=Object.assign(m,{setup(d){const a=o();return(g,p)=>(h(),i("div",null,[l,e("p",null,[s("2092 words, ~11 minute read. "),e("span",{innerHTML:t(n)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),u]))}});export{b as __pageData,w as default}; diff --git a/assets/garden_incremental-social_index.md.B1XcCjeN.js b/assets/garden_incremental-social_index.md.B1XcCjeN.js deleted file mode 100644 index 9115a6dc..00000000 --- a/assets/garden_incremental-social_index.md.B1XcCjeN.js +++ /dev/null @@ -1 +0,0 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as r,c as s,j as e,a as i,k as a,ag as d,o}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"Incremental Social",-1),c=["innerHTML"],m=d('
Referenced by:Federated IdentityMy Personal Website/nowWebrings
Tags:My Projects

Incremental Social is a Fediverse website hosted by me!

Made explicitly for the incremental games community

Most notably hosts an instance of Mbin, Forgejo, and Synapse (and Cinny)

',6),y=JSON.parse('{"title":"Incremental Social","description":"","frontmatter":{"public":"tags:: My Projects","slug":"incremental-social","title":"Incremental Social","prev":false,"next":false},"headers":[],"relativePath":"garden/incremental-social/index.md","filePath":"garden/incremental-social/index.md"}'),_={name:"garden/incremental-social/index.md"},b=Object.assign(_,{setup(p){const n=r();return(f,g)=>(o(),s("div",null,[l,e("p",null,[i("20 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(n).page.value.relativePath}`]},null,8,c)]),m]))}});export{y as __pageData,b as default}; diff --git a/assets/garden_incremental-social_index.md.B1XcCjeN.lean.js b/assets/garden_incremental-social_index.md.B1XcCjeN.lean.js deleted file mode 100644 index 83362209..00000000 --- a/assets/garden_incremental-social_index.md.B1XcCjeN.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as r,c as s,j as e,a as i,k as a,ag as d,o}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"Incremental Social",-1),c=["innerHTML"],m=d("",6),y=JSON.parse('{"title":"Incremental Social","description":"","frontmatter":{"public":"tags:: My Projects","slug":"incremental-social","title":"Incremental Social","prev":false,"next":false},"headers":[],"relativePath":"garden/incremental-social/index.md","filePath":"garden/incremental-social/index.md"}'),_={name:"garden/incremental-social/index.md"},b=Object.assign(_,{setup(p){const n=r();return(f,g)=>(o(),s("div",null,[l,e("p",null,[i("20 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(n).page.value.relativePath}`]},null,8,c)]),m]))}});export{y as __pageData,b as default}; diff --git a/assets/garden_incremental-social_index.md.CsX_i8Lw.js b/assets/garden_incremental-social_index.md.CsX_i8Lw.js new file mode 100644 index 00000000..b1de6175 --- /dev/null +++ b/assets/garden_incremental-social_index.md.CsX_i8Lw.js @@ -0,0 +1 @@ +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as r,q as s,Q as e,K as i,u as a,ag as d,p as o}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"Incremental Social",-1),c=["innerHTML"],m=d('
Referenced by:Federated IdentityMy Personal Website/nowWebrings
Tags:My Projects

Incremental Social is a Fediverse website hosted by me!

Made explicitly for the incremental games community

Most notably hosts an instance of Mbin, Forgejo, and Synapse (and Cinny)

',6),y=JSON.parse('{"title":"Incremental Social","description":"","frontmatter":{"public":"tags:: My Projects","slug":"incremental-social","title":"Incremental Social","prev":false,"next":false},"headers":[],"relativePath":"garden/incremental-social/index.md","filePath":"garden/incremental-social/index.md"}'),_={name:"garden/incremental-social/index.md"},b=Object.assign(_,{setup(p){const n=r();return(f,g)=>(o(),s("div",null,[l,e("p",null,[i("20 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(n).page.value.relativePath}`]},null,8,c)]),m]))}});export{y as __pageData,b as default}; diff --git a/assets/garden_incremental-social_index.md.CsX_i8Lw.lean.js b/assets/garden_incremental-social_index.md.CsX_i8Lw.lean.js new file mode 100644 index 00000000..818b651d --- /dev/null +++ b/assets/garden_incremental-social_index.md.CsX_i8Lw.lean.js @@ -0,0 +1 @@ +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as r,q as s,Q as e,K as i,u as a,ag as d,p as o}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"Incremental Social",-1),c=["innerHTML"],m=d("",6),y=JSON.parse('{"title":"Incremental Social","description":"","frontmatter":{"public":"tags:: My Projects","slug":"incremental-social","title":"Incremental Social","prev":false,"next":false},"headers":[],"relativePath":"garden/incremental-social/index.md","filePath":"garden/incremental-social/index.md"}'),_={name:"garden/incremental-social/index.md"},b=Object.assign(_,{setup(p){const n=r();return(f,g)=>(o(),s("div",null,[l,e("p",null,[i("20 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(n).page.value.relativePath}`]},null,8,c)]),m]))}});export{y as __pageData,b as default}; diff --git a/assets/garden_ivy-road_index.md.DEFjS1hP.js b/assets/garden_ivy-road_index.md.DEFjS1hP.js deleted file mode 100644 index 3780dd13..00000000 --- a/assets/garden_ivy-road_index.md.DEFjS1hP.js +++ /dev/null @@ -1 +0,0 @@ -import{d}from"./chunks/git.data.DG5NumsR.js";import{u as t,c as n,j as e,a as s,k as a,ag as i,o}from"./chunks/framework.VBE0TPts.js";const _=e("h1",{class:"p-name"},"Ivy Road",-1),l=["innerHTML"],m=i('
Referenced by:Davey WredenWanderstop
Tags:Davey Wreden

Ivy Road is a indie game studio created by Davey Wreden, Karla Kimonja, and C418

',4),g=JSON.parse('{"title":"Ivy Road","description":"","frontmatter":{"public":"true","slug":"ivy-road","tags":["Davey Wreden"],"title":"Ivy Road","prev":false,"next":false},"headers":[],"relativePath":"garden/ivy-road/index.md","filePath":"garden/ivy-road/index.md"}'),c={name:"garden/ivy-road/index.md"},h=Object.assign(c,{setup(p){const r=t();return(u,y)=>(o(),n("div",null,[_,e("p",null,[s("6 words, ~0 minute read. "),e("span",{innerHTML:a(d)[`site/${a(r).page.value.relativePath}`]},null,8,l)]),m]))}});export{g as __pageData,h as default}; diff --git a/assets/garden_ivy-road_index.md.DEFjS1hP.lean.js b/assets/garden_ivy-road_index.md.DEFjS1hP.lean.js deleted file mode 100644 index 43732f4e..00000000 --- a/assets/garden_ivy-road_index.md.DEFjS1hP.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{d}from"./chunks/git.data.DG5NumsR.js";import{u as t,c as n,j as e,a as s,k as a,ag as i,o}from"./chunks/framework.VBE0TPts.js";const _=e("h1",{class:"p-name"},"Ivy Road",-1),l=["innerHTML"],m=i("",4),g=JSON.parse('{"title":"Ivy Road","description":"","frontmatter":{"public":"true","slug":"ivy-road","tags":["Davey Wreden"],"title":"Ivy Road","prev":false,"next":false},"headers":[],"relativePath":"garden/ivy-road/index.md","filePath":"garden/ivy-road/index.md"}'),c={name:"garden/ivy-road/index.md"},h=Object.assign(c,{setup(p){const r=t();return(u,y)=>(o(),n("div",null,[_,e("p",null,[s("6 words, ~0 minute read. "),e("span",{innerHTML:a(d)[`site/${a(r).page.value.relativePath}`]},null,8,l)]),m]))}});export{g as __pageData,h as default}; diff --git a/assets/garden_ivy-road_index.md.DcoTLA7N.js b/assets/garden_ivy-road_index.md.DcoTLA7N.js new file mode 100644 index 00000000..c8e892c1 --- /dev/null +++ b/assets/garden_ivy-road_index.md.DcoTLA7N.js @@ -0,0 +1 @@ +import{d}from"./chunks/git.data.DG5NumsR.js";import{M as t,q as n,Q as e,K as s,u as a,ag as i,p as o}from"./chunks/framework.DvHfxfnp.js";const _=e("h1",{class:"p-name"},"Ivy Road",-1),l=["innerHTML"],m=i('
Referenced by:Davey WredenWanderstop
Tags:Davey Wreden

Ivy Road is a indie game studio created by Davey Wreden, Karla Kimonja, and C418

',4),g=JSON.parse('{"title":"Ivy Road","description":"","frontmatter":{"public":"true","slug":"ivy-road","tags":["Davey Wreden"],"title":"Ivy Road","prev":false,"next":false},"headers":[],"relativePath":"garden/ivy-road/index.md","filePath":"garden/ivy-road/index.md"}'),c={name:"garden/ivy-road/index.md"},h=Object.assign(c,{setup(p){const r=t();return(u,y)=>(o(),n("div",null,[_,e("p",null,[s("6 words, ~0 minute read. "),e("span",{innerHTML:a(d)[`site/${a(r).page.value.relativePath}`]},null,8,l)]),m]))}});export{g as __pageData,h as default}; diff --git a/assets/garden_ivy-road_index.md.DcoTLA7N.lean.js b/assets/garden_ivy-road_index.md.DcoTLA7N.lean.js new file mode 100644 index 00000000..5f32cbbc --- /dev/null +++ b/assets/garden_ivy-road_index.md.DcoTLA7N.lean.js @@ -0,0 +1 @@ +import{d}from"./chunks/git.data.DG5NumsR.js";import{M as t,q as n,Q as e,K as s,u as a,ag as i,p as o}from"./chunks/framework.DvHfxfnp.js";const _=e("h1",{class:"p-name"},"Ivy Road",-1),l=["innerHTML"],m=i("",4),g=JSON.parse('{"title":"Ivy Road","description":"","frontmatter":{"public":"true","slug":"ivy-road","tags":["Davey Wreden"],"title":"Ivy Road","prev":false,"next":false},"headers":[],"relativePath":"garden/ivy-road/index.md","filePath":"garden/ivy-road/index.md"}'),c={name:"garden/ivy-road/index.md"},h=Object.assign(c,{setup(p){const r=t();return(u,y)=>(o(),n("div",null,[_,e("p",null,[s("6 words, ~0 minute read. "),e("span",{innerHTML:a(d)[`site/${a(r).page.value.relativePath}`]},null,8,l)]),m]))}});export{g as __pageData,h as default}; diff --git a/assets/garden_kronos_index.md.DWmqXBaE.js b/assets/garden_kronos_index.md.Cu7rVJ0m.js similarity index 77% rename from assets/garden_kronos_index.md.DWmqXBaE.js rename to assets/garden_kronos_index.md.Cu7rVJ0m.js index 83918659..ebdbf9d8 100644 --- a/assets/garden_kronos_index.md.DWmqXBaE.js +++ b/assets/garden_kronos_index.md.Cu7rVJ0m.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as n,j as e,a as o,k as a,ag as i,o as l}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Kronos",-1),m=["innerHTML"],p=i('
Referenced by:V-ecs
Tags:My ProjectsProfectus

My largest and most ambitious incremental game I've ever made

  • A magnum opus, of sorts ;P

Still in development, and will be for a long time. I have full intention of completing it, however

An older version, that is built in The Modding Tree, only has the gameplay, and only goes up to Chapter 2, can be played here

',7),y=JSON.parse('{"title":"Kronos","description":"","frontmatter":{"public":"true","slug":"kronos","tags":["My Projects","Profectus"],"title":"Kronos","prev":false,"next":false},"headers":[],"relativePath":"garden/kronos/index.md","filePath":"garden/kronos/index.md"}'),c={name:"garden/kronos/index.md"},v=Object.assign(c,{setup(u){const t=s();return(_,g)=>(l(),n("div",null,[d,e("p",null,[o("60 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),p]))}});export{y as __pageData,v as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as n,Q as e,K as o,u as a,ag as i,p as l}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Kronos",-1),p=["innerHTML"],m=i('
Referenced by:V-ecs
Tags:My ProjectsProfectus

My largest and most ambitious incremental game I've ever made

  • A magnum opus, of sorts ;P

Still in development, and will be for a long time. I have full intention of completing it, however

An older version, that is built in The Modding Tree, only has the gameplay, and only goes up to Chapter 2, can be played here

',7),y=JSON.parse('{"title":"Kronos","description":"","frontmatter":{"public":"true","slug":"kronos","tags":["My Projects","Profectus"],"title":"Kronos","prev":false,"next":false},"headers":[],"relativePath":"garden/kronos/index.md","filePath":"garden/kronos/index.md"}'),c={name:"garden/kronos/index.md"},v=Object.assign(c,{setup(u){const t=s();return(_,g)=>(l(),n("div",null,[d,e("p",null,[o("60 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,p)]),m]))}});export{y as __pageData,v as default}; diff --git a/assets/garden_kronos_index.md.DWmqXBaE.lean.js b/assets/garden_kronos_index.md.Cu7rVJ0m.lean.js similarity index 59% rename from assets/garden_kronos_index.md.DWmqXBaE.lean.js rename to assets/garden_kronos_index.md.Cu7rVJ0m.lean.js index 2fa67fc2..7041da5c 100644 --- a/assets/garden_kronos_index.md.DWmqXBaE.lean.js +++ b/assets/garden_kronos_index.md.Cu7rVJ0m.lean.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as n,j as e,a as o,k as a,ag as i,o as l}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Kronos",-1),m=["innerHTML"],p=i("",7),y=JSON.parse('{"title":"Kronos","description":"","frontmatter":{"public":"true","slug":"kronos","tags":["My Projects","Profectus"],"title":"Kronos","prev":false,"next":false},"headers":[],"relativePath":"garden/kronos/index.md","filePath":"garden/kronos/index.md"}'),c={name:"garden/kronos/index.md"},v=Object.assign(c,{setup(u){const t=s();return(_,g)=>(l(),n("div",null,[d,e("p",null,[o("60 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),p]))}});export{y as __pageData,v as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as n,Q as e,K as o,u as a,ag as i,p as l}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Kronos",-1),p=["innerHTML"],m=i("",7),y=JSON.parse('{"title":"Kronos","description":"","frontmatter":{"public":"true","slug":"kronos","tags":["My Projects","Profectus"],"title":"Kronos","prev":false,"next":false},"headers":[],"relativePath":"garden/kronos/index.md","filePath":"garden/kronos/index.md"}'),c={name:"garden/kronos/index.md"},v=Object.assign(c,{setup(u){const t=s();return(_,g)=>(l(),n("div",null,[d,e("p",null,[o("60 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,p)]),m]))}});export{y as __pageData,v as default}; diff --git a/assets/garden_life-is-strange_index.md.Cvu7AqjX.js b/assets/garden_life-is-strange_index.md.DZxs1spf.js similarity index 98% rename from assets/garden_life-is-strange_index.md.Cvu7AqjX.js rename to assets/garden_life-is-strange_index.md.DZxs1spf.js index aff085ff..4b8a396a 100644 --- a/assets/garden_life-is-strange_index.md.Cvu7AqjX.js +++ b/assets/garden_life-is-strange_index.md.DZxs1spf.js @@ -1 +1 @@ -import{u as i,c as r,j as e,a as s,k as t,ag as o,o as n,ar as l,as as h}from"./chunks/framework.VBE0TPts.js";import{d}from"./chunks/git.data.DG5NumsR.js";const g=e("h1",{class:"p-name"},"Life is Strange",-1),c=["innerHTML"],m=o('

A series of narrative driven video games with a focus on player choices

I really enjoyed the first game and engaged with the community a lot. I would get very emotional playing through the later chapters, and it became one of my favorite games.

Playthroughs I enjoyed:

Around the start of Haley and I's relationship, we'd play through LiS1 on projectors in our's classrooms

The ending

I was not a huge fan of the ending of Life is Strange. Of the two endings, one very clearly got a lot more resources spent on it, but I think Max's story has a better conclusion under the other.

In my mind, Max's arc (and major themes of the last chapter) was about learning not to rely on her powers, and to learn to live with the consequences of her actions. To that end, having the game end with her taking responsibility and living with the consequences of such a major event is a fitting thematic conclusion to the game and her character arc. In contrast, the other ending shows Max relying on her powers once again and, in my opinion, portrays Max as having not grown nor learned any lessons throughout the entire series. I think its a disservice this ending got so much more attention, with unique outfits and a song dedicated to it.

Life is Strange: Before the Storm

I really enjoyed this story. I didn't get quite as invested, perhaps due to it being a condensed 3 chapters rather than 5, but the characters will still just as amazing, which is what makes LiS so good. The ending didn't have as much of a punch as LiS1 - in fact, the entire back half of episode 3 didn't quite meet the bar in my eyes. At the time, I enjoyed these threads discussing criticisms levied at that part of the game:

Deadbones played through the game here

The Awesome Adventures of Captain Spirit

I enjoyed the demo, and it certainly got me hyped for LiS2 (although I would've been regardless). Switching to UE seemed like a really good move, and the comic theme fits the aesthetic of the series well.

Life is Strange 2

Unfortunately, I've only played the first chapter of this game. I wanted to play through it with Haley, but we haven't found time to do so.

LATER Skip the rest of LiS1 and play LiS2 with Haley

Life is Strange: True Colors

This game seems interesting, although the power does seem a little funnily close to "has empathy". I haven't had time to play it, but would like to.

Life is Strange: Double Exposure

I'm very excited for this game! Returning to Max's story sounds awesome. Although I will say, from the trailer alone it's incredibly obvious what one of the story beats will be: Revealing that the two timelines follow the two disparate endings from LiS1.

This game was announced to come with premium editions that get access to the game earlier

  • I think this is a horrible anti-consumer practice
  • Since this game is narratively driven, it is prone to spoilers
  • They're getting more money from their biggest fans without providing any tangible value to them, other than making the experience worse for everyone who plays but doesn't cough up that money
  • I hope other narratively driven games find other ways to do Video Game Monetization
',25),b=JSON.parse('{"title":"Life is Strange","description":"","frontmatter":{"public":"true","slug":"life-is-strange","title":"Life is Strange","prev":false,"next":false},"headers":[],"relativePath":"garden/life-is-strange/index.md","filePath":"garden/life-is-strange/index.md"}'),u={name:"garden/life-is-strange/index.md"},v=Object.assign(u,{setup(f){const a=i();return(p,w)=>(n(),r("div",null,[g,e("p",null,[s("654 words, ~4 minute read. "),e("span",{innerHTML:t(d)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),m]))}});export{b as __pageData,v as default}; +import{M as i,q as r,Q as e,K as s,u as t,ag as o,p as n,ar as l,as as h}from"./chunks/framework.DvHfxfnp.js";import{d}from"./chunks/git.data.DG5NumsR.js";const g=e("h1",{class:"p-name"},"Life is Strange",-1),c=["innerHTML"],m=o('

A series of narrative driven video games with a focus on player choices

I really enjoyed the first game and engaged with the community a lot. I would get very emotional playing through the later chapters, and it became one of my favorite games.

Playthroughs I enjoyed:

Around the start of Haley and I's relationship, we'd play through LiS1 on projectors in our's classrooms

The ending

I was not a huge fan of the ending of Life is Strange. Of the two endings, one very clearly got a lot more resources spent on it, but I think Max's story has a better conclusion under the other.

In my mind, Max's arc (and major themes of the last chapter) was about learning not to rely on her powers, and to learn to live with the consequences of her actions. To that end, having the game end with her taking responsibility and living with the consequences of such a major event is a fitting thematic conclusion to the game and her character arc. In contrast, the other ending shows Max relying on her powers once again and, in my opinion, portrays Max as having not grown nor learned any lessons throughout the entire series. I think its a disservice this ending got so much more attention, with unique outfits and a song dedicated to it.

Life is Strange: Before the Storm

I really enjoyed this story. I didn't get quite as invested, perhaps due to it being a condensed 3 chapters rather than 5, but the characters will still just as amazing, which is what makes LiS so good. The ending didn't have as much of a punch as LiS1 - in fact, the entire back half of episode 3 didn't quite meet the bar in my eyes. At the time, I enjoyed these threads discussing criticisms levied at that part of the game:

Deadbones played through the game here

The Awesome Adventures of Captain Spirit

I enjoyed the demo, and it certainly got me hyped for LiS2 (although I would've been regardless). Switching to UE seemed like a really good move, and the comic theme fits the aesthetic of the series well.

Life is Strange 2

Unfortunately, I've only played the first chapter of this game. I wanted to play through it with Haley, but we haven't found time to do so.

LATER Skip the rest of LiS1 and play LiS2 with Haley

Life is Strange: True Colors

This game seems interesting, although the power does seem a little funnily close to "has empathy". I haven't had time to play it, but would like to.

Life is Strange: Double Exposure

I'm very excited for this game! Returning to Max's story sounds awesome. Although I will say, from the trailer alone it's incredibly obvious what one of the story beats will be: Revealing that the two timelines follow the two disparate endings from LiS1.

This game was announced to come with premium editions that get access to the game earlier

  • I think this is a horrible anti-consumer practice
  • Since this game is narratively driven, it is prone to spoilers
  • They're getting more money from their biggest fans without providing any tangible value to them, other than making the experience worse for everyone who plays but doesn't cough up that money
  • I hope other narratively driven games find other ways to do Video Game Monetization
',25),b=JSON.parse('{"title":"Life is Strange","description":"","frontmatter":{"public":"true","slug":"life-is-strange","title":"Life is Strange","prev":false,"next":false},"headers":[],"relativePath":"garden/life-is-strange/index.md","filePath":"garden/life-is-strange/index.md"}'),u={name:"garden/life-is-strange/index.md"},v=Object.assign(u,{setup(f){const a=i();return(p,w)=>(n(),r("div",null,[g,e("p",null,[s("654 words, ~4 minute read. "),e("span",{innerHTML:t(d)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),m]))}});export{b as __pageData,v as default}; diff --git a/assets/garden_life-is-strange_index.md.Cvu7AqjX.lean.js b/assets/garden_life-is-strange_index.md.DZxs1spf.lean.js similarity index 83% rename from assets/garden_life-is-strange_index.md.Cvu7AqjX.lean.js rename to assets/garden_life-is-strange_index.md.DZxs1spf.lean.js index 21b9b23e..cb884351 100644 --- a/assets/garden_life-is-strange_index.md.Cvu7AqjX.lean.js +++ b/assets/garden_life-is-strange_index.md.DZxs1spf.lean.js @@ -1 +1 @@ -import{u as i,c as r,j as e,a as s,k as t,ag as o,o as n,ar as l,as as h}from"./chunks/framework.VBE0TPts.js";import{d}from"./chunks/git.data.DG5NumsR.js";const g=e("h1",{class:"p-name"},"Life is Strange",-1),c=["innerHTML"],m=o("",25),b=JSON.parse('{"title":"Life is Strange","description":"","frontmatter":{"public":"true","slug":"life-is-strange","title":"Life is Strange","prev":false,"next":false},"headers":[],"relativePath":"garden/life-is-strange/index.md","filePath":"garden/life-is-strange/index.md"}'),u={name:"garden/life-is-strange/index.md"},v=Object.assign(u,{setup(f){const a=i();return(p,w)=>(n(),r("div",null,[g,e("p",null,[s("654 words, ~4 minute read. "),e("span",{innerHTML:t(d)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),m]))}});export{b as __pageData,v as default}; +import{M as i,q as r,Q as e,K as s,u as t,ag as o,p as n,ar as l,as as h}from"./chunks/framework.DvHfxfnp.js";import{d}from"./chunks/git.data.DG5NumsR.js";const g=e("h1",{class:"p-name"},"Life is Strange",-1),c=["innerHTML"],m=o("",25),b=JSON.parse('{"title":"Life is Strange","description":"","frontmatter":{"public":"true","slug":"life-is-strange","title":"Life is Strange","prev":false,"next":false},"headers":[],"relativePath":"garden/life-is-strange/index.md","filePath":"garden/life-is-strange/index.md"}'),u={name:"garden/life-is-strange/index.md"},v=Object.assign(u,{setup(f){const a=i();return(p,w)=>(n(),r("div",null,[g,e("p",null,[s("654 words, ~4 minute read. "),e("span",{innerHTML:t(d)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),m]))}});export{b as __pageData,v as default}; diff --git a/assets/garden_logseq_index.md.CGpHVto-.js b/assets/garden_logseq_index.md.BtOsUfE8.js similarity index 67% rename from assets/garden_logseq_index.md.CGpHVto-.js rename to assets/garden_logseq_index.md.BtOsUfE8.js index 3d001656..08d21141 100644 --- a/assets/garden_logseq_index.md.CGpHVto-.js +++ b/assets/garden_logseq_index.md.BtOsUfE8.js @@ -1 +1 @@ -import{d as s}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as r,j as e,a as o,k as a,ag as d,o as l}from"./chunks/framework.VBE0TPts.js";const i=e("h1",{class:"p-name"},"Logseq",-1),_=["innerHTML"],c=d('
Referenced by:Command PalettesMy Personal WebsiteThis Knowledge Hub

Logseq is an Open Source outlining software

',3),x=JSON.parse('{"title":"Logseq","description":"","frontmatter":{"public":"true","slug":"logseq","title":"Logseq","prev":false,"next":false},"headers":[],"relativePath":"garden/logseq/index.md","filePath":"garden/logseq/index.md"}'),g={name:"garden/logseq/index.md"},T=Object.assign(g,{setup(m){const t=n();return(p,u)=>(l(),r("div",null,[i,e("p",null,[o("3 words, ~0 minute read. "),e("span",{innerHTML:a(s)[`site/${a(t).page.value.relativePath}`]},null,8,_)]),c]))}});export{x as __pageData,T as default}; +import{d as s}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as r,Q as e,K as o,u as a,ag as d,p as l}from"./chunks/framework.DvHfxfnp.js";const i=e("h1",{class:"p-name"},"Logseq",-1),_=["innerHTML"],c=d('
Referenced by:Command PalettesMy Personal WebsiteThis Knowledge Hub

Logseq is an Open Source outlining software

',3),q=JSON.parse('{"title":"Logseq","description":"","frontmatter":{"public":"true","slug":"logseq","title":"Logseq","prev":false,"next":false},"headers":[],"relativePath":"garden/logseq/index.md","filePath":"garden/logseq/index.md"}'),g={name:"garden/logseq/index.md"},x=Object.assign(g,{setup(m){const t=n();return(p,u)=>(l(),r("div",null,[i,e("p",null,[o("3 words, ~0 minute read. "),e("span",{innerHTML:a(s)[`site/${a(t).page.value.relativePath}`]},null,8,_)]),c]))}});export{q as __pageData,x as default}; diff --git a/assets/garden_logseq_index.md.BtOsUfE8.lean.js b/assets/garden_logseq_index.md.BtOsUfE8.lean.js new file mode 100644 index 00000000..1307c847 --- /dev/null +++ b/assets/garden_logseq_index.md.BtOsUfE8.lean.js @@ -0,0 +1 @@ +import{d as s}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as r,Q as e,K as o,u as a,ag as d,p as l}from"./chunks/framework.DvHfxfnp.js";const i=e("h1",{class:"p-name"},"Logseq",-1),_=["innerHTML"],c=d("",3),q=JSON.parse('{"title":"Logseq","description":"","frontmatter":{"public":"true","slug":"logseq","title":"Logseq","prev":false,"next":false},"headers":[],"relativePath":"garden/logseq/index.md","filePath":"garden/logseq/index.md"}'),g={name:"garden/logseq/index.md"},x=Object.assign(g,{setup(m){const t=n();return(p,u)=>(l(),r("div",null,[i,e("p",null,[o("3 words, ~0 minute read. "),e("span",{innerHTML:a(s)[`site/${a(t).page.value.relativePath}`]},null,8,_)]),c]))}});export{q as __pageData,x as default}; diff --git a/assets/garden_logseq_index.md.CGpHVto-.lean.js b/assets/garden_logseq_index.md.CGpHVto-.lean.js deleted file mode 100644 index 574b3057..00000000 --- a/assets/garden_logseq_index.md.CGpHVto-.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{d as s}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as r,j as e,a as o,k as a,ag as d,o as l}from"./chunks/framework.VBE0TPts.js";const i=e("h1",{class:"p-name"},"Logseq",-1),_=["innerHTML"],c=d("",3),x=JSON.parse('{"title":"Logseq","description":"","frontmatter":{"public":"true","slug":"logseq","title":"Logseq","prev":false,"next":false},"headers":[],"relativePath":"garden/logseq/index.md","filePath":"garden/logseq/index.md"}'),g={name:"garden/logseq/index.md"},T=Object.assign(g,{setup(m){const t=n();return(p,u)=>(l(),r("div",null,[i,e("p",null,[o("3 words, ~0 minute read. "),e("span",{innerHTML:a(s)[`site/${a(t).page.value.relativePath}`]},null,8,_)]),c]))}});export{x as __pageData,T as default}; diff --git a/assets/garden_matrix_index.md.BuCnqAik.js b/assets/garden_matrix_index.md.BuCnqAik.js deleted file mode 100644 index 38684b49..00000000 --- a/assets/garden_matrix_index.md.BuCnqAik.js +++ /dev/null @@ -1 +0,0 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as s,j as e,a as i,k as a,ag as d,o}from"./chunks/framework.VBE0TPts.js";const _=e("h1",{class:"p-name"},"Matrix",-1),m=["innerHTML"],c=d('
Referenced by:CinnyCommuneSynapse

Matrix is a protocol for Decentralized messaging

',3),h=JSON.parse('{"title":"Matrix","description":"","frontmatter":{"public":"true","slug":"matrix","title":"Matrix","prev":false,"next":false},"headers":[],"relativePath":"garden/matrix/index.md","filePath":"garden/matrix/index.md"}'),l={name:"garden/matrix/index.md"},T=Object.assign(l,{setup(p){const t=n();return(u,x)=>(o(),s("div",null,[_,e("p",null,[i("2 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),c]))}});export{h as __pageData,T as default}; diff --git a/assets/garden_matrix_index.md.BuCnqAik.lean.js b/assets/garden_matrix_index.md.BuCnqAik.lean.js deleted file mode 100644 index 89b3b592..00000000 --- a/assets/garden_matrix_index.md.BuCnqAik.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as s,j as e,a as i,k as a,ag as d,o}from"./chunks/framework.VBE0TPts.js";const _=e("h1",{class:"p-name"},"Matrix",-1),m=["innerHTML"],c=d("",3),h=JSON.parse('{"title":"Matrix","description":"","frontmatter":{"public":"true","slug":"matrix","title":"Matrix","prev":false,"next":false},"headers":[],"relativePath":"garden/matrix/index.md","filePath":"garden/matrix/index.md"}'),l={name:"garden/matrix/index.md"},T=Object.assign(l,{setup(p){const t=n();return(u,x)=>(o(),s("div",null,[_,e("p",null,[i("2 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),c]))}});export{h as __pageData,T as default}; diff --git a/assets/garden_matrix_index.md.DkFciSU3.js b/assets/garden_matrix_index.md.DkFciSU3.js new file mode 100644 index 00000000..a51b2b46 --- /dev/null +++ b/assets/garden_matrix_index.md.DkFciSU3.js @@ -0,0 +1 @@ +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as s,Q as e,K as i,u as a,ag as d,p as o}from"./chunks/framework.DvHfxfnp.js";const _=e("h1",{class:"p-name"},"Matrix",-1),m=["innerHTML"],l=d('
Referenced by:CinnyCommuneSynapse

Matrix is a protocol for Decentralized messaging

',3),h=JSON.parse('{"title":"Matrix","description":"","frontmatter":{"public":"true","slug":"matrix","title":"Matrix","prev":false,"next":false},"headers":[],"relativePath":"garden/matrix/index.md","filePath":"garden/matrix/index.md"}'),c={name:"garden/matrix/index.md"},T=Object.assign(c,{setup(p){const t=n();return(u,x)=>(o(),s("div",null,[_,e("p",null,[i("2 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),l]))}});export{h as __pageData,T as default}; diff --git a/assets/garden_matrix_index.md.DkFciSU3.lean.js b/assets/garden_matrix_index.md.DkFciSU3.lean.js new file mode 100644 index 00000000..51b51625 --- /dev/null +++ b/assets/garden_matrix_index.md.DkFciSU3.lean.js @@ -0,0 +1 @@ +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as s,Q as e,K as i,u as a,ag as d,p as o}from"./chunks/framework.DvHfxfnp.js";const _=e("h1",{class:"p-name"},"Matrix",-1),m=["innerHTML"],l=d("",3),h=JSON.parse('{"title":"Matrix","description":"","frontmatter":{"public":"true","slug":"matrix","title":"Matrix","prev":false,"next":false},"headers":[],"relativePath":"garden/matrix/index.md","filePath":"garden/matrix/index.md"}'),c={name:"garden/matrix/index.md"},T=Object.assign(c,{setup(p){const t=n();return(u,x)=>(o(),s("div",null,[_,e("p",null,[i("2 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),l]))}});export{h as __pageData,T as default}; diff --git a/assets/garden_mbin_index.md.CsZu6UCI.js b/assets/garden_mbin_index.md.DL7RJU0g.js similarity index 65% rename from assets/garden_mbin_index.md.CsZu6UCI.js rename to assets/garden_mbin_index.md.DL7RJU0g.js index 301b9d1d..02b59698 100644 --- a/assets/garden_mbin_index.md.CsZu6UCI.js +++ b/assets/garden_mbin_index.md.DL7RJU0g.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as i,j as e,a as t,k as n,o as l}from"./chunks/framework.VBE0TPts.js";const o=e("h1",{class:"p-name"},"Mbin",-1),d=["innerHTML"],c=e("hr",null,null,-1),u=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/incremental-social/index.md"},"Incremental Social")],-1),_=e("p",null,[e("a",{href:"https://github.com/MbinOrg/mbin",target:"_blank",rel:"noreferrer"},"Mbin"),t(" is an "),e("a",{href:"/garden/open-source/"},"Open Source"),t(),e("a",{href:"/garden/fediverse/"},"Fediverse"),t(" software")],-1),m=e("p",null,"Can show both twitter-style posts and reddit-style threads",-1),v=JSON.parse('{"title":"Mbin","description":"","frontmatter":{"public":"true","slug":"mbin","title":"Mbin","prev":false,"next":false},"headers":[],"relativePath":"garden/mbin/index.md","filePath":"garden/mbin/index.md"}'),p={name:"garden/mbin/index.md"},M=Object.assign(p,{setup(h){const a=s();return(f,b)=>(l(),i("div",null,[o,e("p",null,[t("12 words, ~0 minute read. "),e("span",{innerHTML:n(r)[`site/${n(a).page.value.relativePath}`]},null,8,d)]),c,u,_,m]))}});export{v as __pageData,M as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as i,Q as e,K as t,u as n,p as l}from"./chunks/framework.DvHfxfnp.js";const o=e("h1",{class:"p-name"},"Mbin",-1),d=["innerHTML"],c=e("hr",null,null,-1),u=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/incremental-social/index.md"},"Incremental Social")],-1),_=e("p",null,[e("a",{href:"https://github.com/MbinOrg/mbin",target:"_blank",rel:"noreferrer"},"Mbin"),t(" is an "),e("a",{href:"/garden/open-source/"},"Open Source"),t(),e("a",{href:"/garden/fediverse/"},"Fediverse"),t(" software")],-1),m=e("p",null,"Can show both twitter-style posts and reddit-style threads",-1),M=JSON.parse('{"title":"Mbin","description":"","frontmatter":{"public":"true","slug":"mbin","title":"Mbin","prev":false,"next":false},"headers":[],"relativePath":"garden/mbin/index.md","filePath":"garden/mbin/index.md"}'),p={name:"garden/mbin/index.md"},v=Object.assign(p,{setup(h){const a=s();return(f,b)=>(l(),i("div",null,[o,e("p",null,[t("12 words, ~0 minute read. "),e("span",{innerHTML:n(r)[`site/${n(a).page.value.relativePath}`]},null,8,d)]),c,u,_,m]))}});export{M as __pageData,v as default}; diff --git a/assets/garden_mbin_index.md.CsZu6UCI.lean.js b/assets/garden_mbin_index.md.DL7RJU0g.lean.js similarity index 65% rename from assets/garden_mbin_index.md.CsZu6UCI.lean.js rename to assets/garden_mbin_index.md.DL7RJU0g.lean.js index 301b9d1d..02b59698 100644 --- a/assets/garden_mbin_index.md.CsZu6UCI.lean.js +++ b/assets/garden_mbin_index.md.DL7RJU0g.lean.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as i,j as e,a as t,k as n,o as l}from"./chunks/framework.VBE0TPts.js";const o=e("h1",{class:"p-name"},"Mbin",-1),d=["innerHTML"],c=e("hr",null,null,-1),u=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/incremental-social/index.md"},"Incremental Social")],-1),_=e("p",null,[e("a",{href:"https://github.com/MbinOrg/mbin",target:"_blank",rel:"noreferrer"},"Mbin"),t(" is an "),e("a",{href:"/garden/open-source/"},"Open Source"),t(),e("a",{href:"/garden/fediverse/"},"Fediverse"),t(" software")],-1),m=e("p",null,"Can show both twitter-style posts and reddit-style threads",-1),v=JSON.parse('{"title":"Mbin","description":"","frontmatter":{"public":"true","slug":"mbin","title":"Mbin","prev":false,"next":false},"headers":[],"relativePath":"garden/mbin/index.md","filePath":"garden/mbin/index.md"}'),p={name:"garden/mbin/index.md"},M=Object.assign(p,{setup(h){const a=s();return(f,b)=>(l(),i("div",null,[o,e("p",null,[t("12 words, ~0 minute read. "),e("span",{innerHTML:n(r)[`site/${n(a).page.value.relativePath}`]},null,8,d)]),c,u,_,m]))}});export{v as __pageData,M as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as i,Q as e,K as t,u as n,p as l}from"./chunks/framework.DvHfxfnp.js";const o=e("h1",{class:"p-name"},"Mbin",-1),d=["innerHTML"],c=e("hr",null,null,-1),u=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/incremental-social/index.md"},"Incremental Social")],-1),_=e("p",null,[e("a",{href:"https://github.com/MbinOrg/mbin",target:"_blank",rel:"noreferrer"},"Mbin"),t(" is an "),e("a",{href:"/garden/open-source/"},"Open Source"),t(),e("a",{href:"/garden/fediverse/"},"Fediverse"),t(" software")],-1),m=e("p",null,"Can show both twitter-style posts and reddit-style threads",-1),M=JSON.parse('{"title":"Mbin","description":"","frontmatter":{"public":"true","slug":"mbin","title":"Mbin","prev":false,"next":false},"headers":[],"relativePath":"garden/mbin/index.md","filePath":"garden/mbin/index.md"}'),p={name:"garden/mbin/index.md"},v=Object.assign(p,{setup(h){const a=s();return(f,b)=>(l(),i("div",null,[o,e("p",null,[t("12 words, ~0 minute read. "),e("span",{innerHTML:n(r)[`site/${n(a).page.value.relativePath}`]},null,8,d)]),c,u,_,m]))}});export{M as __pageData,v as default}; diff --git a/assets/garden_mtx_index.md.BrTCy3ds.js b/assets/garden_mtx_index.md.BrTCy3ds.js deleted file mode 100644 index 62fe6e82..00000000 --- a/assets/garden_mtx_index.md.BrTCy3ds.js +++ /dev/null @@ -1 +0,0 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as r,j as e,a as i,k as a,o}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"MTX",-1),d=["innerHTML"],c=e("hr",null,null,-1),m=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/premium-currency/index.md"},"Premium Currency"),e("a",{href:"/garden/video-game-monetization/index.md"},"Video Game Monetization")],-1),u=e("p",null,"Purchaseable items in video games that cost real life currencies",-1),v=JSON.parse('{"title":"MTX","description":"","frontmatter":{"alias":"Microtransactions, IAP, In-App Purchases","public":"true","slug":"mtx","title":"MTX","prev":false,"next":false},"headers":[],"relativePath":"garden/mtx/index.md","filePath":"garden/mtx/index.md"}'),_={name:"garden/mtx/index.md"},M=Object.assign(_,{setup(p){const t=s();return(h,f)=>(o(),r("div",null,[l,e("p",null,[i("10 words, ~0 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,d)]),c,m,u]))}});export{v as __pageData,M as default}; diff --git a/assets/garden_mtx_index.md.BrTCy3ds.lean.js b/assets/garden_mtx_index.md.BrTCy3ds.lean.js deleted file mode 100644 index 62fe6e82..00000000 --- a/assets/garden_mtx_index.md.BrTCy3ds.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as r,j as e,a as i,k as a,o}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"MTX",-1),d=["innerHTML"],c=e("hr",null,null,-1),m=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/premium-currency/index.md"},"Premium Currency"),e("a",{href:"/garden/video-game-monetization/index.md"},"Video Game Monetization")],-1),u=e("p",null,"Purchaseable items in video games that cost real life currencies",-1),v=JSON.parse('{"title":"MTX","description":"","frontmatter":{"alias":"Microtransactions, IAP, In-App Purchases","public":"true","slug":"mtx","title":"MTX","prev":false,"next":false},"headers":[],"relativePath":"garden/mtx/index.md","filePath":"garden/mtx/index.md"}'),_={name:"garden/mtx/index.md"},M=Object.assign(_,{setup(p){const t=s();return(h,f)=>(o(),r("div",null,[l,e("p",null,[i("10 words, ~0 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,d)]),c,m,u]))}});export{v as __pageData,M as default}; diff --git a/assets/garden_mtx_index.md.BwWrNpeS.js b/assets/garden_mtx_index.md.BwWrNpeS.js new file mode 100644 index 00000000..17b96cf0 --- /dev/null +++ b/assets/garden_mtx_index.md.BwWrNpeS.js @@ -0,0 +1 @@ +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as r,Q as e,K as i,u as a,p as o}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"MTX",-1),d=["innerHTML"],c=e("hr",null,null,-1),m=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/premium-currency/index.md"},"Premium Currency"),e("a",{href:"/garden/video-game-monetization/index.md"},"Video Game Monetization")],-1),u=e("p",null,"Purchaseable items in video games that cost real life currencies",-1),M=JSON.parse('{"title":"MTX","description":"","frontmatter":{"alias":"Microtransactions, IAP, In-App Purchases","public":"true","slug":"mtx","title":"MTX","prev":false,"next":false},"headers":[],"relativePath":"garden/mtx/index.md","filePath":"garden/mtx/index.md"}'),p={name:"garden/mtx/index.md"},v=Object.assign(p,{setup(_){const t=s();return(h,f)=>(o(),r("div",null,[l,e("p",null,[i("10 words, ~0 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,d)]),c,m,u]))}});export{M as __pageData,v as default}; diff --git a/assets/garden_mtx_index.md.BwWrNpeS.lean.js b/assets/garden_mtx_index.md.BwWrNpeS.lean.js new file mode 100644 index 00000000..17b96cf0 --- /dev/null +++ b/assets/garden_mtx_index.md.BwWrNpeS.lean.js @@ -0,0 +1 @@ +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as r,Q as e,K as i,u as a,p as o}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"MTX",-1),d=["innerHTML"],c=e("hr",null,null,-1),m=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/premium-currency/index.md"},"Premium Currency"),e("a",{href:"/garden/video-game-monetization/index.md"},"Video Game Monetization")],-1),u=e("p",null,"Purchaseable items in video games that cost real life currencies",-1),M=JSON.parse('{"title":"MTX","description":"","frontmatter":{"alias":"Microtransactions, IAP, In-App Purchases","public":"true","slug":"mtx","title":"MTX","prev":false,"next":false},"headers":[],"relativePath":"garden/mtx/index.md","filePath":"garden/mtx/index.md"}'),p={name:"garden/mtx/index.md"},v=Object.assign(p,{setup(_){const t=s();return(h,f)=>(o(),r("div",null,[l,e("p",null,[i("10 words, ~0 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,d)]),c,m,u]))}});export{M as __pageData,v as default}; diff --git a/assets/garden_my-personal-website_index.md.B7pFBXsd.js b/assets/garden_my-personal-website_index.md.CGVQsQif.js similarity index 93% rename from assets/garden_my-personal-website_index.md.B7pFBXsd.js rename to assets/garden_my-personal-website_index.md.CGVQsQif.js index d63eb764..9deae080 100644 --- a/assets/garden_my-personal-website_index.md.B7pFBXsd.js +++ b/assets/garden_my-personal-website_index.md.CGVQsQif.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as l,j as e,a as i,k as a,ag as o,o as n}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"My Personal Website",-1),h=["innerHTML"],p=o('
Referenced by:The Small Web

A Personal Websites for myself, available at https://thepaperpilot.org

Tech Stack

I use Logseq to journal and collect my thoughts on various topics that interest me

  • Seafile syncs my logseq files between my devices
  • Git syncs my logseq files to a private repo on Incremental Social for purposes of version control and using as a submodule
  • The seafile files and all repos on Incremental Social are independently backed up daily to backblaze

My logseq files are synced to a private git repo which is added as a submodule to my website repo

A Node.js script pre-processes my logseq files into markdown files in the /garden path of the website

  • Converts all links and block references
  • Adds lists of tags and references to pages
  • Adds <h1 /> titles, word counts, update commits, etc. to each page
  • Moves the /now page to /now instead of /garden/now
  • Copies some of the Guide to Incrementals pages to /guide-to-incrementals so as to not break links made before the current site iteration
  • Generates /changelog and its RSS, Atom, and JSON feeds
    • The outputs of the generation are NOT .gitignore'd, as I use the git log to determine which pages updated when - Commit information about when a file was last updated is added via a data loader because if it was added to the file directly, rebuilding the site would count as having updated every page, by updating each commit to the changes introduced last build

Vitepress builds a static site from the markdown files

  • Includes a custom theme that makes the whole site paper-themed
  • Includes some pages like the homepage and the about me page that require markup, thus don't make sense to maintain inside logseq
  • The sidebar is generated from my favorited pages within Logseq
  • Includes various static files, like copies of several of my games and a robots.txt (borrowed from Tracy Durnell's robots.txt) that blocks several crawlers specifically used for training AI models

Three.js is used to create the effect in the background

  • Simplex noise gets used to adjust the opacity of a repeating SVG pattern
  • Initially tried to use just SVG, which supports creating noise and using it as a mask, but it only does 2d noise and I need 2d slices of 3d noise

Microformats are used to markup the site for The IndieWeb

  • The footer contains a minimal h-card with a link to my full profile
  • Each garden page is an h-entry, and the changelog an h-feed
  • All my socials are added as rel-me links, and the profiles then link back to me (as rel-me links, if allowed by the platform)
    • Together this can verify the owner of this website and those socials are the same person
',15),k=JSON.parse('{"title":"My Personal Website","description":"","frontmatter":{"public":"true","slug":"my-personal-website","title":"My Personal Website","prev":false,"next":false},"headers":[],"relativePath":"garden/my-personal-website/index.md","filePath":"garden/my-personal-website/index.md"}'),c={name:"garden/my-personal-website/index.md"},_=Object.assign(c,{setup(f){const t=s();return(g,m)=>(n(),l("div",null,[d,e("p",null,[i("422 words, ~2 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,h)]),p]))}});export{k as __pageData,_ as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as l,Q as e,K as i,u as a,ag as o,p as n}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"My Personal Website",-1),h=["innerHTML"],p=o('
Referenced by:The Small Web

A Personal Websites for myself, available at https://thepaperpilot.org

Tech Stack

I use Logseq to journal and collect my thoughts on various topics that interest me

  • Seafile syncs my logseq files between my devices
  • Git syncs my logseq files to a private repo on Incremental Social for purposes of version control and using as a submodule
  • The seafile files and all repos on Incremental Social are independently backed up daily to backblaze

My logseq files are synced to a private git repo which is added as a submodule to my website repo

A Node.js script pre-processes my logseq files into markdown files in the /garden path of the website

  • Converts all links and block references
  • Adds lists of tags and references to pages
  • Adds <h1 /> titles, word counts, update commits, etc. to each page
  • Moves the /now page to /now instead of /garden/now
  • Copies some of the Guide to Incrementals pages to /guide-to-incrementals so as to not break links made before the current site iteration
  • Generates /changelog and its RSS, Atom, and JSON feeds
    • The outputs of the generation are NOT .gitignore'd, as I use the git log to determine which pages updated when - Commit information about when a file was last updated is added via a data loader because if it was added to the file directly, rebuilding the site would count as having updated every page, by updating each commit to the changes introduced last build

Vitepress builds a static site from the markdown files

  • Includes a custom theme that makes the whole site paper-themed
  • Includes some pages like the homepage and the about me page that require markup, thus don't make sense to maintain inside logseq
  • The sidebar is generated from my favorited pages within Logseq
  • Includes various static files, like copies of several of my games and a robots.txt (borrowed from Tracy Durnell's robots.txt) that blocks several crawlers specifically used for training AI models

Three.js is used to create the effect in the background

  • Simplex noise gets used to adjust the opacity of a repeating SVG pattern
  • Initially tried to use just SVG, which supports creating noise and using it as a mask, but it only does 2d noise and I need 2d slices of 3d noise

Microformats are used to markup the site for The IndieWeb

  • The footer contains a minimal h-card with a link to my full profile
  • Each garden page is an h-entry, and the changelog an h-feed
  • All my socials are added as rel-me links, and the profiles then link back to me (as rel-me links, if allowed by the platform)
    • Together this can verify the owner of this website and those socials are the same person
',15),_=JSON.parse('{"title":"My Personal Website","description":"","frontmatter":{"public":"true","slug":"my-personal-website","title":"My Personal Website","prev":false,"next":false},"headers":[],"relativePath":"garden/my-personal-website/index.md","filePath":"garden/my-personal-website/index.md"}'),c={name:"garden/my-personal-website/index.md"},k=Object.assign(c,{setup(f){const t=s();return(g,m)=>(n(),l("div",null,[d,e("p",null,[i("422 words, ~2 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,h)]),p]))}});export{_ as __pageData,k as default}; diff --git a/assets/garden_my-personal-website_index.md.B7pFBXsd.lean.js b/assets/garden_my-personal-website_index.md.CGVQsQif.lean.js similarity index 54% rename from assets/garden_my-personal-website_index.md.B7pFBXsd.lean.js rename to assets/garden_my-personal-website_index.md.CGVQsQif.lean.js index a8ca92b0..912b7e69 100644 --- a/assets/garden_my-personal-website_index.md.B7pFBXsd.lean.js +++ b/assets/garden_my-personal-website_index.md.CGVQsQif.lean.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as l,j as e,a as i,k as a,ag as o,o as n}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"My Personal Website",-1),h=["innerHTML"],p=o("",15),k=JSON.parse('{"title":"My Personal Website","description":"","frontmatter":{"public":"true","slug":"my-personal-website","title":"My Personal Website","prev":false,"next":false},"headers":[],"relativePath":"garden/my-personal-website/index.md","filePath":"garden/my-personal-website/index.md"}'),c={name:"garden/my-personal-website/index.md"},_=Object.assign(c,{setup(f){const t=s();return(g,m)=>(n(),l("div",null,[d,e("p",null,[i("422 words, ~2 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,h)]),p]))}});export{k as __pageData,_ as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as l,Q as e,K as i,u as a,ag as o,p as n}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"My Personal Website",-1),h=["innerHTML"],p=o("",15),_=JSON.parse('{"title":"My Personal Website","description":"","frontmatter":{"public":"true","slug":"my-personal-website","title":"My Personal Website","prev":false,"next":false},"headers":[],"relativePath":"garden/my-personal-website/index.md","filePath":"garden/my-personal-website/index.md"}'),c={name:"garden/my-personal-website/index.md"},k=Object.assign(c,{setup(f){const t=s();return(g,m)=>(n(),l("div",null,[d,e("p",null,[i("422 words, ~2 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,h)]),p]))}});export{_ as __pageData,k as default}; diff --git a/assets/garden_my-projects_index.md.BTL4J3HO.lean.js b/assets/garden_my-projects_index.md.BTL4J3HO.lean.js deleted file mode 100644 index 3aee063f..00000000 --- a/assets/garden_my-projects_index.md.BTL4J3HO.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as t,c as l,j as e,a as o,k as a,ag as i,o as d}from"./chunks/framework.VBE0TPts.js";const s=e("h1",{class:"p-name"},"My Projects",-1),c=["innerHTML"],h=i("",7),b=JSON.parse('{"title":"My Projects","description":"","frontmatter":{"index":"true","public":"true","slug":"my-projects","title":"My Projects","prev":false,"next":false},"headers":[],"relativePath":"garden/my-projects/index.md","filePath":"garden/my-projects/index.md"}'),p={name:"garden/my-projects/index.md"},v=Object.assign(p,{setup(m){const r=t();return(g,f)=>(d(),l("div",null,[s,e("p",null,[o("72 words, ~0 minute read. "),e("span",{innerHTML:a(n)[`site/${a(r).page.value.relativePath}`]},null,8,c)]),h]))}});export{b as __pageData,v as default}; diff --git a/assets/garden_my-projects_index.md.BTL4J3HO.js b/assets/garden_my-projects_index.md.pIi7fe_T.js similarity index 82% rename from assets/garden_my-projects_index.md.BTL4J3HO.js rename to assets/garden_my-projects_index.md.pIi7fe_T.js index a606530b..7cdf2837 100644 --- a/assets/garden_my-projects_index.md.BTL4J3HO.js +++ b/assets/garden_my-projects_index.md.pIi7fe_T.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as t,c as l,j as e,a as o,k as a,ag as i,o as d}from"./chunks/framework.VBE0TPts.js";const s=e("h1",{class:"p-name"},"My Projects",-1),c=["innerHTML"],h=i('
Tagged by:Advent IncrementalBabble BudsCapture the CitadelDice ArmorGame Dev TreeIncremental SocialKronosOpti-SpeechPlanar PioneersProfectusV-ecs

I like making games and tools!

Games

Tools (and other non-games)

',7),b=JSON.parse('{"title":"My Projects","description":"","frontmatter":{"index":"true","public":"true","slug":"my-projects","title":"My Projects","prev":false,"next":false},"headers":[],"relativePath":"garden/my-projects/index.md","filePath":"garden/my-projects/index.md"}'),p={name:"garden/my-projects/index.md"},v=Object.assign(p,{setup(m){const r=t();return(g,f)=>(d(),l("div",null,[s,e("p",null,[o("72 words, ~0 minute read. "),e("span",{innerHTML:a(n)[`site/${a(r).page.value.relativePath}`]},null,8,c)]),h]))}});export{b as __pageData,v as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as t,q as l,Q as e,K as i,u as a,ag as o,p as d}from"./chunks/framework.DvHfxfnp.js";const s=e("h1",{class:"p-name"},"My Projects",-1),p=["innerHTML"],h=o('
Tagged by:Advent IncrementalBabble BudsCapture the CitadelDice ArmorGame Dev TreeIncremental SocialKronosOpti-SpeechPlanar PioneersProfectusV-ecs

I like making games and tools!

Games

Tools (and other non-games)

',7),b=JSON.parse('{"title":"My Projects","description":"","frontmatter":{"index":"true","public":"true","slug":"my-projects","title":"My Projects","prev":false,"next":false},"headers":[],"relativePath":"garden/my-projects/index.md","filePath":"garden/my-projects/index.md"}'),c={name:"garden/my-projects/index.md"},v=Object.assign(c,{setup(m){const r=t();return(g,f)=>(d(),l("div",null,[s,e("p",null,[i("72 words, ~0 minute read. "),e("span",{innerHTML:a(n)[`site/${a(r).page.value.relativePath}`]},null,8,p)]),h]))}});export{b as __pageData,v as default}; diff --git a/assets/garden_my-projects_index.md.pIi7fe_T.lean.js b/assets/garden_my-projects_index.md.pIi7fe_T.lean.js new file mode 100644 index 00000000..5bd5cd8e --- /dev/null +++ b/assets/garden_my-projects_index.md.pIi7fe_T.lean.js @@ -0,0 +1 @@ +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as t,q as l,Q as e,K as i,u as a,ag as o,p as d}from"./chunks/framework.DvHfxfnp.js";const s=e("h1",{class:"p-name"},"My Projects",-1),p=["innerHTML"],h=o("",7),b=JSON.parse('{"title":"My Projects","description":"","frontmatter":{"index":"true","public":"true","slug":"my-projects","title":"My Projects","prev":false,"next":false},"headers":[],"relativePath":"garden/my-projects/index.md","filePath":"garden/my-projects/index.md"}'),c={name:"garden/my-projects/index.md"},v=Object.assign(c,{setup(m){const r=t();return(g,f)=>(d(),l("div",null,[s,e("p",null,[i("72 words, ~0 minute read. "),e("span",{innerHTML:a(n)[`site/${a(r).page.value.relativePath}`]},null,8,p)]),h]))}});export{b as __pageData,v as default}; diff --git a/assets/garden_nostr_index.md.DQgV1bMu.js b/assets/garden_nostr_index.md.DQgV1bMu.js new file mode 100644 index 00000000..6e8af4bd --- /dev/null +++ b/assets/garden_nostr_index.md.DQgV1bMu.js @@ -0,0 +1 @@ +import{d as s}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as d,Q as e,K as a,u as t,p as o}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"Nostr",-1),i=["innerHTML"],c=e("hr",null,null,-1),u=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/fediverse/index.md"},"Fediverse")],-1),_=e("details",null,[e("summary",null,"Tags:"),e("a",{href:"/garden/decentralized/index.md"},"Decentralized")],-1),p=e("p",null,[e("a",{href:"https://nostr.com",target:"_blank",rel:"noreferrer"},"Nostr"),a(" is a protocol for "),e("a",{href:"/garden/fediverse/"},"Federated Social Media")],-1),N=JSON.parse('{"title":"Nostr","description":"","frontmatter":{"public":"true","slug":"nostr","tags":["Decentralized"],"title":"Nostr","prev":false,"next":false},"headers":[],"relativePath":"garden/nostr/index.md","filePath":"garden/nostr/index.md"}'),m={name:"garden/nostr/index.md"},D=Object.assign(m,{setup(f){const r=n();return(h,g)=>(o(),d("div",null,[l,e("p",null,[a("8 words, ~0 minute read. "),e("span",{innerHTML:t(s)[`site/${t(r).page.value.relativePath}`]},null,8,i)]),c,u,_,p]))}});export{N as __pageData,D as default}; diff --git a/assets/garden_nostr_index.md.DQgV1bMu.lean.js b/assets/garden_nostr_index.md.DQgV1bMu.lean.js new file mode 100644 index 00000000..6e8af4bd --- /dev/null +++ b/assets/garden_nostr_index.md.DQgV1bMu.lean.js @@ -0,0 +1 @@ +import{d as s}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as d,Q as e,K as a,u as t,p as o}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"Nostr",-1),i=["innerHTML"],c=e("hr",null,null,-1),u=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/fediverse/index.md"},"Fediverse")],-1),_=e("details",null,[e("summary",null,"Tags:"),e("a",{href:"/garden/decentralized/index.md"},"Decentralized")],-1),p=e("p",null,[e("a",{href:"https://nostr.com",target:"_blank",rel:"noreferrer"},"Nostr"),a(" is a protocol for "),e("a",{href:"/garden/fediverse/"},"Federated Social Media")],-1),N=JSON.parse('{"title":"Nostr","description":"","frontmatter":{"public":"true","slug":"nostr","tags":["Decentralized"],"title":"Nostr","prev":false,"next":false},"headers":[],"relativePath":"garden/nostr/index.md","filePath":"garden/nostr/index.md"}'),m={name:"garden/nostr/index.md"},D=Object.assign(m,{setup(f){const r=n();return(h,g)=>(o(),d("div",null,[l,e("p",null,[a("8 words, ~0 minute read. "),e("span",{innerHTML:t(s)[`site/${t(r).page.value.relativePath}`]},null,8,i)]),c,u,_,p]))}});export{N as __pageData,D as default}; diff --git a/assets/garden_nostr_index.md.DuRG5Z1P.js b/assets/garden_nostr_index.md.DuRG5Z1P.js deleted file mode 100644 index bd1dba24..00000000 --- a/assets/garden_nostr_index.md.DuRG5Z1P.js +++ /dev/null @@ -1 +0,0 @@ -import{d as s}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as o,j as e,a,k as t,o as d}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"Nostr",-1),i=["innerHTML"],c=e("hr",null,null,-1),u=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/fediverse/index.md"},"Fediverse")],-1),_=e("details",null,[e("summary",null,"Tags:"),e("a",{href:"/garden/decentralized/index.md"},"Decentralized")],-1),m=e("p",null,[e("a",{href:"https://nostr.com",target:"_blank",rel:"noreferrer"},"Nostr"),a(" is a protocol for "),e("a",{href:"/garden/fediverse/"},"Federated Social Media")],-1),N=JSON.parse('{"title":"Nostr","description":"","frontmatter":{"public":"true","slug":"nostr","tags":["Decentralized"],"title":"Nostr","prev":false,"next":false},"headers":[],"relativePath":"garden/nostr/index.md","filePath":"garden/nostr/index.md"}'),p={name:"garden/nostr/index.md"},D=Object.assign(p,{setup(f){const r=n();return(h,g)=>(d(),o("div",null,[l,e("p",null,[a("8 words, ~0 minute read. "),e("span",{innerHTML:t(s)[`site/${t(r).page.value.relativePath}`]},null,8,i)]),c,u,_,m]))}});export{N as __pageData,D as default}; diff --git a/assets/garden_nostr_index.md.DuRG5Z1P.lean.js b/assets/garden_nostr_index.md.DuRG5Z1P.lean.js deleted file mode 100644 index bd1dba24..00000000 --- a/assets/garden_nostr_index.md.DuRG5Z1P.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{d as s}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as o,j as e,a,k as t,o as d}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"Nostr",-1),i=["innerHTML"],c=e("hr",null,null,-1),u=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/fediverse/index.md"},"Fediverse")],-1),_=e("details",null,[e("summary",null,"Tags:"),e("a",{href:"/garden/decentralized/index.md"},"Decentralized")],-1),m=e("p",null,[e("a",{href:"https://nostr.com",target:"_blank",rel:"noreferrer"},"Nostr"),a(" is a protocol for "),e("a",{href:"/garden/fediverse/"},"Federated Social Media")],-1),N=JSON.parse('{"title":"Nostr","description":"","frontmatter":{"public":"true","slug":"nostr","tags":["Decentralized"],"title":"Nostr","prev":false,"next":false},"headers":[],"relativePath":"garden/nostr/index.md","filePath":"garden/nostr/index.md"}'),p={name:"garden/nostr/index.md"},D=Object.assign(p,{setup(f){const r=n();return(h,g)=>(d(),o("div",null,[l,e("p",null,[a("8 words, ~0 minute read. "),e("span",{innerHTML:t(s)[`site/${t(r).page.value.relativePath}`]},null,8,i)]),c,u,_,m]))}});export{N as __pageData,D as default}; diff --git a/assets/garden_open-source_index.md.D0998lGJ.js b/assets/garden_open-source_index.md.D0998lGJ.js new file mode 100644 index 00000000..2ed4451a --- /dev/null +++ b/assets/garden_open-source_index.md.D0998lGJ.js @@ -0,0 +1 @@ +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as d,q as t,Q as e,K as s,u as a,ag as i,p as o}from"./chunks/framework.DvHfxfnp.js";const c=e("h1",{class:"p-name"},"Open Source",-1),m=["innerHTML"],p=i('
Referenced by:Advent IncrementalCinnyCommuneDice ArmorForgejoGame Dev TreeLogseqMbinPlanar PioneersProfectusSynapseVitepressWeird

Projects with the source code publicly accessible

Typically also grants users the right to modify the code and redistribute those changes, depending on the license

',4),x=JSON.parse('{"title":"Open Source","description":"","frontmatter":{"public":"true","slug":"open-source","title":"Open Source","prev":false,"next":false},"headers":[],"relativePath":"garden/open-source/index.md","filePath":"garden/open-source/index.md"}'),l={name:"garden/open-source/index.md"},y=Object.assign(l,{setup(u){const n=d();return(g,h)=>(o(),t("div",null,[c,e("p",null,[s("25 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(n).page.value.relativePath}`]},null,8,m)]),p]))}});export{x as __pageData,y as default}; diff --git a/assets/garden_open-source_index.md.D0998lGJ.lean.js b/assets/garden_open-source_index.md.D0998lGJ.lean.js new file mode 100644 index 00000000..9fcc0ad4 --- /dev/null +++ b/assets/garden_open-source_index.md.D0998lGJ.lean.js @@ -0,0 +1 @@ +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as d,q as t,Q as e,K as s,u as a,ag as i,p as o}from"./chunks/framework.DvHfxfnp.js";const c=e("h1",{class:"p-name"},"Open Source",-1),m=["innerHTML"],p=i("",4),x=JSON.parse('{"title":"Open Source","description":"","frontmatter":{"public":"true","slug":"open-source","title":"Open Source","prev":false,"next":false},"headers":[],"relativePath":"garden/open-source/index.md","filePath":"garden/open-source/index.md"}'),l={name:"garden/open-source/index.md"},y=Object.assign(l,{setup(u){const n=d();return(g,h)=>(o(),t("div",null,[c,e("p",null,[s("25 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(n).page.value.relativePath}`]},null,8,m)]),p]))}});export{x as __pageData,y as default}; diff --git a/assets/garden_open-source_index.md.D7bOPf6D.js b/assets/garden_open-source_index.md.D7bOPf6D.js deleted file mode 100644 index bb405f4f..00000000 --- a/assets/garden_open-source_index.md.D7bOPf6D.js +++ /dev/null @@ -1 +0,0 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as d,c as t,j as e,a as s,k as a,ag as i,o}from"./chunks/framework.VBE0TPts.js";const c=e("h1",{class:"p-name"},"Open Source",-1),m=["innerHTML"],p=i('
Referenced by:Advent IncrementalCinnyCommuneDice ArmorForgejoGame Dev TreeLogseqMbinPlanar PioneersProfectusSynapseVitepressWeird

Projects with the source code publicly accessible

Typically also grants users the right to modify the code and redistribute those changes, depending on the license

',4),x=JSON.parse('{"title":"Open Source","description":"","frontmatter":{"public":"true","slug":"open-source","title":"Open Source","prev":false,"next":false},"headers":[],"relativePath":"garden/open-source/index.md","filePath":"garden/open-source/index.md"}'),l={name:"garden/open-source/index.md"},y=Object.assign(l,{setup(u){const n=d();return(g,h)=>(o(),t("div",null,[c,e("p",null,[s("25 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(n).page.value.relativePath}`]},null,8,m)]),p]))}});export{x as __pageData,y as default}; diff --git a/assets/garden_open-source_index.md.D7bOPf6D.lean.js b/assets/garden_open-source_index.md.D7bOPf6D.lean.js deleted file mode 100644 index 294744e7..00000000 --- a/assets/garden_open-source_index.md.D7bOPf6D.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as d,c as t,j as e,a as s,k as a,ag as i,o}from"./chunks/framework.VBE0TPts.js";const c=e("h1",{class:"p-name"},"Open Source",-1),m=["innerHTML"],p=i("",4),x=JSON.parse('{"title":"Open Source","description":"","frontmatter":{"public":"true","slug":"open-source","title":"Open Source","prev":false,"next":false},"headers":[],"relativePath":"garden/open-source/index.md","filePath":"garden/open-source/index.md"}'),l={name:"garden/open-source/index.md"},y=Object.assign(l,{setup(u){const n=d();return(g,h)=>(o(),t("div",null,[c,e("p",null,[s("25 words, ~0 minute read. "),e("span",{innerHTML:a(r)[`site/${a(n).page.value.relativePath}`]},null,8,m)]),p]))}});export{x as __pageData,y as default}; diff --git a/assets/garden_opti-speech_index.md.CRwm6q2W.js b/assets/garden_opti-speech_index.md.CRwm6q2W.js new file mode 100644 index 00000000..729d0a87 --- /dev/null +++ b/assets/garden_opti-speech_index.md.CRwm6q2W.js @@ -0,0 +1 @@ +import{M as r,q as s,Q as e,K as n,u as t,ag as a,p as o,at as l,au as c,av as p,aw as d}from"./chunks/framework.DvHfxfnp.js";import{d as h}from"./chunks/git.data.DG5NumsR.js";const m=e("h1",{class:"p-name"},"Opti-Speech",-1),u=["innerHTML"],g=a('
Tags:My Projects

In college I continued development on the Opti-Speech project, originally built alongside the scientific paper Opti-speech: a real-time, 3d visual feedback system for speech training

The Original Project

The Optispeech project involves designing and testing a real-time tongue model that can be viewed in a transparent head while a subject talks — for the purposes of treating speech errors and teaching foreign language sounds. This work has been conducted in partnership with Vulintus and with support from the National Institutes of Health (NIH).

',6),_=e("iframe",{width:"560",height:"315",src:"https://www.youtube.com/embed/9uHqIRs7ZjM",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:"",style:{display:"block",margin:"auto"}},null,-1),f=e("p",null,"This video shows a talker with WAVE sensors placed on the tongue hitting a virtual target sphere located at the alveolar ridge. When an alveolar consonant is hit (e.g., /s/, /n/, /d/) the sphere changes color from red to green.",-1),v=e("iframe",{width:"560",height:"315",src:"https://www.youtube.com/embed/Oz42mKvlzqI",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:"",style:{display:"block",margin:"auto"}},null,-1),y=a('

This video shows an American talker learning a novel sound not found in English. When the post-alveolar consonant is hit, the target sphere changes color from red to green. Here, the NDI WAVE system serves as input.

My Work

As the sole programmer at UT Dallas Speech Production Lab at the time, my changes involved updating to a more modern version of Unity, improving the interface, in general cleaning up tech debt so it can more easily support new features, and added support for additional EMA systems, namely the Carstens AG501.

In addition, the program now includes documentation and unit tests to improve program stability and maintainability going forward.

',7),O=JSON.parse('{"title":"Opti-Speech","description":"","frontmatter":{"public":"true","slug":"opti-speech","tags":["My Projects"],"title":"Opti-Speech","prev":false,"next":false},"headers":[],"relativePath":"garden/opti-speech/index.md","filePath":"garden/opti-speech/index.md"}'),w={name:"garden/opti-speech/index.md"},S=Object.assign(w,{setup(b){const i=r();return(T,k)=>(o(),s("div",null,[m,e("p",null,[n("312 words, ~2 minute read. "),e("span",{innerHTML:t(h)[`site/${t(i).page.value.relativePath}`]},null,8,u)]),g,_,f,v,y]))}});export{O as __pageData,S as default}; diff --git a/assets/garden_opti-speech_index.md.CRwm6q2W.lean.js b/assets/garden_opti-speech_index.md.CRwm6q2W.lean.js new file mode 100644 index 00000000..7b0c046e --- /dev/null +++ b/assets/garden_opti-speech_index.md.CRwm6q2W.lean.js @@ -0,0 +1 @@ +import{M as r,q as s,Q as e,K as n,u as t,ag as a,p as o,at as l,au as c,av as p,aw as d}from"./chunks/framework.DvHfxfnp.js";import{d as h}from"./chunks/git.data.DG5NumsR.js";const m=e("h1",{class:"p-name"},"Opti-Speech",-1),u=["innerHTML"],g=a("",6),_=e("iframe",{width:"560",height:"315",src:"https://www.youtube.com/embed/9uHqIRs7ZjM",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:"",style:{display:"block",margin:"auto"}},null,-1),f=e("p",null,"This video shows a talker with WAVE sensors placed on the tongue hitting a virtual target sphere located at the alveolar ridge. When an alveolar consonant is hit (e.g., /s/, /n/, /d/) the sphere changes color from red to green.",-1),v=e("iframe",{width:"560",height:"315",src:"https://www.youtube.com/embed/Oz42mKvlzqI",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:"",style:{display:"block",margin:"auto"}},null,-1),y=a("",7),O=JSON.parse('{"title":"Opti-Speech","description":"","frontmatter":{"public":"true","slug":"opti-speech","tags":["My Projects"],"title":"Opti-Speech","prev":false,"next":false},"headers":[],"relativePath":"garden/opti-speech/index.md","filePath":"garden/opti-speech/index.md"}'),w={name:"garden/opti-speech/index.md"},S=Object.assign(w,{setup(b){const i=r();return(T,k)=>(o(),s("div",null,[m,e("p",null,[n("312 words, ~2 minute read. "),e("span",{innerHTML:t(h)[`site/${t(i).page.value.relativePath}`]},null,8,u)]),g,_,f,v,y]))}});export{O as __pageData,S as default}; diff --git a/assets/garden_opti-speech_index.md.VQVokYBw.js b/assets/garden_opti-speech_index.md.VQVokYBw.js deleted file mode 100644 index acc04e26..00000000 --- a/assets/garden_opti-speech_index.md.VQVokYBw.js +++ /dev/null @@ -1 +0,0 @@ -import{u as r,c as s,j as e,a as n,k as t,ag as a,o,at as l,au as c,av as p,aw as d}from"./chunks/framework.VBE0TPts.js";import{d as h}from"./chunks/git.data.DG5NumsR.js";const m=e("h1",{class:"p-name"},"Opti-Speech",-1),u=["innerHTML"],g=a('
Tags:My Projects

In college I continued development on the Opti-Speech project, originally built alongside the scientific paper Opti-speech: a real-time, 3d visual feedback system for speech training

The Original Project

The Optispeech project involves designing and testing a real-time tongue model that can be viewed in a transparent head while a subject talks — for the purposes of treating speech errors and teaching foreign language sounds. This work has been conducted in partnership with Vulintus and with support from the National Institutes of Health (NIH).

',6),_=e("iframe",{width:"560",height:"315",src:"https://www.youtube.com/embed/9uHqIRs7ZjM",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:"",style:{display:"block",margin:"auto"}},null,-1),f=e("p",null,"This video shows a talker with WAVE sensors placed on the tongue hitting a virtual target sphere located at the alveolar ridge. When an alveolar consonant is hit (e.g., /s/, /n/, /d/) the sphere changes color from red to green.",-1),v=e("iframe",{width:"560",height:"315",src:"https://www.youtube.com/embed/Oz42mKvlzqI",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:"",style:{display:"block",margin:"auto"}},null,-1),y=a('

This video shows an American talker learning a novel sound not found in English. When the post-alveolar consonant is hit, the target sphere changes color from red to green. Here, the NDI WAVE system serves as input.

My Work

As the sole programmer at UT Dallas Speech Production Lab at the time, my changes involved updating to a more modern version of Unity, improving the interface, in general cleaning up tech debt so it can more easily support new features, and added support for additional EMA systems, namely the Carstens AG501.

In addition, the program now includes documentation and unit tests to improve program stability and maintainability going forward.

',7),O=JSON.parse('{"title":"Opti-Speech","description":"","frontmatter":{"public":"true","slug":"opti-speech","tags":["My Projects"],"title":"Opti-Speech","prev":false,"next":false},"headers":[],"relativePath":"garden/opti-speech/index.md","filePath":"garden/opti-speech/index.md"}'),w={name:"garden/opti-speech/index.md"},S=Object.assign(w,{setup(b){const i=r();return(T,k)=>(o(),s("div",null,[m,e("p",null,[n("312 words, ~2 minute read. "),e("span",{innerHTML:t(h)[`site/${t(i).page.value.relativePath}`]},null,8,u)]),g,_,f,v,y]))}});export{O as __pageData,S as default}; diff --git a/assets/garden_opti-speech_index.md.VQVokYBw.lean.js b/assets/garden_opti-speech_index.md.VQVokYBw.lean.js deleted file mode 100644 index f64250dc..00000000 --- a/assets/garden_opti-speech_index.md.VQVokYBw.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{u as r,c as s,j as e,a as n,k as t,ag as a,o,at as l,au as c,av as p,aw as d}from"./chunks/framework.VBE0TPts.js";import{d as h}from"./chunks/git.data.DG5NumsR.js";const m=e("h1",{class:"p-name"},"Opti-Speech",-1),u=["innerHTML"],g=a("",6),_=e("iframe",{width:"560",height:"315",src:"https://www.youtube.com/embed/9uHqIRs7ZjM",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:"",style:{display:"block",margin:"auto"}},null,-1),f=e("p",null,"This video shows a talker with WAVE sensors placed on the tongue hitting a virtual target sphere located at the alveolar ridge. When an alveolar consonant is hit (e.g., /s/, /n/, /d/) the sphere changes color from red to green.",-1),v=e("iframe",{width:"560",height:"315",src:"https://www.youtube.com/embed/Oz42mKvlzqI",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:"",style:{display:"block",margin:"auto"}},null,-1),y=a("",7),O=JSON.parse('{"title":"Opti-Speech","description":"","frontmatter":{"public":"true","slug":"opti-speech","tags":["My Projects"],"title":"Opti-Speech","prev":false,"next":false},"headers":[],"relativePath":"garden/opti-speech/index.md","filePath":"garden/opti-speech/index.md"}'),w={name:"garden/opti-speech/index.md"},S=Object.assign(w,{setup(b){const i=r();return(T,k)=>(o(),s("div",null,[m,e("p",null,[n("312 words, ~2 minute read. "),e("span",{innerHTML:t(h)[`site/${t(i).page.value.relativePath}`]},null,8,u)]),g,_,f,v,y]))}});export{O as __pageData,S as default}; diff --git a/assets/garden_planar-pioneers_index.md.CrWQHny8.js b/assets/garden_planar-pioneers_index.md.Bkbkl8EX.js similarity index 77% rename from assets/garden_planar-pioneers_index.md.CrWQHny8.js rename to assets/garden_planar-pioneers_index.md.Bkbkl8EX.js index 81a7f368..73b15fd6 100644 --- a/assets/garden_planar-pioneers_index.md.CrWQHny8.js +++ b/assets/garden_planar-pioneers_index.md.Bkbkl8EX.js @@ -1 +1 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as n,j as e,a as o,k as a,ag as i,o as p}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"Planar Pioneers",-1),d=["innerHTML"],c=i('
Tags:My ProjectsProfectus

Play it here!

An Open Source game designed to show off Profectus' dynamic layer system!

The TV Tropes page on this game mentions some of the cool things about this game

',5),P=JSON.parse('{"title":"Planar Pioneers","description":"","frontmatter":{"public":"true","slug":"planar-pioneers","tags":["My Projects","Profectus"],"title":"Planar Pioneers","prev":false,"next":false},"headers":[],"relativePath":"garden/planar-pioneers/index.md","filePath":"garden/planar-pioneers/index.md"}'),_={name:"garden/planar-pioneers/index.md"},T=Object.assign(_,{setup(m){const r=s();return(h,f)=>(p(),n("div",null,[l,e("p",null,[o("25 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,d)]),c]))}});export{P as __pageData,T as default}; +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as n,Q as e,K as o,u as a,ag as p,p as i}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"Planar Pioneers",-1),d=["innerHTML"],c=p('
Tags:My ProjectsProfectus

Play it here!

An Open Source game designed to show off Profectus' dynamic layer system!

The TV Tropes page on this game mentions some of the cool things about this game

',5),P=JSON.parse('{"title":"Planar Pioneers","description":"","frontmatter":{"public":"true","slug":"planar-pioneers","tags":["My Projects","Profectus"],"title":"Planar Pioneers","prev":false,"next":false},"headers":[],"relativePath":"garden/planar-pioneers/index.md","filePath":"garden/planar-pioneers/index.md"}'),_={name:"garden/planar-pioneers/index.md"},T=Object.assign(_,{setup(m){const r=s();return(h,f)=>(i(),n("div",null,[l,e("p",null,[o("25 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,d)]),c]))}});export{P as __pageData,T as default}; diff --git a/assets/garden_planar-pioneers_index.md.CrWQHny8.lean.js b/assets/garden_planar-pioneers_index.md.Bkbkl8EX.lean.js similarity index 61% rename from assets/garden_planar-pioneers_index.md.CrWQHny8.lean.js rename to assets/garden_planar-pioneers_index.md.Bkbkl8EX.lean.js index 3025eda2..336258c3 100644 --- a/assets/garden_planar-pioneers_index.md.CrWQHny8.lean.js +++ b/assets/garden_planar-pioneers_index.md.Bkbkl8EX.lean.js @@ -1 +1 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as n,j as e,a as o,k as a,ag as i,o as p}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"Planar Pioneers",-1),d=["innerHTML"],c=i("",5),P=JSON.parse('{"title":"Planar Pioneers","description":"","frontmatter":{"public":"true","slug":"planar-pioneers","tags":["My Projects","Profectus"],"title":"Planar Pioneers","prev":false,"next":false},"headers":[],"relativePath":"garden/planar-pioneers/index.md","filePath":"garden/planar-pioneers/index.md"}'),_={name:"garden/planar-pioneers/index.md"},T=Object.assign(_,{setup(m){const r=s();return(h,f)=>(p(),n("div",null,[l,e("p",null,[o("25 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,d)]),c]))}});export{P as __pageData,T as default}; +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as n,Q as e,K as o,u as a,ag as p,p as i}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"Planar Pioneers",-1),d=["innerHTML"],c=p("",5),P=JSON.parse('{"title":"Planar Pioneers","description":"","frontmatter":{"public":"true","slug":"planar-pioneers","tags":["My Projects","Profectus"],"title":"Planar Pioneers","prev":false,"next":false},"headers":[],"relativePath":"garden/planar-pioneers/index.md","filePath":"garden/planar-pioneers/index.md"}'),_={name:"garden/planar-pioneers/index.md"},T=Object.assign(_,{setup(m){const r=s();return(h,f)=>(i(),n("div",null,[l,e("p",null,[o("25 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,d)]),c]))}});export{P as __pageData,T as default}; diff --git a/assets/garden_pre-order-bonuses_index.md.CCGmxPHN.js b/assets/garden_pre-order-bonuses_index.md.shTakEi9.js similarity index 89% rename from assets/garden_pre-order-bonuses_index.md.CCGmxPHN.js rename to assets/garden_pre-order-bonuses_index.md.shTakEi9.js index 99ab7688..8aaf8658 100644 --- a/assets/garden_pre-order-bonuses_index.md.CCGmxPHN.js +++ b/assets/garden_pre-order-bonuses_index.md.shTakEi9.js @@ -1 +1 @@ -import{d as a}from"./chunks/git.data.DG5NumsR.js";import{u as t,c as r,j as e,a as l,k as i,ag as o,o as n}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Pre-Order Bonuses",-1),u=["innerHTML"],c=o('
Referenced by:Video Game Monetization

Pre-order bonuses are benefits given to players who buy a game before it comes out

They primarily serve to benefit the company

  • People commit to buying before the embargo date passes
  • Heuristic of how well it'll sell after launch
  • Slight lead on return on investment
    • More significantly impacts indie studios, who will likely have less cash on hand
  • Companies make deals with storefronts to have exclusive bonuses, to drive customers to said storefronts

Common bonuses:

  • Digital goods:
  • Physical goods:
    • Typically pins, keychains, etc.
    • Typically only included in physical editions of the game
',7),y=JSON.parse('{"title":"Pre-Order Bonuses","description":"","frontmatter":{"public":"true","slug":"pre-order-bonuses","title":"Pre-Order Bonuses","prev":false,"next":false},"headers":[],"relativePath":"garden/pre-order-bonuses/index.md","filePath":"garden/pre-order-bonuses/index.md"}'),m={name:"garden/pre-order-bonuses/index.md"},b=Object.assign(m,{setup(p){const s=t();return(_,h)=>(n(),r("div",null,[d,e("p",null,[l("98 words, ~1 minute read. "),e("span",{innerHTML:i(a)[`site/${i(s).page.value.relativePath}`]},null,8,u)]),c]))}});export{y as __pageData,b as default}; +import{d as a}from"./chunks/git.data.DG5NumsR.js";import{M as t,q as r,Q as e,K as l,u as i,ag as o,p as n}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Pre-Order Bonuses",-1),u=["innerHTML"],c=o('
Referenced by:Video Game Monetization

Pre-order bonuses are benefits given to players who buy a game before it comes out

They primarily serve to benefit the company

  • People commit to buying before the embargo date passes
  • Heuristic of how well it'll sell after launch
  • Slight lead on return on investment
    • More significantly impacts indie studios, who will likely have less cash on hand
  • Companies make deals with storefronts to have exclusive bonuses, to drive customers to said storefronts

Common bonuses:

  • Digital goods:
  • Physical goods:
    • Typically pins, keychains, etc.
    • Typically only included in physical editions of the game
',7),y=JSON.parse('{"title":"Pre-Order Bonuses","description":"","frontmatter":{"public":"true","slug":"pre-order-bonuses","title":"Pre-Order Bonuses","prev":false,"next":false},"headers":[],"relativePath":"garden/pre-order-bonuses/index.md","filePath":"garden/pre-order-bonuses/index.md"}'),m={name:"garden/pre-order-bonuses/index.md"},b=Object.assign(m,{setup(p){const s=t();return(_,h)=>(n(),r("div",null,[d,e("p",null,[l("98 words, ~1 minute read. "),e("span",{innerHTML:i(a)[`site/${i(s).page.value.relativePath}`]},null,8,u)]),c]))}});export{y as __pageData,b as default}; diff --git a/assets/garden_pre-order-bonuses_index.md.CCGmxPHN.lean.js b/assets/garden_pre-order-bonuses_index.md.shTakEi9.lean.js similarity index 76% rename from assets/garden_pre-order-bonuses_index.md.CCGmxPHN.lean.js rename to assets/garden_pre-order-bonuses_index.md.shTakEi9.lean.js index 08ec9737..eb5e383b 100644 --- a/assets/garden_pre-order-bonuses_index.md.CCGmxPHN.lean.js +++ b/assets/garden_pre-order-bonuses_index.md.shTakEi9.lean.js @@ -1 +1 @@ -import{d as a}from"./chunks/git.data.DG5NumsR.js";import{u as t,c as r,j as e,a as l,k as i,ag as o,o as n}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Pre-Order Bonuses",-1),u=["innerHTML"],c=o("",7),y=JSON.parse('{"title":"Pre-Order Bonuses","description":"","frontmatter":{"public":"true","slug":"pre-order-bonuses","title":"Pre-Order Bonuses","prev":false,"next":false},"headers":[],"relativePath":"garden/pre-order-bonuses/index.md","filePath":"garden/pre-order-bonuses/index.md"}'),m={name:"garden/pre-order-bonuses/index.md"},b=Object.assign(m,{setup(p){const s=t();return(_,h)=>(n(),r("div",null,[d,e("p",null,[l("98 words, ~1 minute read. "),e("span",{innerHTML:i(a)[`site/${i(s).page.value.relativePath}`]},null,8,u)]),c]))}});export{y as __pageData,b as default}; +import{d as a}from"./chunks/git.data.DG5NumsR.js";import{M as t,q as r,Q as e,K as l,u as i,ag as o,p as n}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Pre-Order Bonuses",-1),u=["innerHTML"],c=o("",7),y=JSON.parse('{"title":"Pre-Order Bonuses","description":"","frontmatter":{"public":"true","slug":"pre-order-bonuses","title":"Pre-Order Bonuses","prev":false,"next":false},"headers":[],"relativePath":"garden/pre-order-bonuses/index.md","filePath":"garden/pre-order-bonuses/index.md"}'),m={name:"garden/pre-order-bonuses/index.md"},b=Object.assign(m,{setup(p){const s=t();return(_,h)=>(n(),r("div",null,[d,e("p",null,[l("98 words, ~1 minute read. "),e("span",{innerHTML:i(a)[`site/${i(s).page.value.relativePath}`]},null,8,u)]),c]))}});export{y as __pageData,b as default}; diff --git a/assets/garden_premium-currency_index.md.DnHfK06C.js b/assets/garden_premium-currency_index.md.C5KciJ55.js similarity index 86% rename from assets/garden_premium-currency_index.md.DnHfK06C.js rename to assets/garden_premium-currency_index.md.C5KciJ55.js index 5f2cc909..e51f2989 100644 --- a/assets/garden_premium-currency_index.md.DnHfK06C.js +++ b/assets/garden_premium-currency_index.md.C5KciJ55.js @@ -1 +1 @@ -import{d as s}from"./chunks/git.data.DG5NumsR.js";import{u as t,c as n,j as e,a as i,k as r,ag as o,o as c}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"Premium Currency",-1),u=["innerHTML"],d=o('
Referenced by:Pre-Order Bonuses

A popular form of MTX where instead of receiving a useful item or effect directly, you receive a currency that is then spent on an in game store

Reasons companies use them

  • Abstracts the real world price of items
    • No strict conversion ratio
    • Discounts for bulk purchasing
    • Small amounts given for free based on story progression or watching ads
  • Consolidates smaller purchases into a larger one (decreasing friction of individual purchases)
',5),y=JSON.parse('{"title":"Premium Currency","description":"","frontmatter":{"public":"true","slug":"premium-currency","title":"Premium Currency","prev":false,"next":false},"headers":[],"relativePath":"garden/premium-currency/index.md","filePath":"garden/premium-currency/index.md"}'),m={name:"garden/premium-currency/index.md"},v=Object.assign(m,{setup(p){const a=t();return(_,f)=>(c(),n("div",null,[l,e("p",null,[i("71 words, ~0 minute read. "),e("span",{innerHTML:r(s)[`site/${r(a).page.value.relativePath}`]},null,8,u)]),d]))}});export{y as __pageData,v as default}; +import{d as s}from"./chunks/git.data.DG5NumsR.js";import{M as t,q as n,Q as e,K as i,u as r,ag as o,p as c}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"Premium Currency",-1),u=["innerHTML"],d=o('
Referenced by:Pre-Order Bonuses

A popular form of MTX where instead of receiving a useful item or effect directly, you receive a currency that is then spent on an in game store

Reasons companies use them

  • Abstracts the real world price of items
    • No strict conversion ratio
    • Discounts for bulk purchasing
    • Small amounts given for free based on story progression or watching ads
  • Consolidates smaller purchases into a larger one (decreasing friction of individual purchases)
',5),y=JSON.parse('{"title":"Premium Currency","description":"","frontmatter":{"public":"true","slug":"premium-currency","title":"Premium Currency","prev":false,"next":false},"headers":[],"relativePath":"garden/premium-currency/index.md","filePath":"garden/premium-currency/index.md"}'),m={name:"garden/premium-currency/index.md"},v=Object.assign(m,{setup(p){const a=t();return(_,f)=>(c(),n("div",null,[l,e("p",null,[i("71 words, ~0 minute read. "),e("span",{innerHTML:r(s)[`site/${r(a).page.value.relativePath}`]},null,8,u)]),d]))}});export{y as __pageData,v as default}; diff --git a/assets/garden_premium-currency_index.md.DnHfK06C.lean.js b/assets/garden_premium-currency_index.md.C5KciJ55.lean.js similarity index 75% rename from assets/garden_premium-currency_index.md.DnHfK06C.lean.js rename to assets/garden_premium-currency_index.md.C5KciJ55.lean.js index c7a39e0f..d26799ca 100644 --- a/assets/garden_premium-currency_index.md.DnHfK06C.lean.js +++ b/assets/garden_premium-currency_index.md.C5KciJ55.lean.js @@ -1 +1 @@ -import{d as s}from"./chunks/git.data.DG5NumsR.js";import{u as t,c as n,j as e,a as i,k as r,ag as o,o as c}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"Premium Currency",-1),u=["innerHTML"],d=o("",5),y=JSON.parse('{"title":"Premium Currency","description":"","frontmatter":{"public":"true","slug":"premium-currency","title":"Premium Currency","prev":false,"next":false},"headers":[],"relativePath":"garden/premium-currency/index.md","filePath":"garden/premium-currency/index.md"}'),m={name:"garden/premium-currency/index.md"},v=Object.assign(m,{setup(p){const a=t();return(_,f)=>(c(),n("div",null,[l,e("p",null,[i("71 words, ~0 minute read. "),e("span",{innerHTML:r(s)[`site/${r(a).page.value.relativePath}`]},null,8,u)]),d]))}});export{y as __pageData,v as default}; +import{d as s}from"./chunks/git.data.DG5NumsR.js";import{M as t,q as n,Q as e,K as i,u as r,ag as o,p as c}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"Premium Currency",-1),u=["innerHTML"],d=o("",5),y=JSON.parse('{"title":"Premium Currency","description":"","frontmatter":{"public":"true","slug":"premium-currency","title":"Premium Currency","prev":false,"next":false},"headers":[],"relativePath":"garden/premium-currency/index.md","filePath":"garden/premium-currency/index.md"}'),m={name:"garden/premium-currency/index.md"},v=Object.assign(m,{setup(p){const a=t();return(_,f)=>(c(),n("div",null,[l,e("p",null,[i("71 words, ~0 minute read. "),e("span",{innerHTML:r(s)[`site/${r(a).page.value.relativePath}`]},null,8,u)]),d]))}});export{y as __pageData,v as default}; diff --git a/assets/garden_profectus_index.md.BmLQh2zb.js b/assets/garden_profectus_index.md.upNDNXA9.js similarity index 90% rename from assets/garden_profectus_index.md.BmLQh2zb.js rename to assets/garden_profectus_index.md.upNDNXA9.js index 81e94f8d..1c0e9f5f 100644 --- a/assets/garden_profectus_index.md.BmLQh2zb.js +++ b/assets/garden_profectus_index.md.upNDNXA9.js @@ -1 +1 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as s,j as e,a as o,k as a,ag as i,o as d}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"Profectus",-1),m=["innerHTML"],c=i('
Referenced by:Advent IncrementalPlanar Pioneers
Tagged by:Advent IncrementalKronosPlanar Pioneers
Tags:My Projects

Profectus is an Open Source game engine I made, loosely based on The Modding Tree by Acamaeda

Technically it's more of a template for making web games

It centers around using Vue's reactivity and is designed with the intent to not restrain developers into making games that only look or behave "one way"

Games made with Profectus:

  • Everything in this garden tagged with this page!
  • The entries to the Profectus Creation Jam
  • Primordia by Jacorb
',9),y=JSON.parse('{"title":"Profectus","description":"","frontmatter":{"public":"true","slug":"profectus","tags":["My Projects"],"title":"Profectus","prev":false,"next":false},"headers":[],"relativePath":"garden/profectus/index.md","filePath":"garden/profectus/index.md"}'),p={name:"garden/profectus/index.md"},P=Object.assign(p,{setup(u){const r=n();return(g,f)=>(d(),s("div",null,[l,e("p",null,[o("73 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,m)]),c]))}});export{y as __pageData,P as default}; +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as s,Q as e,K as o,u as a,ag as i,p as d}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"Profectus",-1),m=["innerHTML"],c=i('
Referenced by:Advent IncrementalPlanar Pioneers
Tagged by:Advent IncrementalKronosPlanar Pioneers
Tags:My Projects

Profectus is an Open Source game engine I made, loosely based on The Modding Tree by Acamaeda

Technically it's more of a template for making web games

It centers around using Vue's reactivity and is designed with the intent to not restrain developers into making games that only look or behave "one way"

Games made with Profectus:

  • Everything in this garden tagged with this page!
  • The entries to the Profectus Creation Jam
  • Primordia by Jacorb
',9),y=JSON.parse('{"title":"Profectus","description":"","frontmatter":{"public":"true","slug":"profectus","tags":["My Projects"],"title":"Profectus","prev":false,"next":false},"headers":[],"relativePath":"garden/profectus/index.md","filePath":"garden/profectus/index.md"}'),p={name:"garden/profectus/index.md"},P=Object.assign(p,{setup(u){const r=n();return(g,f)=>(d(),s("div",null,[l,e("p",null,[o("73 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,m)]),c]))}});export{y as __pageData,P as default}; diff --git a/assets/garden_profectus_index.md.BmLQh2zb.lean.js b/assets/garden_profectus_index.md.upNDNXA9.lean.js similarity index 74% rename from assets/garden_profectus_index.md.BmLQh2zb.lean.js rename to assets/garden_profectus_index.md.upNDNXA9.lean.js index 3e0bb7e0..6af7eac9 100644 --- a/assets/garden_profectus_index.md.BmLQh2zb.lean.js +++ b/assets/garden_profectus_index.md.upNDNXA9.lean.js @@ -1 +1 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as s,j as e,a as o,k as a,ag as i,o as d}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"Profectus",-1),m=["innerHTML"],c=i("",9),y=JSON.parse('{"title":"Profectus","description":"","frontmatter":{"public":"true","slug":"profectus","tags":["My Projects"],"title":"Profectus","prev":false,"next":false},"headers":[],"relativePath":"garden/profectus/index.md","filePath":"garden/profectus/index.md"}'),p={name:"garden/profectus/index.md"},P=Object.assign(p,{setup(u){const r=n();return(g,f)=>(d(),s("div",null,[l,e("p",null,[o("73 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,m)]),c]))}});export{y as __pageData,P as default}; +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as s,Q as e,K as o,u as a,ag as i,p as d}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"Profectus",-1),m=["innerHTML"],c=i("",9),y=JSON.parse('{"title":"Profectus","description":"","frontmatter":{"public":"true","slug":"profectus","tags":["My Projects"],"title":"Profectus","prev":false,"next":false},"headers":[],"relativePath":"garden/profectus/index.md","filePath":"garden/profectus/index.md"}'),p={name:"garden/profectus/index.md"},P=Object.assign(p,{setup(u){const r=n();return(g,f)=>(d(),s("div",null,[l,e("p",null,[o("73 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,m)]),c]))}});export{y as __pageData,P as default}; diff --git a/assets/garden_social-media_index.md.DYnTYuzx.js b/assets/garden_social-media_index.md.BdEPqp0F.js similarity index 82% rename from assets/garden_social-media_index.md.DYnTYuzx.js rename to assets/garden_social-media_index.md.BdEPqp0F.js index 4c472b33..f273bbc1 100644 --- a/assets/garden_social-media_index.md.DYnTYuzx.js +++ b/assets/garden_social-media_index.md.BdEPqp0F.js @@ -1 +1 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as l,c as n,j as e,a as o,k as a,ag as r,o as s}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Social Media",-1),c=["innerHTML"],u=r('
Referenced by:CommuneFediverse

Traditional social media

  • Not Decentralized
    • Can't choose your own rules, sorting methods, data queries, etc.
  • Overrun by scams and ads and influencers

Federated Social Media

  • Partially Decentralized
    • Self hosting is too hard for everyone to do
    • Still subject to instance's moderation, limitations, etc.
  • Users need to pick an instance, associating their identity with one specific group
    • People belong to many groups
    • The person is permanently associated with that one group
    • You have to pick before getting a "trial period" to ensure you actually like that group/instance

My take on an ideal social media Fedi v2

',7),v=JSON.parse('{"title":"Social Media","description":"","frontmatter":{"alias":"Social Web","public":"true","slug":"social-media","title":"Social Media","prev":false,"next":false},"headers":[],"relativePath":"garden/social-media/index.md","filePath":"garden/social-media/index.md"}'),m={name:"garden/social-media/index.md"},y=Object.assign(m,{setup(p){const i=l();return(_,h)=>(s(),n("div",null,[d,e("p",null,[o("98 words, ~1 minute read. "),e("span",{innerHTML:a(t)[`site/${a(i).page.value.relativePath}`]},null,8,c)]),u]))}});export{v as __pageData,y as default}; +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as l,q as n,Q as e,K as r,u as a,ag as o,p as s}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Social Media",-1),c=["innerHTML"],u=o('
Referenced by:CommuneFediverse

Traditional social media

  • Not Decentralized
    • Can't choose your own rules, sorting methods, data queries, etc.
  • Overrun by scams and ads and influencers

Federated Social Media

  • Partially Decentralized
    • Self hosting is too hard for everyone to do
    • Still subject to instance's moderation, limitations, etc.
  • Users need to pick an instance, associating their identity with one specific group
    • People belong to many groups
    • The person is permanently associated with that one group
    • You have to pick before getting a "trial period" to ensure you actually like that group/instance

My take on an ideal social media Fedi v2

',7),v=JSON.parse('{"title":"Social Media","description":"","frontmatter":{"alias":"Social Web","public":"true","slug":"social-media","title":"Social Media","prev":false,"next":false},"headers":[],"relativePath":"garden/social-media/index.md","filePath":"garden/social-media/index.md"}'),m={name:"garden/social-media/index.md"},y=Object.assign(m,{setup(p){const i=l();return(_,h)=>(s(),n("div",null,[d,e("p",null,[r("98 words, ~1 minute read. "),e("span",{innerHTML:a(t)[`site/${a(i).page.value.relativePath}`]},null,8,c)]),u]))}});export{v as __pageData,y as default}; diff --git a/assets/garden_social-media_index.md.DYnTYuzx.lean.js b/assets/garden_social-media_index.md.BdEPqp0F.lean.js similarity index 59% rename from assets/garden_social-media_index.md.DYnTYuzx.lean.js rename to assets/garden_social-media_index.md.BdEPqp0F.lean.js index f7334f58..adf11d17 100644 --- a/assets/garden_social-media_index.md.DYnTYuzx.lean.js +++ b/assets/garden_social-media_index.md.BdEPqp0F.lean.js @@ -1 +1 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as l,c as n,j as e,a as o,k as a,ag as r,o as s}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Social Media",-1),c=["innerHTML"],u=r("",7),v=JSON.parse('{"title":"Social Media","description":"","frontmatter":{"alias":"Social Web","public":"true","slug":"social-media","title":"Social Media","prev":false,"next":false},"headers":[],"relativePath":"garden/social-media/index.md","filePath":"garden/social-media/index.md"}'),m={name:"garden/social-media/index.md"},y=Object.assign(m,{setup(p){const i=l();return(_,h)=>(s(),n("div",null,[d,e("p",null,[o("98 words, ~1 minute read. "),e("span",{innerHTML:a(t)[`site/${a(i).page.value.relativePath}`]},null,8,c)]),u]))}});export{v as __pageData,y as default}; +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as l,q as n,Q as e,K as r,u as a,ag as o,p as s}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Social Media",-1),c=["innerHTML"],u=o("",7),v=JSON.parse('{"title":"Social Media","description":"","frontmatter":{"alias":"Social Web","public":"true","slug":"social-media","title":"Social Media","prev":false,"next":false},"headers":[],"relativePath":"garden/social-media/index.md","filePath":"garden/social-media/index.md"}'),m={name:"garden/social-media/index.md"},y=Object.assign(m,{setup(p){const i=l();return(_,h)=>(s(),n("div",null,[d,e("p",null,[r("98 words, ~1 minute read. "),e("span",{innerHTML:a(t)[`site/${a(i).page.value.relativePath}`]},null,8,c)]),u]))}});export{v as __pageData,y as default}; diff --git a/assets/garden_synapse_index.md.BkDI3Nqf.js b/assets/garden_synapse_index.md.BkDI3Nqf.js deleted file mode 100644 index 68b6fce7..00000000 --- a/assets/garden_synapse_index.md.BkDI3Nqf.js +++ /dev/null @@ -1 +0,0 @@ -import{d as s}from"./chunks/git.data.DG5NumsR.js";import{u as r,c as l,j as e,a,k as n,o}from"./chunks/framework.VBE0TPts.js";const i=e("h1",{class:"p-name"},"Synapse",-1),c=["innerHTML"],d=e("hr",null,null,-1),p=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/incremental-social/index.md"},"Incremental Social")],-1),u=e("p",null,[e("a",{href:"https://github.com/element-hq/synapse",target:"_blank",rel:"noreferrer"},"Synapse"),a(" is an "),e("a",{href:"/garden/open-source/"},"Open Source"),a(" server software for the "),e("a",{href:"/garden/matrix/"},"Matrix"),a(" protocol")],-1),x=JSON.parse('{"title":"Synapse","description":"","frontmatter":{"public":"true","slug":"synapse","title":"Synapse","prev":false,"next":false},"headers":[],"relativePath":"garden/synapse/index.md","filePath":"garden/synapse/index.md"}'),_={name:"garden/synapse/index.md"},S=Object.assign(_,{setup(m){const t=r();return(h,f)=>(o(),l("div",null,[i,e("p",null,[a("2 words, ~0 minute read. "),e("span",{innerHTML:n(s)[`site/${n(t).page.value.relativePath}`]},null,8,c)]),d,p,u]))}});export{x as __pageData,S as default}; diff --git a/assets/garden_synapse_index.md.BkDI3Nqf.lean.js b/assets/garden_synapse_index.md.BkDI3Nqf.lean.js deleted file mode 100644 index 68b6fce7..00000000 --- a/assets/garden_synapse_index.md.BkDI3Nqf.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{d as s}from"./chunks/git.data.DG5NumsR.js";import{u as r,c as l,j as e,a,k as n,o}from"./chunks/framework.VBE0TPts.js";const i=e("h1",{class:"p-name"},"Synapse",-1),c=["innerHTML"],d=e("hr",null,null,-1),p=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/incremental-social/index.md"},"Incremental Social")],-1),u=e("p",null,[e("a",{href:"https://github.com/element-hq/synapse",target:"_blank",rel:"noreferrer"},"Synapse"),a(" is an "),e("a",{href:"/garden/open-source/"},"Open Source"),a(" server software for the "),e("a",{href:"/garden/matrix/"},"Matrix"),a(" protocol")],-1),x=JSON.parse('{"title":"Synapse","description":"","frontmatter":{"public":"true","slug":"synapse","title":"Synapse","prev":false,"next":false},"headers":[],"relativePath":"garden/synapse/index.md","filePath":"garden/synapse/index.md"}'),_={name:"garden/synapse/index.md"},S=Object.assign(_,{setup(m){const t=r();return(h,f)=>(o(),l("div",null,[i,e("p",null,[a("2 words, ~0 minute read. "),e("span",{innerHTML:n(s)[`site/${n(t).page.value.relativePath}`]},null,8,c)]),d,p,u]))}});export{x as __pageData,S as default}; diff --git a/assets/garden_synapse_index.md.BvwgQk4N.js b/assets/garden_synapse_index.md.BvwgQk4N.js new file mode 100644 index 00000000..52eedd99 --- /dev/null +++ b/assets/garden_synapse_index.md.BvwgQk4N.js @@ -0,0 +1 @@ +import{d as s}from"./chunks/git.data.DG5NumsR.js";import{M as r,q as l,Q as e,K as a,u as n,p as o}from"./chunks/framework.DvHfxfnp.js";const i=e("h1",{class:"p-name"},"Synapse",-1),d=["innerHTML"],p=e("hr",null,null,-1),c=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/incremental-social/index.md"},"Incremental Social")],-1),u=e("p",null,[e("a",{href:"https://github.com/element-hq/synapse",target:"_blank",rel:"noreferrer"},"Synapse"),a(" is an "),e("a",{href:"/garden/open-source/"},"Open Source"),a(" server software for the "),e("a",{href:"/garden/matrix/"},"Matrix"),a(" protocol")],-1),x=JSON.parse('{"title":"Synapse","description":"","frontmatter":{"public":"true","slug":"synapse","title":"Synapse","prev":false,"next":false},"headers":[],"relativePath":"garden/synapse/index.md","filePath":"garden/synapse/index.md"}'),_={name:"garden/synapse/index.md"},S=Object.assign(_,{setup(m){const t=r();return(h,f)=>(o(),l("div",null,[i,e("p",null,[a("2 words, ~0 minute read. "),e("span",{innerHTML:n(s)[`site/${n(t).page.value.relativePath}`]},null,8,d)]),p,c,u]))}});export{x as __pageData,S as default}; diff --git a/assets/garden_synapse_index.md.BvwgQk4N.lean.js b/assets/garden_synapse_index.md.BvwgQk4N.lean.js new file mode 100644 index 00000000..52eedd99 --- /dev/null +++ b/assets/garden_synapse_index.md.BvwgQk4N.lean.js @@ -0,0 +1 @@ +import{d as s}from"./chunks/git.data.DG5NumsR.js";import{M as r,q as l,Q as e,K as a,u as n,p as o}from"./chunks/framework.DvHfxfnp.js";const i=e("h1",{class:"p-name"},"Synapse",-1),d=["innerHTML"],p=e("hr",null,null,-1),c=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/incremental-social/index.md"},"Incremental Social")],-1),u=e("p",null,[e("a",{href:"https://github.com/element-hq/synapse",target:"_blank",rel:"noreferrer"},"Synapse"),a(" is an "),e("a",{href:"/garden/open-source/"},"Open Source"),a(" server software for the "),e("a",{href:"/garden/matrix/"},"Matrix"),a(" protocol")],-1),x=JSON.parse('{"title":"Synapse","description":"","frontmatter":{"public":"true","slug":"synapse","title":"Synapse","prev":false,"next":false},"headers":[],"relativePath":"garden/synapse/index.md","filePath":"garden/synapse/index.md"}'),_={name:"garden/synapse/index.md"},S=Object.assign(_,{setup(m){const t=r();return(h,f)=>(o(),l("div",null,[i,e("p",null,[a("2 words, ~0 minute read. "),e("span",{innerHTML:n(s)[`site/${n(t).page.value.relativePath}`]},null,8,d)]),p,c,u]))}});export{x as __pageData,S as default}; diff --git a/assets/garden_the-beginner-s-guide_index.md.Bh4pwbi0.js b/assets/garden_the-beginner-s-guide_index.md.CaCS8ERA.js similarity index 79% rename from assets/garden_the-beginner-s-guide_index.md.Bh4pwbi0.js rename to assets/garden_the-beginner-s-guide_index.md.CaCS8ERA.js index 083323a0..70ccd7de 100644 --- a/assets/garden_the-beginner-s-guide_index.md.Bh4pwbi0.js +++ b/assets/garden_the-beginner-s-guide_index.md.CaCS8ERA.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as t,c as s,j as e,a as i,k as a,ag as d,o as l}from"./chunks/framework.VBE0TPts.js";const o=e("h1",{class:"p-name"},"The Beginner's Guide",-1),u=["innerHTML"],h=d('
Referenced by:Davey Wreden
Tags:Davey Wreden

My favorite video game of all time, bar none. Created by Davey Wreden

The game broadly comments on the relationship between creators and consumers, and it can apply to all forms of art

  • Perhaps also an important commentary on parasocial relationships

Important analyses:

',8),y=JSON.parse(`{"title":"The Beginner's Guide","description":"","frontmatter":{"public":"true","slug":"the-beginner-s-guide","tags":["Davey Wreden"],"title":"The Beginner's Guide","prev":false,"next":false},"headers":[],"relativePath":"garden/the-beginner-s-guide/index.md","filePath":"garden/the-beginner-s-guide/index.md"}`),c={name:"garden/the-beginner-s-guide/index.md"},b=Object.assign(c,{setup(m){const r=t();return(p,g)=>(l(),s("div",null,[o,e("p",null,[i("70 words, ~0 minute read. "),e("span",{innerHTML:a(n)[`site/${a(r).page.value.relativePath}`]},null,8,u)]),h]))}});export{y as __pageData,b as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as t,q as s,Q as e,K as i,u as a,ag as d,p as l}from"./chunks/framework.DvHfxfnp.js";const o=e("h1",{class:"p-name"},"The Beginner's Guide",-1),u=["innerHTML"],h=d('
Referenced by:Davey Wreden
Tags:Davey Wreden

My favorite video game of all time, bar none. Created by Davey Wreden

The game broadly comments on the relationship between creators and consumers, and it can apply to all forms of art

  • Perhaps also an important commentary on parasocial relationships

Important analyses:

',8),y=JSON.parse(`{"title":"The Beginner's Guide","description":"","frontmatter":{"public":"true","slug":"the-beginner-s-guide","tags":["Davey Wreden"],"title":"The Beginner's Guide","prev":false,"next":false},"headers":[],"relativePath":"garden/the-beginner-s-guide/index.md","filePath":"garden/the-beginner-s-guide/index.md"}`),m={name:"garden/the-beginner-s-guide/index.md"},b=Object.assign(m,{setup(p){const r=t();return(c,g)=>(l(),s("div",null,[o,e("p",null,[i("70 words, ~0 minute read. "),e("span",{innerHTML:a(n)[`site/${a(r).page.value.relativePath}`]},null,8,u)]),h]))}});export{y as __pageData,b as default}; diff --git a/assets/garden_the-beginner-s-guide_index.md.Bh4pwbi0.lean.js b/assets/garden_the-beginner-s-guide_index.md.CaCS8ERA.lean.js similarity index 54% rename from assets/garden_the-beginner-s-guide_index.md.Bh4pwbi0.lean.js rename to assets/garden_the-beginner-s-guide_index.md.CaCS8ERA.lean.js index 1f47b07d..5f8ae8da 100644 --- a/assets/garden_the-beginner-s-guide_index.md.Bh4pwbi0.lean.js +++ b/assets/garden_the-beginner-s-guide_index.md.CaCS8ERA.lean.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as t,c as s,j as e,a as i,k as a,ag as d,o as l}from"./chunks/framework.VBE0TPts.js";const o=e("h1",{class:"p-name"},"The Beginner's Guide",-1),u=["innerHTML"],h=d("",8),y=JSON.parse(`{"title":"The Beginner's Guide","description":"","frontmatter":{"public":"true","slug":"the-beginner-s-guide","tags":["Davey Wreden"],"title":"The Beginner's Guide","prev":false,"next":false},"headers":[],"relativePath":"garden/the-beginner-s-guide/index.md","filePath":"garden/the-beginner-s-guide/index.md"}`),c={name:"garden/the-beginner-s-guide/index.md"},b=Object.assign(c,{setup(m){const r=t();return(p,g)=>(l(),s("div",null,[o,e("p",null,[i("70 words, ~0 minute read. "),e("span",{innerHTML:a(n)[`site/${a(r).page.value.relativePath}`]},null,8,u)]),h]))}});export{y as __pageData,b as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as t,q as s,Q as e,K as i,u as a,ag as d,p as l}from"./chunks/framework.DvHfxfnp.js";const o=e("h1",{class:"p-name"},"The Beginner's Guide",-1),u=["innerHTML"],h=d("",8),y=JSON.parse(`{"title":"The Beginner's Guide","description":"","frontmatter":{"public":"true","slug":"the-beginner-s-guide","tags":["Davey Wreden"],"title":"The Beginner's Guide","prev":false,"next":false},"headers":[],"relativePath":"garden/the-beginner-s-guide/index.md","filePath":"garden/the-beginner-s-guide/index.md"}`),m={name:"garden/the-beginner-s-guide/index.md"},b=Object.assign(m,{setup(p){const r=t();return(c,g)=>(l(),s("div",null,[o,e("p",null,[i("70 words, ~0 minute read. "),e("span",{innerHTML:a(n)[`site/${a(r).page.value.relativePath}`]},null,8,u)]),h]))}});export{y as __pageData,b as default}; diff --git a/assets/garden_the-cozy-web_index.md.Dphn0Ga1.js b/assets/garden_the-cozy-web_index.md.BlzW7dqM.js similarity index 86% rename from assets/garden_the-cozy-web_index.md.Dphn0Ga1.js rename to assets/garden_the-cozy-web_index.md.BlzW7dqM.js index f0e7b95b..13eac7f0 100644 --- a/assets/garden_the-cozy-web_index.md.Dphn0Ga1.js +++ b/assets/garden_the-cozy-web_index.md.BlzW7dqM.js @@ -1 +1 @@ -import{d as o}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as r,j as e,a as t,k as a,o as l}from"./chunks/framework.VBE0TPts.js";const i=e("h1",{class:"p-name"},"The Cozy Web",-1),d=["innerHTML"],h=e("hr",null,null,-1),c=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/digital-gardens/index.md"},"Digital Gardens")],-1),p=e("p",null,"The Cozy Web is an extension of the dark forest theory of the Internet",-1),_=e("p",null,"It refers to the part of the web that is not web indexable",-1),u=e("p",null,"This part of the web is known for not typically having ads or marketers",-1),f=e("p",null,[t("Popularized by "),e("a",{href:"https://maggieappleton.com/cozy-web",target:"_blank",rel:"noreferrer"},"this article"),t(" written by Maggie Appleton, who has also written a lot about "),e("a",{href:"/garden/digital-gardens/"},"Digital Gardens")],-1),z=JSON.parse('{"title":"The Cozy Web","description":"","frontmatter":{"public":"true","slug":"the-cozy-web","title":"The Cozy Web","prev":false,"next":false},"headers":[],"relativePath":"garden/the-cozy-web/index.md","filePath":"garden/the-cozy-web/index.md"}'),g={name:"garden/the-cozy-web/index.md"},T=Object.assign(g,{setup(b){const n=s();return(m,y)=>(l(),r("div",null,[i,e("p",null,[t("45 words, ~0 minute read. "),e("span",{innerHTML:a(o)[`site/${a(n).page.value.relativePath}`]},null,8,d)]),h,c,p,_,u,f]))}});export{z as __pageData,T as default}; +import{d as o}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as r,Q as e,K as t,u as a,p as l}from"./chunks/framework.DvHfxfnp.js";const i=e("h1",{class:"p-name"},"The Cozy Web",-1),d=["innerHTML"],h=e("hr",null,null,-1),c=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/digital-gardens/index.md"},"Digital Gardens")],-1),p=e("p",null,"The Cozy Web is an extension of the dark forest theory of the Internet",-1),_=e("p",null,"It refers to the part of the web that is not web indexable",-1),u=e("p",null,"This part of the web is known for not typically having ads or marketers",-1),f=e("p",null,[t("Popularized by "),e("a",{href:"https://maggieappleton.com/cozy-web",target:"_blank",rel:"noreferrer"},"this article"),t(" written by Maggie Appleton, who has also written a lot about "),e("a",{href:"/garden/digital-gardens/"},"Digital Gardens")],-1),z=JSON.parse('{"title":"The Cozy Web","description":"","frontmatter":{"public":"true","slug":"the-cozy-web","title":"The Cozy Web","prev":false,"next":false},"headers":[],"relativePath":"garden/the-cozy-web/index.md","filePath":"garden/the-cozy-web/index.md"}'),g={name:"garden/the-cozy-web/index.md"},T=Object.assign(g,{setup(b){const n=s();return(m,y)=>(l(),r("div",null,[i,e("p",null,[t("45 words, ~0 minute read. "),e("span",{innerHTML:a(o)[`site/${a(n).page.value.relativePath}`]},null,8,d)]),h,c,p,_,u,f]))}});export{z as __pageData,T as default}; diff --git a/assets/garden_the-cozy-web_index.md.Dphn0Ga1.lean.js b/assets/garden_the-cozy-web_index.md.BlzW7dqM.lean.js similarity index 86% rename from assets/garden_the-cozy-web_index.md.Dphn0Ga1.lean.js rename to assets/garden_the-cozy-web_index.md.BlzW7dqM.lean.js index f0e7b95b..13eac7f0 100644 --- a/assets/garden_the-cozy-web_index.md.Dphn0Ga1.lean.js +++ b/assets/garden_the-cozy-web_index.md.BlzW7dqM.lean.js @@ -1 +1 @@ -import{d as o}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as r,j as e,a as t,k as a,o as l}from"./chunks/framework.VBE0TPts.js";const i=e("h1",{class:"p-name"},"The Cozy Web",-1),d=["innerHTML"],h=e("hr",null,null,-1),c=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/digital-gardens/index.md"},"Digital Gardens")],-1),p=e("p",null,"The Cozy Web is an extension of the dark forest theory of the Internet",-1),_=e("p",null,"It refers to the part of the web that is not web indexable",-1),u=e("p",null,"This part of the web is known for not typically having ads or marketers",-1),f=e("p",null,[t("Popularized by "),e("a",{href:"https://maggieappleton.com/cozy-web",target:"_blank",rel:"noreferrer"},"this article"),t(" written by Maggie Appleton, who has also written a lot about "),e("a",{href:"/garden/digital-gardens/"},"Digital Gardens")],-1),z=JSON.parse('{"title":"The Cozy Web","description":"","frontmatter":{"public":"true","slug":"the-cozy-web","title":"The Cozy Web","prev":false,"next":false},"headers":[],"relativePath":"garden/the-cozy-web/index.md","filePath":"garden/the-cozy-web/index.md"}'),g={name:"garden/the-cozy-web/index.md"},T=Object.assign(g,{setup(b){const n=s();return(m,y)=>(l(),r("div",null,[i,e("p",null,[t("45 words, ~0 minute read. "),e("span",{innerHTML:a(o)[`site/${a(n).page.value.relativePath}`]},null,8,d)]),h,c,p,_,u,f]))}});export{z as __pageData,T as default}; +import{d as o}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as r,Q as e,K as t,u as a,p as l}from"./chunks/framework.DvHfxfnp.js";const i=e("h1",{class:"p-name"},"The Cozy Web",-1),d=["innerHTML"],h=e("hr",null,null,-1),c=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/digital-gardens/index.md"},"Digital Gardens")],-1),p=e("p",null,"The Cozy Web is an extension of the dark forest theory of the Internet",-1),_=e("p",null,"It refers to the part of the web that is not web indexable",-1),u=e("p",null,"This part of the web is known for not typically having ads or marketers",-1),f=e("p",null,[t("Popularized by "),e("a",{href:"https://maggieappleton.com/cozy-web",target:"_blank",rel:"noreferrer"},"this article"),t(" written by Maggie Appleton, who has also written a lot about "),e("a",{href:"/garden/digital-gardens/"},"Digital Gardens")],-1),z=JSON.parse('{"title":"The Cozy Web","description":"","frontmatter":{"public":"true","slug":"the-cozy-web","title":"The Cozy Web","prev":false,"next":false},"headers":[],"relativePath":"garden/the-cozy-web/index.md","filePath":"garden/the-cozy-web/index.md"}'),g={name:"garden/the-cozy-web/index.md"},T=Object.assign(g,{setup(b){const n=s();return(m,y)=>(l(),r("div",null,[i,e("p",null,[t("45 words, ~0 minute read. "),e("span",{innerHTML:a(o)[`site/${a(n).page.value.relativePath}`]},null,8,d)]),h,c,p,_,u,f]))}});export{z as __pageData,T as default}; diff --git a/assets/garden_the-indieweb_amplification_index.md.CdpguDI2.js b/assets/garden_the-indieweb_amplification_index.md.C7orSKJb.js similarity index 89% rename from assets/garden_the-indieweb_amplification_index.md.CdpguDI2.js rename to assets/garden_the-indieweb_amplification_index.md.C7orSKJb.js index 5e4eeb82..9752ce42 100644 --- a/assets/garden_the-indieweb_amplification_index.md.CdpguDI2.js +++ b/assets/garden_the-indieweb_amplification_index.md.C7orSKJb.js @@ -1 +1 @@ -import{d as i}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as s,j as e,a as r,k as a,ag as o,o as d}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"The IndieWeb___Amplification",-1),c=["innerHTML"],m=o('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

Refers to reblogging (and re-hosting, sometimes) of someone else's content on your own site

The Internet is a series of webs discusses some ideas and best practices for amplification

To ensure the rehosted content actually came from the claimed author and was not tampered with, all content should be signed using The IndieWeb/Signature Blocks

',5),b=JSON.parse('{"title":"The IndieWeb/Amplification","description":"","frontmatter":{"public":"true","slug":"the-indieweb/amplification","title":"The IndieWeb/Amplification","prev":false,"next":false},"headers":[],"relativePath":"garden/the-indieweb/amplification/index.md","filePath":"garden/the-indieweb/amplification/index.md"}'),h={name:"garden/the-indieweb/amplification/index.md"},T=Object.assign(h,{setup(p){const t=n();return(_,f)=>(d(),s("div",null,[l,e("p",null,[r("57 words, ~0 minute read. "),e("span",{innerHTML:a(i)[`site/${a(t).page.value.relativePath}`]},null,8,c)]),m]))}});export{b as __pageData,T as default}; +import{d as i}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as s,Q as e,K as r,u as a,ag as o,p as d}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"The IndieWeb___Amplification",-1),c=["innerHTML"],m=o('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

Refers to reblogging (and re-hosting, sometimes) of someone else's content on your own site

The Internet is a series of webs discusses some ideas and best practices for amplification

To ensure the rehosted content actually came from the claimed author and was not tampered with, all content should be signed using The IndieWeb/Signature Blocks

',5),b=JSON.parse('{"title":"The IndieWeb/Amplification","description":"","frontmatter":{"public":"true","slug":"the-indieweb/amplification","title":"The IndieWeb/Amplification","prev":false,"next":false},"headers":[],"relativePath":"garden/the-indieweb/amplification/index.md","filePath":"garden/the-indieweb/amplification/index.md"}'),h={name:"garden/the-indieweb/amplification/index.md"},T=Object.assign(h,{setup(p){const t=n();return(_,f)=>(d(),s("div",null,[l,e("p",null,[r("57 words, ~0 minute read. "),e("span",{innerHTML:a(i)[`site/${a(t).page.value.relativePath}`]},null,8,c)]),m]))}});export{b as __pageData,T as default}; diff --git a/assets/garden_the-indieweb_amplification_index.md.CdpguDI2.lean.js b/assets/garden_the-indieweb_amplification_index.md.C7orSKJb.lean.js similarity index 77% rename from assets/garden_the-indieweb_amplification_index.md.CdpguDI2.lean.js rename to assets/garden_the-indieweb_amplification_index.md.C7orSKJb.lean.js index 52161582..4a8a5c97 100644 --- a/assets/garden_the-indieweb_amplification_index.md.CdpguDI2.lean.js +++ b/assets/garden_the-indieweb_amplification_index.md.C7orSKJb.lean.js @@ -1 +1 @@ -import{d as i}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as s,j as e,a as r,k as a,ag as o,o as d}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"The IndieWeb___Amplification",-1),c=["innerHTML"],m=o("",5),b=JSON.parse('{"title":"The IndieWeb/Amplification","description":"","frontmatter":{"public":"true","slug":"the-indieweb/amplification","title":"The IndieWeb/Amplification","prev":false,"next":false},"headers":[],"relativePath":"garden/the-indieweb/amplification/index.md","filePath":"garden/the-indieweb/amplification/index.md"}'),h={name:"garden/the-indieweb/amplification/index.md"},T=Object.assign(h,{setup(p){const t=n();return(_,f)=>(d(),s("div",null,[l,e("p",null,[r("57 words, ~0 minute read. "),e("span",{innerHTML:a(i)[`site/${a(t).page.value.relativePath}`]},null,8,c)]),m]))}});export{b as __pageData,T as default}; +import{d as i}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as s,Q as e,K as r,u as a,ag as o,p as d}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"The IndieWeb___Amplification",-1),c=["innerHTML"],m=o("",5),b=JSON.parse('{"title":"The IndieWeb/Amplification","description":"","frontmatter":{"public":"true","slug":"the-indieweb/amplification","title":"The IndieWeb/Amplification","prev":false,"next":false},"headers":[],"relativePath":"garden/the-indieweb/amplification/index.md","filePath":"garden/the-indieweb/amplification/index.md"}'),h={name:"garden/the-indieweb/amplification/index.md"},T=Object.assign(h,{setup(p){const t=n();return(_,f)=>(d(),s("div",null,[l,e("p",null,[r("57 words, ~0 minute read. "),e("span",{innerHTML:a(i)[`site/${a(t).page.value.relativePath}`]},null,8,c)]),m]))}});export{b as __pageData,T as default}; diff --git a/assets/garden_the-indieweb_signature-blocks_index.md.Cb_LJurF.js b/assets/garden_the-indieweb_signature-blocks_index.md.Cb_LJurF.js new file mode 100644 index 00000000..3ae5ac94 --- /dev/null +++ b/assets/garden_the-indieweb_signature-blocks_index.md.Cb_LJurF.js @@ -0,0 +1 @@ +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as s,Q as e,K as r,u as a,ag as d,p as o}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"The IndieWeb___Signature Blocks",-1),c=["innerHTML"],_=d('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

A proposal I want to write for posting signed content on your IndieWeb website

',3),f=JSON.parse('{"title":"The IndieWeb/Signature Blocks","description":"","frontmatter":{"public":"true","slug":"the-indieweb/signature-blocks","title":"The IndieWeb/Signature Blocks","prev":false,"next":false},"headers":[],"relativePath":"garden/the-indieweb/signature-blocks/index.md","filePath":"garden/the-indieweb/signature-blocks/index.md"}'),g={name:"garden/the-indieweb/signature-blocks/index.md"},x=Object.assign(g,{setup(m){const n=i();return(u,h)=>(o(),s("div",null,[l,e("p",null,[r("14 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(n).page.value.relativePath}`]},null,8,c)]),_]))}});export{f as __pageData,x as default}; diff --git a/assets/garden_the-indieweb_signature-blocks_index.md.Cb_LJurF.lean.js b/assets/garden_the-indieweb_signature-blocks_index.md.Cb_LJurF.lean.js new file mode 100644 index 00000000..f7a77d92 --- /dev/null +++ b/assets/garden_the-indieweb_signature-blocks_index.md.Cb_LJurF.lean.js @@ -0,0 +1 @@ +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as s,Q as e,K as r,u as a,ag as d,p as o}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"The IndieWeb___Signature Blocks",-1),c=["innerHTML"],_=d("",3),f=JSON.parse('{"title":"The IndieWeb/Signature Blocks","description":"","frontmatter":{"public":"true","slug":"the-indieweb/signature-blocks","title":"The IndieWeb/Signature Blocks","prev":false,"next":false},"headers":[],"relativePath":"garden/the-indieweb/signature-blocks/index.md","filePath":"garden/the-indieweb/signature-blocks/index.md"}'),g={name:"garden/the-indieweb/signature-blocks/index.md"},x=Object.assign(g,{setup(m){const n=i();return(u,h)=>(o(),s("div",null,[l,e("p",null,[r("14 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(n).page.value.relativePath}`]},null,8,c)]),_]))}});export{f as __pageData,x as default}; diff --git a/assets/garden_the-indieweb_signature-blocks_index.md.ZTvTccur.js b/assets/garden_the-indieweb_signature-blocks_index.md.ZTvTccur.js deleted file mode 100644 index 3db584cf..00000000 --- a/assets/garden_the-indieweb_signature-blocks_index.md.ZTvTccur.js +++ /dev/null @@ -1 +0,0 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as i,c as s,j as e,a as r,k as a,ag as d,o}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"The IndieWeb___Signature Blocks",-1),c=["innerHTML"],_=d('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

A proposal I want to write for posting signed content on your IndieWeb website

',3),f=JSON.parse('{"title":"The IndieWeb/Signature Blocks","description":"","frontmatter":{"public":"true","slug":"the-indieweb/signature-blocks","title":"The IndieWeb/Signature Blocks","prev":false,"next":false},"headers":[],"relativePath":"garden/the-indieweb/signature-blocks/index.md","filePath":"garden/the-indieweb/signature-blocks/index.md"}'),g={name:"garden/the-indieweb/signature-blocks/index.md"},x=Object.assign(g,{setup(m){const n=i();return(u,h)=>(o(),s("div",null,[l,e("p",null,[r("14 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(n).page.value.relativePath}`]},null,8,c)]),_]))}});export{f as __pageData,x as default}; diff --git a/assets/garden_the-indieweb_signature-blocks_index.md.ZTvTccur.lean.js b/assets/garden_the-indieweb_signature-blocks_index.md.ZTvTccur.lean.js deleted file mode 100644 index 3b783400..00000000 --- a/assets/garden_the-indieweb_signature-blocks_index.md.ZTvTccur.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as i,c as s,j as e,a as r,k as a,ag as d,o}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"The IndieWeb___Signature Blocks",-1),c=["innerHTML"],_=d("",3),f=JSON.parse('{"title":"The IndieWeb/Signature Blocks","description":"","frontmatter":{"public":"true","slug":"the-indieweb/signature-blocks","title":"The IndieWeb/Signature Blocks","prev":false,"next":false},"headers":[],"relativePath":"garden/the-indieweb/signature-blocks/index.md","filePath":"garden/the-indieweb/signature-blocks/index.md"}'),g={name:"garden/the-indieweb/signature-blocks/index.md"},x=Object.assign(g,{setup(m){const n=i();return(u,h)=>(o(),s("div",null,[l,e("p",null,[r("14 words, ~0 minute read. "),e("span",{innerHTML:a(t)[`site/${a(n).page.value.relativePath}`]},null,8,c)]),_]))}});export{f as __pageData,x as default}; diff --git a/assets/garden_the-small-web_index.md.C-NKW4Ch.js b/assets/garden_the-small-web_index.md.BXEnXP2C.js similarity index 97% rename from assets/garden_the-small-web_index.md.C-NKW4Ch.js rename to assets/garden_the-small-web_index.md.BXEnXP2C.js index 4e9e3be0..29b5322a 100644 --- a/assets/garden_the-small-web_index.md.C-NKW4Ch.js +++ b/assets/garden_the-small-web_index.md.BXEnXP2C.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as o,c as i,j as e,a as s,k as a,ag as n,o as l}from"./chunks/framework.VBE0TPts.js";const h=e("h1",{class:"p-name"},"The Small Web",-1),d=["innerHTML"],b=n('
Referenced by:CommuneFederated IdentityFedi v2My Personal Website/nowThe IndieWeb/Signature BlocksThis Knowledge HubWebringsWeird

The small web (also known as the indie web, personal web, the web revival movement, and other terms) refers to small, personal, independent websites. It is seen as a direct alternative to the centralized and homogenized websites like X, Meta, and TikTok. My Personal Website is part of the small web!

Motivation behind the small web

The modern web is bad

The small web is, at its roots, a direct response to the issues with the modern web:

The modern web is dominated by a handful of large websites, sometimes referred to as the "corporate web". These websites limit personalization, how you can use the website, and are filled with ads, marketers, and influencers.

The corporate web is designed for consuming content created by a few large/popular creators. This manifests in the near-ubiquitous infinitely scrolling feed of algorithmically chosen posts, optimized to keep you on the site for as long as possible, to the detriment of society.

Websites this large are expensive and, due to Capitalism, must forever be making more money than before - which means if they're not growing users, they must grow how much money they're making per user. This process typically means corporate websites become worse for their users over time, and was coined as Enshittification by Cory Doctorow.

The old web was good

In contrast to the above, the classic web was filled with many diverse sites that typically represented a single person or organization, who were able to fully tailor their site to what they wanted it to be. Websites would be more unique and interesting, since the creator would have full control over them. This also makes the whole web feel more personal and intimate, as you're looking at a closer representation of how someone chooses to portray themselves online, in a way a profile page on X or Meta cannot be.

There are still lessons we've learned over time that can apply to modern "small web" pages, like accessible design and how to be more inclusive.

The small web is anti-corporate

Small static websites are very cheap to host, making anti-features like ads unnecessary and therefore rare. In general small websites are cheap enough to avoid needing to think about monetization entirely, let alone worrying about how to perpetually make more money. This lack of profit motive behind most small websites contributes to a culture of not just being "not corporate", but "anti-corporate".

In general, the corporate web seems to have values that align with those of authoritarianism - control, surveillance, and hierarchy, whereas the small web aligns with anarchist values - autonomy, cooperation, and egalitarianism.

Further reading

These are videos and articles that continue expanding on the values and motivations behind the small web as an alternative to the corporate web:

Browsing the small web

Follow Webrings or other links from known small websites.

Marginalia is a search engine for non-commercial content with a "random" button and filters for the small web explicitly (amongst other useful filters!)

The Tildeverse contains a large set of personal websites.

  • Pick one of the member sites, and they'll have a list of all their users, who each have a custom page. Some may also list most recently updated pages, which is a good way of filtering out default pages.
  • You may also consider joining one of these communities. They're effectively shared Linux computers, with a focus on small tight knit communities as an alternative to social media. Great if you're interested in learning Linux and command line utilities!

Building personal websites

IndieWeb contains various information and resources on building personal websites that use open standards to better interact with readers and other sites consistently. Check out IndieWebify Me to get assistance implementing their standards.

Free hosting for static websites:

Other resources:

Streams

Microsub is a proposed protocol to support hosting streams of content on personal websites in a way they can be consistently ingested by microsub clients. This way, people could subscribe to multiple streams on independent websites and get them in one feed. Through this, the indie web becomes a Federated Social Media.

Streams also allow your personal website to be the one source of truth for your posted content, in a concept called POSSE - Publish (on your) Own Site, Syndicate Elsewhere (other social media sites). This would effectively solve the problems described in Hey Creators, Please Make Firehoses!

Multiple streams can be hosted by one site/person so people can subscribe to the kind of content they're interested in.

Digital Gardens

These sites may be useful to occasionally check up on rather than get notifications from on every post/change

  • Although Garden-RSS could allow those who want to receive notifications to do so

The future

The Internet is a series of webs talks about transitioning from our current consolidated web back to the indie web

',38),w=JSON.parse('{"title":"The Small Web","description":"","frontmatter":{"alias":"The IndieWeb, Personal Web, Personal Websites, IndieWeb","public":"true","slug":"the-small-web","title":"The Small Web","prev":false,"next":false},"headers":[],"relativePath":"garden/the-small-web/index.md","filePath":"garden/the-small-web/index.md"}'),c={name:"garden/the-small-web/index.md"},y=Object.assign(c,{setup(m){const t=o();return(u,p)=>(l(),i("div",null,[h,e("p",null,[s("778 words, ~4 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,d)]),b]))}});export{w as __pageData,y as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as o,Q as e,K as s,u as a,ag as n,p as l}from"./chunks/framework.DvHfxfnp.js";const h=e("h1",{class:"p-name"},"The Small Web",-1),d=["innerHTML"],b=n('
Referenced by:CommuneFederated IdentityFedi v2My Personal Website/nowThe IndieWeb/Signature BlocksThis Knowledge HubWebringsWeird

The small web (also known as the indie web, personal web, the web revival movement, and other terms) refers to small, personal, independent websites. It is seen as a direct alternative to the centralized and homogenized websites like X, Meta, and TikTok. My Personal Website is part of the small web!

Motivation behind the small web

The modern web is bad

The small web is, at its roots, a direct response to the issues with the modern web:

The modern web is dominated by a handful of large websites, sometimes referred to as the "corporate web". These websites limit personalization, how you can use the website, and are filled with ads, marketers, and influencers.

The corporate web is designed for consuming content created by a few large/popular creators. This manifests in the near-ubiquitous infinitely scrolling feed of algorithmically chosen posts, optimized to keep you on the site for as long as possible, to the detriment of society.

Websites this large are expensive and, due to Capitalism, must forever be making more money than before - which means if they're not growing users, they must grow how much money they're making per user. This process typically means corporate websites become worse for their users over time, and was coined as Enshittification by Cory Doctorow.

The old web was good

In contrast to the above, the classic web was filled with many diverse sites that typically represented a single person or organization, who were able to fully tailor their site to what they wanted it to be. Websites would be more unique and interesting, since the creator would have full control over them. This also makes the whole web feel more personal and intimate, as you're looking at a closer representation of how someone chooses to portray themselves online, in a way a profile page on X or Meta cannot be.

There are still lessons we've learned over time that can apply to modern "small web" pages, like accessible design and how to be more inclusive.

The small web is anti-corporate

Small static websites are very cheap to host, making anti-features like ads unnecessary and therefore rare. In general small websites are cheap enough to avoid needing to think about monetization entirely, let alone worrying about how to perpetually make more money. This lack of profit motive behind most small websites contributes to a culture of not just being "not corporate", but "anti-corporate".

In general, the corporate web seems to have values that align with those of authoritarianism - control, surveillance, and hierarchy, whereas the small web aligns with anarchist values - autonomy, cooperation, and egalitarianism.

Further reading

These are videos and articles that continue expanding on the values and motivations behind the small web as an alternative to the corporate web:

Browsing the small web

Follow Webrings or other links from known small websites.

Marginalia is a search engine for non-commercial content with a "random" button and filters for the small web explicitly (amongst other useful filters!)

The Tildeverse contains a large set of personal websites.

  • Pick one of the member sites, and they'll have a list of all their users, who each have a custom page. Some may also list most recently updated pages, which is a good way of filtering out default pages.
  • You may also consider joining one of these communities. They're effectively shared Linux computers, with a focus on small tight knit communities as an alternative to social media. Great if you're interested in learning Linux and command line utilities!

Building personal websites

IndieWeb contains various information and resources on building personal websites that use open standards to better interact with readers and other sites consistently. Check out IndieWebify Me to get assistance implementing their standards.

Free hosting for static websites:

Other resources:

Streams

Microsub is a proposed protocol to support hosting streams of content on personal websites in a way they can be consistently ingested by microsub clients. This way, people could subscribe to multiple streams on independent websites and get them in one feed. Through this, the indie web becomes a Federated Social Media.

Streams also allow your personal website to be the one source of truth for your posted content, in a concept called POSSE - Publish (on your) Own Site, Syndicate Elsewhere (other social media sites). This would effectively solve the problems described in Hey Creators, Please Make Firehoses!

Multiple streams can be hosted by one site/person so people can subscribe to the kind of content they're interested in.

Digital Gardens

These sites may be useful to occasionally check up on rather than get notifications from on every post/change

  • Although Garden-RSS could allow those who want to receive notifications to do so

The future

The Internet is a series of webs talks about transitioning from our current consolidated web back to the indie web

',38),w=JSON.parse('{"title":"The Small Web","description":"","frontmatter":{"alias":"The IndieWeb, Personal Web, Personal Websites, IndieWeb","public":"true","slug":"the-small-web","title":"The Small Web","prev":false,"next":false},"headers":[],"relativePath":"garden/the-small-web/index.md","filePath":"garden/the-small-web/index.md"}'),c={name:"garden/the-small-web/index.md"},y=Object.assign(c,{setup(m){const t=i();return(u,p)=>(l(),o("div",null,[h,e("p",null,[s("778 words, ~4 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,d)]),b]))}});export{w as __pageData,y as default}; diff --git a/assets/garden_the-small-web_index.md.C-NKW4Ch.lean.js b/assets/garden_the-small-web_index.md.BXEnXP2C.lean.js similarity index 61% rename from assets/garden_the-small-web_index.md.C-NKW4Ch.lean.js rename to assets/garden_the-small-web_index.md.BXEnXP2C.lean.js index 422c1ec4..bc3c8b6c 100644 --- a/assets/garden_the-small-web_index.md.C-NKW4Ch.lean.js +++ b/assets/garden_the-small-web_index.md.BXEnXP2C.lean.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as o,c as i,j as e,a as s,k as a,ag as n,o as l}from"./chunks/framework.VBE0TPts.js";const h=e("h1",{class:"p-name"},"The Small Web",-1),d=["innerHTML"],b=n("",38),w=JSON.parse('{"title":"The Small Web","description":"","frontmatter":{"alias":"The IndieWeb, Personal Web, Personal Websites, IndieWeb","public":"true","slug":"the-small-web","title":"The Small Web","prev":false,"next":false},"headers":[],"relativePath":"garden/the-small-web/index.md","filePath":"garden/the-small-web/index.md"}'),c={name:"garden/the-small-web/index.md"},y=Object.assign(c,{setup(m){const t=o();return(u,p)=>(l(),i("div",null,[h,e("p",null,[s("778 words, ~4 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,d)]),b]))}});export{w as __pageData,y as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as o,Q as e,K as s,u as a,ag as n,p as l}from"./chunks/framework.DvHfxfnp.js";const h=e("h1",{class:"p-name"},"The Small Web",-1),d=["innerHTML"],b=n("",38),w=JSON.parse('{"title":"The Small Web","description":"","frontmatter":{"alias":"The IndieWeb, Personal Web, Personal Websites, IndieWeb","public":"true","slug":"the-small-web","title":"The Small Web","prev":false,"next":false},"headers":[],"relativePath":"garden/the-small-web/index.md","filePath":"garden/the-small-web/index.md"}'),c={name:"garden/the-small-web/index.md"},y=Object.assign(c,{setup(m){const t=i();return(u,p)=>(l(),o("div",null,[h,e("p",null,[s("778 words, ~4 minute read. "),e("span",{innerHTML:a(r)[`site/${a(t).page.value.relativePath}`]},null,8,d)]),b]))}});export{w as __pageData,y as default}; diff --git a/assets/garden_this-knowledge-hub_index.md.BDMSkEmc.js b/assets/garden_this-knowledge-hub_index.md.BDMSkEmc.js new file mode 100644 index 00000000..bebc31b5 --- /dev/null +++ b/assets/garden_this-knowledge-hub_index.md.BDMSkEmc.js @@ -0,0 +1 @@ +import{d as s}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as n,Q as e,K as r,u as a,ag as l,p as o}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"This Knowledge Hub",-1),h=["innerHTML"],g=l('
Referenced by:Digital Gardens

This is my knowledge hub!

  • It's a Digital Garden collecting my thoughts in varying levels of completeness on basically anything I have interest in

This is not Wikipedia. My thoughts are biased and argumentative, but to the best of my ability based on fact and expertise

I'm writing on something essentially every day

  • Most of my pages are private, especially the journal pages
  • I'll only push updates to this site every so often (not an automatic process)
  • Until something like Garden-RSS exists, we'll have to make do with /changelog which gives a git diff summary for every pushed change, in the form of a The IndieWeb stream as well as an RSS feed

Written in Logseq and rendered with Vitepress

I want to utilize the strategies described in Andy's working notes to help improve my digital garden

Suggested pages:

',11),b=JSON.parse('{"title":"This Knowledge Hub","description":"","frontmatter":{"public":"true","slug":"this-knowledge-hub","title":"This Knowledge Hub","prev":false,"next":false},"headers":[],"relativePath":"garden/this-knowledge-hub/index.md","filePath":"garden/this-knowledge-hub/index.md"}'),p={name:"garden/this-knowledge-hub/index.md"},y=Object.assign(p,{setup(u){const t=i();return(m,c)=>(o(),n("div",null,[d,e("p",null,[r("135 words, ~1 minute read. "),e("span",{innerHTML:a(s)[`site/${a(t).page.value.relativePath}`]},null,8,h)]),g]))}});export{b as __pageData,y as default}; diff --git a/assets/garden_this-knowledge-hub_index.md.BDMSkEmc.lean.js b/assets/garden_this-knowledge-hub_index.md.BDMSkEmc.lean.js new file mode 100644 index 00000000..ce58d6cc --- /dev/null +++ b/assets/garden_this-knowledge-hub_index.md.BDMSkEmc.lean.js @@ -0,0 +1 @@ +import{d as s}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as n,Q as e,K as r,u as a,ag as l,p as o}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"This Knowledge Hub",-1),h=["innerHTML"],g=l("",11),b=JSON.parse('{"title":"This Knowledge Hub","description":"","frontmatter":{"public":"true","slug":"this-knowledge-hub","title":"This Knowledge Hub","prev":false,"next":false},"headers":[],"relativePath":"garden/this-knowledge-hub/index.md","filePath":"garden/this-knowledge-hub/index.md"}'),p={name:"garden/this-knowledge-hub/index.md"},y=Object.assign(p,{setup(u){const t=i();return(m,c)=>(o(),n("div",null,[d,e("p",null,[r("135 words, ~1 minute read. "),e("span",{innerHTML:a(s)[`site/${a(t).page.value.relativePath}`]},null,8,h)]),g]))}});export{b as __pageData,y as default}; diff --git a/assets/garden_this-knowledge-hub_index.md.BeloVRmr.js b/assets/garden_this-knowledge-hub_index.md.BeloVRmr.js deleted file mode 100644 index 207aadb0..00000000 --- a/assets/garden_this-knowledge-hub_index.md.BeloVRmr.js +++ /dev/null @@ -1 +0,0 @@ -import{d as s}from"./chunks/git.data.DG5NumsR.js";import{u as i,c as n,j as e,a as r,k as a,ag as l,o}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"This Knowledge Hub",-1),h=["innerHTML"],g=l('
Referenced by:Digital Gardens

This is my knowledge hub!

  • It's a Digital Garden collecting my thoughts in varying levels of completeness on basically anything I have interest in

This is not Wikipedia. My thoughts are biased and argumentative, but to the best of my ability based on fact and expertise

I'm writing on something essentially every day

  • Most of my pages are private, especially the journal pages
  • I'll only push updates to this site every so often (not an automatic process)
  • Until something like Garden-RSS exists, we'll have to make do with /changelog which gives a git diff summary for every pushed change, in the form of a The IndieWeb stream as well as an RSS feed

Written in Logseq and rendered with Vitepress

I want to utilize the strategies described in Andy's working notes to help improve my digital garden

Suggested pages:

',11),b=JSON.parse('{"title":"This Knowledge Hub","description":"","frontmatter":{"public":"true","slug":"this-knowledge-hub","title":"This Knowledge Hub","prev":false,"next":false},"headers":[],"relativePath":"garden/this-knowledge-hub/index.md","filePath":"garden/this-knowledge-hub/index.md"}'),p={name:"garden/this-knowledge-hub/index.md"},y=Object.assign(p,{setup(u){const t=i();return(c,m)=>(o(),n("div",null,[d,e("p",null,[r("135 words, ~1 minute read. "),e("span",{innerHTML:a(s)[`site/${a(t).page.value.relativePath}`]},null,8,h)]),g]))}});export{b as __pageData,y as default}; diff --git a/assets/garden_this-knowledge-hub_index.md.BeloVRmr.lean.js b/assets/garden_this-knowledge-hub_index.md.BeloVRmr.lean.js deleted file mode 100644 index 49053105..00000000 --- a/assets/garden_this-knowledge-hub_index.md.BeloVRmr.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{d as s}from"./chunks/git.data.DG5NumsR.js";import{u as i,c as n,j as e,a as r,k as a,ag as l,o}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"This Knowledge Hub",-1),h=["innerHTML"],g=l("",11),b=JSON.parse('{"title":"This Knowledge Hub","description":"","frontmatter":{"public":"true","slug":"this-knowledge-hub","title":"This Knowledge Hub","prev":false,"next":false},"headers":[],"relativePath":"garden/this-knowledge-hub/index.md","filePath":"garden/this-knowledge-hub/index.md"}'),p={name:"garden/this-knowledge-hub/index.md"},y=Object.assign(p,{setup(u){const t=i();return(c,m)=>(o(),n("div",null,[d,e("p",null,[r("135 words, ~1 minute read. "),e("span",{innerHTML:a(s)[`site/${a(t).page.value.relativePath}`]},null,8,h)]),g]))}});export{b as __pageData,y as default}; diff --git a/assets/garden_v-ecs_index.md.DYGQYRv1.js b/assets/garden_v-ecs_index.md.Eos2Bywd.js similarity index 94% rename from assets/garden_v-ecs_index.md.DYGQYRv1.js rename to assets/garden_v-ecs_index.md.Eos2Bywd.js index fa4d55eb..61b451f4 100644 --- a/assets/garden_v-ecs_index.md.DYGQYRv1.js +++ b/assets/garden_v-ecs_index.md.Eos2Bywd.js @@ -1 +1 @@ -import{u as s,c as n,j as e,a as o,k as a,ag as r,o as i,ax as l,ay as d,az as c}from"./chunks/framework.VBE0TPts.js";import{d as m}from"./chunks/git.data.DG5NumsR.js";const p=e("h1",{class:"p-name"},"V-ecs",-1),h=["innerHTML"],g=r('
Tags:My Projects

V-ecs (pronounced "Vex") is a Vulkan-based engine I made for making highly moddable games and tools in Lua centered around the ECS design pattern and a work-stealing job system.

The engine works with "worlds", which are collections of systems and renderers. The engine comes with several worlds using systems and renderers I made, including a voxel world, an incremental game, and some test scenes. All of these include systems to render the fps as well as show a debug console by typing the grave key (`). The default world is a title screen that detects any worlds in the "worlds" folder and displays a button for each of them.

The original plans were to eventually put it on the steam workshop so people could more easily share their creations amongst each other, but I never became happy enough with the performance of the engine - the parallelization of the lua code involved a lot of overhead that severely limited performance.

Instead, I made a couple of worlds by myself - an infinite procedurally generated voxel world, a simple incremental game, and a more complex incremental game I call "Sands of Time".

The gameplay of Sands of Time was replicated in Kronos Chapter 2!

',10),T=JSON.parse('{"title":"V-ecs","description":"","frontmatter":{"public":"true","slug":"v-ecs","tags":["My Projects"],"title":"V-ecs","prev":false,"next":false},"headers":[],"relativePath":"garden/v-ecs/index.md","filePath":"garden/v-ecs/index.md"}'),u={name:"garden/v-ecs/index.md"},b=Object.assign(u,{setup(_){const t=s();return(f,v)=>(i(),n("div",null,[p,e("p",null,[o("209 words, ~1 minute read. "),e("span",{innerHTML:a(m)[`site/${a(t).page.value.relativePath}`]},null,8,h)]),g]))}});export{T as __pageData,b as default}; +import{M as s,q as n,Q as e,K as o,u as a,ag as r,p as i,ax as l,ay as d,az as c}from"./chunks/framework.DvHfxfnp.js";import{d as m}from"./chunks/git.data.DG5NumsR.js";const p=e("h1",{class:"p-name"},"V-ecs",-1),h=["innerHTML"],g=r('
Tags:My Projects

V-ecs (pronounced "Vex") is a Vulkan-based engine I made for making highly moddable games and tools in Lua centered around the ECS design pattern and a work-stealing job system.

The engine works with "worlds", which are collections of systems and renderers. The engine comes with several worlds using systems and renderers I made, including a voxel world, an incremental game, and some test scenes. All of these include systems to render the fps as well as show a debug console by typing the grave key (`). The default world is a title screen that detects any worlds in the "worlds" folder and displays a button for each of them.

The original plans were to eventually put it on the steam workshop so people could more easily share their creations amongst each other, but I never became happy enough with the performance of the engine - the parallelization of the lua code involved a lot of overhead that severely limited performance.

Instead, I made a couple of worlds by myself - an infinite procedurally generated voxel world, a simple incremental game, and a more complex incremental game I call "Sands of Time".

The gameplay of Sands of Time was replicated in Kronos Chapter 2!

',10),T=JSON.parse('{"title":"V-ecs","description":"","frontmatter":{"public":"true","slug":"v-ecs","tags":["My Projects"],"title":"V-ecs","prev":false,"next":false},"headers":[],"relativePath":"garden/v-ecs/index.md","filePath":"garden/v-ecs/index.md"}'),u={name:"garden/v-ecs/index.md"},b=Object.assign(u,{setup(_){const t=s();return(f,v)=>(i(),n("div",null,[p,e("p",null,[o("209 words, ~1 minute read. "),e("span",{innerHTML:a(m)[`site/${a(t).page.value.relativePath}`]},null,8,h)]),g]))}});export{T as __pageData,b as default}; diff --git a/assets/garden_v-ecs_index.md.DYGQYRv1.lean.js b/assets/garden_v-ecs_index.md.Eos2Bywd.lean.js similarity index 83% rename from assets/garden_v-ecs_index.md.DYGQYRv1.lean.js rename to assets/garden_v-ecs_index.md.Eos2Bywd.lean.js index 1e19f7ba..a3724062 100644 --- a/assets/garden_v-ecs_index.md.DYGQYRv1.lean.js +++ b/assets/garden_v-ecs_index.md.Eos2Bywd.lean.js @@ -1 +1 @@ -import{u as s,c as n,j as e,a as o,k as a,ag as r,o as i,ax as l,ay as d,az as c}from"./chunks/framework.VBE0TPts.js";import{d as m}from"./chunks/git.data.DG5NumsR.js";const p=e("h1",{class:"p-name"},"V-ecs",-1),h=["innerHTML"],g=r("",10),T=JSON.parse('{"title":"V-ecs","description":"","frontmatter":{"public":"true","slug":"v-ecs","tags":["My Projects"],"title":"V-ecs","prev":false,"next":false},"headers":[],"relativePath":"garden/v-ecs/index.md","filePath":"garden/v-ecs/index.md"}'),u={name:"garden/v-ecs/index.md"},b=Object.assign(u,{setup(_){const t=s();return(f,v)=>(i(),n("div",null,[p,e("p",null,[o("209 words, ~1 minute read. "),e("span",{innerHTML:a(m)[`site/${a(t).page.value.relativePath}`]},null,8,h)]),g]))}});export{T as __pageData,b as default}; +import{M as s,q as n,Q as e,K as o,u as a,ag as r,p as i,ax as l,ay as d,az as c}from"./chunks/framework.DvHfxfnp.js";import{d as m}from"./chunks/git.data.DG5NumsR.js";const p=e("h1",{class:"p-name"},"V-ecs",-1),h=["innerHTML"],g=r("",10),T=JSON.parse('{"title":"V-ecs","description":"","frontmatter":{"public":"true","slug":"v-ecs","tags":["My Projects"],"title":"V-ecs","prev":false,"next":false},"headers":[],"relativePath":"garden/v-ecs/index.md","filePath":"garden/v-ecs/index.md"}'),u={name:"garden/v-ecs/index.md"},b=Object.assign(u,{setup(_){const t=s();return(f,v)=>(i(),n("div",null,[p,e("p",null,[o("209 words, ~1 minute read. "),e("span",{innerHTML:a(m)[`site/${a(t).page.value.relativePath}`]},null,8,h)]),g]))}});export{T as __pageData,b as default}; diff --git a/assets/garden_video-game-monetization_index.md.ClgnBtf0.js b/assets/garden_video-game-monetization_index.md.CF0Gozbk.js similarity index 94% rename from assets/garden_video-game-monetization_index.md.ClgnBtf0.js rename to assets/garden_video-game-monetization_index.md.CF0Gozbk.js index 67a65ca9..bd89d1af 100644 --- a/assets/garden_video-game-monetization_index.md.ClgnBtf0.js +++ b/assets/garden_video-game-monetization_index.md.CF0Gozbk.js @@ -1 +1 @@ -import{d as i}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as o,j as e,a as r,k as a,ag as s,o as l}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Video Game Monetization",-1),m=["innerHTML"],h=s('
Referenced by:Life is Strange

AAA games

They Clcost a lot of money to make, mostly due to the graphics arms race. The price required to make these games profitable would be much higher than the current price of AAA games.

Graphics would not justify significantly higher prices, and AAA studios know this. So instead they use the techniques to make more money without raising the base price:

Free-to-play games

Typically utilize MTX and ads in order to profit. Often extreme cases of designing games to compell players to spend money.

Indie developers

Trying to make a sustainable living as an indie developer is hard. The industry is packed with lots of competition, and drive prices people are willing to pay very low. Therefore, I don't blame indies for their monetization strategies, even if I consider them unethical or tainting the game design.

Ethical game monetization

Requirements:

  • Free demo
  • Paid base game
  • No MTX
  • Paid content expansions

The goal of the above is to allow players to determine if they enjoy the game without putting money down, and to ensure the game design cannot be tainted by the monetization.

I think having the gameplay affected by transactions of any kind taints the game design. This is a particularly controversial take in the context of communal benefits (e.g. one person donates and all players get a 2x buff for an hour, or a persistent buff based on number of patrons), which are generally seen as ethical.

',15),_=JSON.parse('{"title":"Video Game Monetization","description":"","frontmatter":{"public":"true","slug":"video-game-monetization","title":"Video Game Monetization","prev":false,"next":false},"headers":[],"relativePath":"garden/video-game-monetization/index.md","filePath":"garden/video-game-monetization/index.md"}'),p={name:"garden/video-game-monetization/index.md"},b=Object.assign(p,{setup(c){const t=n();return(g,u)=>(l(),o("div",null,[d,e("p",null,[r("250 words, ~1 minute read. "),e("span",{innerHTML:a(i)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),h]))}});export{_ as __pageData,b as default}; +import{d as i}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as o,Q as e,K as r,u as a,ag as s,p as l}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Video Game Monetization",-1),m=["innerHTML"],h=s('
Referenced by:Life is Strange

AAA games

They Clcost a lot of money to make, mostly due to the graphics arms race. The price required to make these games profitable would be much higher than the current price of AAA games.

Graphics would not justify significantly higher prices, and AAA studios know this. So instead they use the techniques to make more money without raising the base price:

Free-to-play games

Typically utilize MTX and ads in order to profit. Often extreme cases of designing games to compell players to spend money.

Indie developers

Trying to make a sustainable living as an indie developer is hard. The industry is packed with lots of competition, and drive prices people are willing to pay very low. Therefore, I don't blame indies for their monetization strategies, even if I consider them unethical or tainting the game design.

Ethical game monetization

Requirements:

  • Free demo
  • Paid base game
  • No MTX
  • Paid content expansions

The goal of the above is to allow players to determine if they enjoy the game without putting money down, and to ensure the game design cannot be tainted by the monetization.

I think having the gameplay affected by transactions of any kind taints the game design. This is a particularly controversial take in the context of communal benefits (e.g. one person donates and all players get a 2x buff for an hour, or a persistent buff based on number of patrons), which are generally seen as ethical.

',15),_=JSON.parse('{"title":"Video Game Monetization","description":"","frontmatter":{"public":"true","slug":"video-game-monetization","title":"Video Game Monetization","prev":false,"next":false},"headers":[],"relativePath":"garden/video-game-monetization/index.md","filePath":"garden/video-game-monetization/index.md"}'),p={name:"garden/video-game-monetization/index.md"},b=Object.assign(p,{setup(c){const t=n();return(g,u)=>(l(),o("div",null,[d,e("p",null,[r("250 words, ~1 minute read. "),e("span",{innerHTML:a(i)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),h]))}});export{_ as __pageData,b as default}; diff --git a/assets/garden_video-game-monetization_index.md.ClgnBtf0.lean.js b/assets/garden_video-game-monetization_index.md.CF0Gozbk.lean.js similarity index 77% rename from assets/garden_video-game-monetization_index.md.ClgnBtf0.lean.js rename to assets/garden_video-game-monetization_index.md.CF0Gozbk.lean.js index 96842ea9..ba24248e 100644 --- a/assets/garden_video-game-monetization_index.md.ClgnBtf0.lean.js +++ b/assets/garden_video-game-monetization_index.md.CF0Gozbk.lean.js @@ -1 +1 @@ -import{d as i}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as o,j as e,a as r,k as a,ag as s,o as l}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Video Game Monetization",-1),m=["innerHTML"],h=s("",15),_=JSON.parse('{"title":"Video Game Monetization","description":"","frontmatter":{"public":"true","slug":"video-game-monetization","title":"Video Game Monetization","prev":false,"next":false},"headers":[],"relativePath":"garden/video-game-monetization/index.md","filePath":"garden/video-game-monetization/index.md"}'),p={name:"garden/video-game-monetization/index.md"},b=Object.assign(p,{setup(c){const t=n();return(g,u)=>(l(),o("div",null,[d,e("p",null,[r("250 words, ~1 minute read. "),e("span",{innerHTML:a(i)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),h]))}});export{_ as __pageData,b as default}; +import{d as i}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as o,Q as e,K as r,u as a,ag as s,p as l}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Video Game Monetization",-1),m=["innerHTML"],h=s("",15),_=JSON.parse('{"title":"Video Game Monetization","description":"","frontmatter":{"public":"true","slug":"video-game-monetization","title":"Video Game Monetization","prev":false,"next":false},"headers":[],"relativePath":"garden/video-game-monetization/index.md","filePath":"garden/video-game-monetization/index.md"}'),p={name:"garden/video-game-monetization/index.md"},b=Object.assign(p,{setup(c){const t=n();return(g,u)=>(l(),o("div",null,[d,e("p",null,[r("250 words, ~1 minute read. "),e("span",{innerHTML:a(i)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),h]))}});export{_ as __pageData,b as default}; diff --git a/assets/garden_vitepress_index.md.BwIztJxS.js b/assets/garden_vitepress_index.md.Jhyyyy8E.js similarity index 72% rename from assets/garden_vitepress_index.md.BwIztJxS.js rename to assets/garden_vitepress_index.md.Jhyyyy8E.js index fac5fa17..6ca6f4d5 100644 --- a/assets/garden_vitepress_index.md.BwIztJxS.js +++ b/assets/garden_vitepress_index.md.Jhyyyy8E.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as i,j as e,a as s,k as t,o as l}from"./chunks/framework.VBE0TPts.js";const o=e("h1",{class:"p-name"},"Vitepress",-1),d=["innerHTML"],p=e("hr",null,null,-1),c=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/my-personal-website/index.md"},"My Personal Website"),e("a",{href:"/garden/this-knowledge-hub/index.md"},"This Knowledge Hub")],-1),u=e("p",null,[e("a",{href:"https://vitepress.dev",target:"_blank",rel:"noreferrer"},"Vitepress"),s(" is an "),e("a",{href:"/garden/open-source/"},"Open Source"),s(" static site generator")],-1),x=JSON.parse('{"title":"Vitepress","description":"","frontmatter":{"public":"true","slug":"vitepress","title":"Vitepress","prev":false,"next":false},"headers":[],"relativePath":"garden/vitepress/index.md","filePath":"garden/vitepress/index.md"}'),_={name:"garden/vitepress/index.md"},b=Object.assign(_,{setup(h){const a=n();return(m,f)=>(l(),i("div",null,[o,e("p",null,[s("4 words, ~0 minute read. "),e("span",{innerHTML:t(r)[`site/${t(a).page.value.relativePath}`]},null,8,d)]),p,c,u]))}});export{x as __pageData,b as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as i,Q as e,K as s,u as t,p as l}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Vitepress",-1),o=["innerHTML"],p=e("hr",null,null,-1),c=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/my-personal-website/index.md"},"My Personal Website"),e("a",{href:"/garden/this-knowledge-hub/index.md"},"This Knowledge Hub")],-1),u=e("p",null,[e("a",{href:"https://vitepress.dev",target:"_blank",rel:"noreferrer"},"Vitepress"),s(" is an "),e("a",{href:"/garden/open-source/"},"Open Source"),s(" static site generator")],-1),x=JSON.parse('{"title":"Vitepress","description":"","frontmatter":{"public":"true","slug":"vitepress","title":"Vitepress","prev":false,"next":false},"headers":[],"relativePath":"garden/vitepress/index.md","filePath":"garden/vitepress/index.md"}'),_={name:"garden/vitepress/index.md"},b=Object.assign(_,{setup(h){const a=n();return(m,f)=>(l(),i("div",null,[d,e("p",null,[s("4 words, ~0 minute read. "),e("span",{innerHTML:t(r)[`site/${t(a).page.value.relativePath}`]},null,8,o)]),p,c,u]))}});export{x as __pageData,b as default}; diff --git a/assets/garden_vitepress_index.md.BwIztJxS.lean.js b/assets/garden_vitepress_index.md.Jhyyyy8E.lean.js similarity index 72% rename from assets/garden_vitepress_index.md.BwIztJxS.lean.js rename to assets/garden_vitepress_index.md.Jhyyyy8E.lean.js index fac5fa17..6ca6f4d5 100644 --- a/assets/garden_vitepress_index.md.BwIztJxS.lean.js +++ b/assets/garden_vitepress_index.md.Jhyyyy8E.lean.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as i,j as e,a as s,k as t,o as l}from"./chunks/framework.VBE0TPts.js";const o=e("h1",{class:"p-name"},"Vitepress",-1),d=["innerHTML"],p=e("hr",null,null,-1),c=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/my-personal-website/index.md"},"My Personal Website"),e("a",{href:"/garden/this-knowledge-hub/index.md"},"This Knowledge Hub")],-1),u=e("p",null,[e("a",{href:"https://vitepress.dev",target:"_blank",rel:"noreferrer"},"Vitepress"),s(" is an "),e("a",{href:"/garden/open-source/"},"Open Source"),s(" static site generator")],-1),x=JSON.parse('{"title":"Vitepress","description":"","frontmatter":{"public":"true","slug":"vitepress","title":"Vitepress","prev":false,"next":false},"headers":[],"relativePath":"garden/vitepress/index.md","filePath":"garden/vitepress/index.md"}'),_={name:"garden/vitepress/index.md"},b=Object.assign(_,{setup(h){const a=n();return(m,f)=>(l(),i("div",null,[o,e("p",null,[s("4 words, ~0 minute read. "),e("span",{innerHTML:t(r)[`site/${t(a).page.value.relativePath}`]},null,8,d)]),p,c,u]))}});export{x as __pageData,b as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as i,Q as e,K as s,u as t,p as l}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Vitepress",-1),o=["innerHTML"],p=e("hr",null,null,-1),c=e("details",null,[e("summary",null,"Referenced by:"),e("a",{href:"/garden/my-personal-website/index.md"},"My Personal Website"),e("a",{href:"/garden/this-knowledge-hub/index.md"},"This Knowledge Hub")],-1),u=e("p",null,[e("a",{href:"https://vitepress.dev",target:"_blank",rel:"noreferrer"},"Vitepress"),s(" is an "),e("a",{href:"/garden/open-source/"},"Open Source"),s(" static site generator")],-1),x=JSON.parse('{"title":"Vitepress","description":"","frontmatter":{"public":"true","slug":"vitepress","title":"Vitepress","prev":false,"next":false},"headers":[],"relativePath":"garden/vitepress/index.md","filePath":"garden/vitepress/index.md"}'),_={name:"garden/vitepress/index.md"},b=Object.assign(_,{setup(h){const a=n();return(m,f)=>(l(),i("div",null,[d,e("p",null,[s("4 words, ~0 minute read. "),e("span",{innerHTML:t(r)[`site/${t(a).page.value.relativePath}`]},null,8,o)]),p,c,u]))}});export{x as __pageData,b as default}; diff --git a/assets/garden_wanderstop_index.md.-GaIeUe_.js b/assets/garden_wanderstop_index.md.-GaIeUe_.js deleted file mode 100644 index 2fcb4101..00000000 --- a/assets/garden_wanderstop_index.md.-GaIeUe_.js +++ /dev/null @@ -1 +0,0 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as d,j as e,a,k as t,o}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"Wanderstop",-1),i=["innerHTML"],p=e("hr",null,null,-1),c=e("details",null,[e("summary",null,"Tags:"),e("a",{href:"/garden/davey-wreden/index.md"},"Davey Wreden")],-1),u=e("p",null,[e("a",{href:"https://www.wanderstopgame.com/",target:"_blank",rel:"noreferrer"},"Wanderstop"),a(" is the first game by "),e("a",{href:"/garden/ivy-road/"},"Ivy Road"),a(". It's a narrative focused cozy game")],-1),w=JSON.parse('{"title":"Wanderstop","description":"","frontmatter":{"public":"true","slug":"wanderstop","tags":["Davey Wreden"],"title":"Wanderstop","prev":false,"next":false},"headers":[],"relativePath":"garden/wanderstop/index.md","filePath":"garden/wanderstop/index.md"}'),_={name:"garden/wanderstop/index.md"},x=Object.assign(_,{setup(m){const n=s();return(h,f)=>(o(),d("div",null,[l,e("p",null,[a("8 words, ~0 minute read. "),e("span",{innerHTML:t(r)[`site/${t(n).page.value.relativePath}`]},null,8,i)]),p,c,u]))}});export{w as __pageData,x as default}; diff --git a/assets/garden_wanderstop_index.md.-GaIeUe_.lean.js b/assets/garden_wanderstop_index.md.-GaIeUe_.lean.js deleted file mode 100644 index 2fcb4101..00000000 --- a/assets/garden_wanderstop_index.md.-GaIeUe_.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as s,c as d,j as e,a,k as t,o}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"Wanderstop",-1),i=["innerHTML"],p=e("hr",null,null,-1),c=e("details",null,[e("summary",null,"Tags:"),e("a",{href:"/garden/davey-wreden/index.md"},"Davey Wreden")],-1),u=e("p",null,[e("a",{href:"https://www.wanderstopgame.com/",target:"_blank",rel:"noreferrer"},"Wanderstop"),a(" is the first game by "),e("a",{href:"/garden/ivy-road/"},"Ivy Road"),a(". It's a narrative focused cozy game")],-1),w=JSON.parse('{"title":"Wanderstop","description":"","frontmatter":{"public":"true","slug":"wanderstop","tags":["Davey Wreden"],"title":"Wanderstop","prev":false,"next":false},"headers":[],"relativePath":"garden/wanderstop/index.md","filePath":"garden/wanderstop/index.md"}'),_={name:"garden/wanderstop/index.md"},x=Object.assign(_,{setup(m){const n=s();return(h,f)=>(o(),d("div",null,[l,e("p",null,[a("8 words, ~0 minute read. "),e("span",{innerHTML:t(r)[`site/${t(n).page.value.relativePath}`]},null,8,i)]),p,c,u]))}});export{w as __pageData,x as default}; diff --git a/assets/garden_wanderstop_index.md.DAn8eZ1Y.js b/assets/garden_wanderstop_index.md.DAn8eZ1Y.js new file mode 100644 index 00000000..ec44fc40 --- /dev/null +++ b/assets/garden_wanderstop_index.md.DAn8eZ1Y.js @@ -0,0 +1 @@ +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as d,Q as e,K as a,u as t,p as o}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"Wanderstop",-1),i=["innerHTML"],p=e("hr",null,null,-1),c=e("details",null,[e("summary",null,"Tags:"),e("a",{href:"/garden/davey-wreden/index.md"},"Davey Wreden")],-1),u=e("p",null,[e("a",{href:"https://www.wanderstopgame.com/",target:"_blank",rel:"noreferrer"},"Wanderstop"),a(" is the first game by "),e("a",{href:"/garden/ivy-road/"},"Ivy Road"),a(". It's a narrative focused cozy game")],-1),w=JSON.parse('{"title":"Wanderstop","description":"","frontmatter":{"public":"true","slug":"wanderstop","tags":["Davey Wreden"],"title":"Wanderstop","prev":false,"next":false},"headers":[],"relativePath":"garden/wanderstop/index.md","filePath":"garden/wanderstop/index.md"}'),_={name:"garden/wanderstop/index.md"},x=Object.assign(_,{setup(m){const n=s();return(h,f)=>(o(),d("div",null,[l,e("p",null,[a("8 words, ~0 minute read. "),e("span",{innerHTML:t(r)[`site/${t(n).page.value.relativePath}`]},null,8,i)]),p,c,u]))}});export{w as __pageData,x as default}; diff --git a/assets/garden_wanderstop_index.md.DAn8eZ1Y.lean.js b/assets/garden_wanderstop_index.md.DAn8eZ1Y.lean.js new file mode 100644 index 00000000..ec44fc40 --- /dev/null +++ b/assets/garden_wanderstop_index.md.DAn8eZ1Y.lean.js @@ -0,0 +1 @@ +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as s,q as d,Q as e,K as a,u as t,p as o}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"Wanderstop",-1),i=["innerHTML"],p=e("hr",null,null,-1),c=e("details",null,[e("summary",null,"Tags:"),e("a",{href:"/garden/davey-wreden/index.md"},"Davey Wreden")],-1),u=e("p",null,[e("a",{href:"https://www.wanderstopgame.com/",target:"_blank",rel:"noreferrer"},"Wanderstop"),a(" is the first game by "),e("a",{href:"/garden/ivy-road/"},"Ivy Road"),a(". It's a narrative focused cozy game")],-1),w=JSON.parse('{"title":"Wanderstop","description":"","frontmatter":{"public":"true","slug":"wanderstop","tags":["Davey Wreden"],"title":"Wanderstop","prev":false,"next":false},"headers":[],"relativePath":"garden/wanderstop/index.md","filePath":"garden/wanderstop/index.md"}'),_={name:"garden/wanderstop/index.md"},x=Object.assign(_,{setup(m){const n=s();return(h,f)=>(o(),d("div",null,[l,e("p",null,[a("8 words, ~0 minute read. "),e("span",{innerHTML:t(r)[`site/${t(n).page.value.relativePath}`]},null,8,i)]),p,c,u]))}});export{w as __pageData,x as default}; diff --git a/assets/garden_webrings_index.md.CopTyfrh.js b/assets/garden_webrings_index.md.CopTyfrh.js new file mode 100644 index 00000000..246c1f14 --- /dev/null +++ b/assets/garden_webrings_index.md.CopTyfrh.js @@ -0,0 +1 @@ +import{d as i}from"./chunks/git.data.DG5NumsR.js";import{M as l,q as s,Q as e,K as r,u as a,ag as n,p as o}from"./chunks/framework.DvHfxfnp.js";const m=e("h1",{class:"p-name"},"Webrings",-1),c=["innerHTML"],d=n('
Referenced by:The Small Web

A collection of Personal Websites that link to each other

  • These websites are all endorsing each other
  • They form a network of related sites readers might be interested in
  • Built on human trust rather than algorithms

Commune has a vision for modern webrings

  • Have communities set up matrix spaces for chatting
  • Multiple spaces can contain the same room
  • Related communities can share a room about a relevant topic
    • e.g. a bunch of game development libraries shared a "Game Design" room
  • This allows smaller communities to grow from cross-pollinating with other related communities
  • Could Incremental Social host a shared "Incremental Games" room?
    • How to bridge one channel to multiple discord servers, since that's where most incremental games communities are
    • Would this be appealing to already large communities?
    • Would this be overwhelming to smaller communities?
    • Who would moderate?
',6),f=JSON.parse('{"title":"Webrings","description":"","frontmatter":{"public":"true","slug":"webrings","title":"Webrings","prev":false,"next":false},"headers":[],"relativePath":"garden/webrings/index.md","filePath":"garden/webrings/index.md"}'),u={name:"garden/webrings/index.md"},w=Object.assign(u,{setup(h){const t=l();return(g,p)=>(o(),s("div",null,[m,e("p",null,[r("139 words, ~1 minute read. "),e("span",{innerHTML:a(i)[`site/${a(t).page.value.relativePath}`]},null,8,c)]),d]))}});export{f as __pageData,w as default}; diff --git a/assets/garden_webrings_index.md.CopTyfrh.lean.js b/assets/garden_webrings_index.md.CopTyfrh.lean.js new file mode 100644 index 00000000..7f92d5d1 --- /dev/null +++ b/assets/garden_webrings_index.md.CopTyfrh.lean.js @@ -0,0 +1 @@ +import{d as i}from"./chunks/git.data.DG5NumsR.js";import{M as l,q as s,Q as e,K as r,u as a,ag as n,p as o}from"./chunks/framework.DvHfxfnp.js";const m=e("h1",{class:"p-name"},"Webrings",-1),c=["innerHTML"],d=n("",6),f=JSON.parse('{"title":"Webrings","description":"","frontmatter":{"public":"true","slug":"webrings","title":"Webrings","prev":false,"next":false},"headers":[],"relativePath":"garden/webrings/index.md","filePath":"garden/webrings/index.md"}'),u={name:"garden/webrings/index.md"},w=Object.assign(u,{setup(h){const t=l();return(g,p)=>(o(),s("div",null,[m,e("p",null,[r("139 words, ~1 minute read. "),e("span",{innerHTML:a(i)[`site/${a(t).page.value.relativePath}`]},null,8,c)]),d]))}});export{f as __pageData,w as default}; diff --git a/assets/garden_webrings_index.md.D5KgyhV9.js b/assets/garden_webrings_index.md.D5KgyhV9.js deleted file mode 100644 index 9b201022..00000000 --- a/assets/garden_webrings_index.md.D5KgyhV9.js +++ /dev/null @@ -1 +0,0 @@ -import{d as i}from"./chunks/git.data.DG5NumsR.js";import{u as l,c as s,j as e,a as r,k as a,ag as n,o}from"./chunks/framework.VBE0TPts.js";const m=e("h1",{class:"p-name"},"Webrings",-1),c=["innerHTML"],d=n('
Referenced by:The Small Web

A collection of Personal Websites that link to each other

  • These websites are all endorsing each other
  • They form a network of related sites readers might be interested in
  • Built on human trust rather than algorithms

Commune has a vision for modern webrings

  • Have communities set up matrix spaces for chatting
  • Multiple spaces can contain the same room
  • Related communities can share a room about a relevant topic
    • e.g. a bunch of game development libraries shared a "Game Design" room
  • This allows smaller communities to grow from cross-pollinating with other related communities
  • Could Incremental Social host a shared "Incremental Games" room?
    • How to bridge one channel to multiple discord servers, since that's where most incremental games communities are
    • Would this be appealing to already large communities?
    • Would this be overwhelming to smaller communities?
    • Who would moderate?
',6),f=JSON.parse('{"title":"Webrings","description":"","frontmatter":{"public":"true","slug":"webrings","title":"Webrings","prev":false,"next":false},"headers":[],"relativePath":"garden/webrings/index.md","filePath":"garden/webrings/index.md"}'),u={name:"garden/webrings/index.md"},w=Object.assign(u,{setup(h){const t=l();return(g,p)=>(o(),s("div",null,[m,e("p",null,[r("139 words, ~1 minute read. "),e("span",{innerHTML:a(i)[`site/${a(t).page.value.relativePath}`]},null,8,c)]),d]))}});export{f as __pageData,w as default}; diff --git a/assets/garden_webrings_index.md.D5KgyhV9.lean.js b/assets/garden_webrings_index.md.D5KgyhV9.lean.js deleted file mode 100644 index 1fb303b1..00000000 --- a/assets/garden_webrings_index.md.D5KgyhV9.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{d as i}from"./chunks/git.data.DG5NumsR.js";import{u as l,c as s,j as e,a as r,k as a,ag as n,o}from"./chunks/framework.VBE0TPts.js";const m=e("h1",{class:"p-name"},"Webrings",-1),c=["innerHTML"],d=n("",6),f=JSON.parse('{"title":"Webrings","description":"","frontmatter":{"public":"true","slug":"webrings","title":"Webrings","prev":false,"next":false},"headers":[],"relativePath":"garden/webrings/index.md","filePath":"garden/webrings/index.md"}'),u={name:"garden/webrings/index.md"},w=Object.assign(u,{setup(h){const t=l();return(g,p)=>(o(),s("div",null,[m,e("p",null,[r("139 words, ~1 minute read. "),e("span",{innerHTML:a(i)[`site/${a(t).page.value.relativePath}`]},null,8,c)]),d]))}});export{f as __pageData,w as default}; diff --git a/assets/garden_weird_index.md.CVpFc8I8.js b/assets/garden_weird_index.md.CVpFc8I8.js deleted file mode 100644 index 0e91caa6..00000000 --- a/assets/garden_weird_index.md.CVpFc8I8.js +++ /dev/null @@ -1 +0,0 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as i,c as n,j as e,a as s,k as a,ag as d,o}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"Weird",-1),h=["innerHTML"],c=d('
Referenced by:CommuneFedi v2My Personal WebsiteThe Small Web

Weird is an Open Source project by the Commune team currently in development

Aims to make creating Personal Websites with Federated Identity available to everyone

  • Also plans on having paid tiers for giving people access to single user instances of various Fediverse tools

Long term, Weird wants to build a new better fediverse

',7),v=JSON.parse('{"title":"Weird","description":"","frontmatter":{"public":"true","slug":"weird","title":"Weird","prev":false,"next":false},"headers":[],"relativePath":"garden/weird/index.md","filePath":"garden/weird/index.md"}'),m={name:"garden/weird/index.md"},b=Object.assign(m,{setup(p){const r=i();return(u,f)=>(o(),n("div",null,[l,e("p",null,[s("114 words, ~1 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,h)]),c]))}});export{v as __pageData,b as default}; diff --git a/assets/garden_weird_index.md.CVpFc8I8.lean.js b/assets/garden_weird_index.md.CVpFc8I8.lean.js deleted file mode 100644 index fc13da72..00000000 --- a/assets/garden_weird_index.md.CVpFc8I8.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{d as t}from"./chunks/git.data.DG5NumsR.js";import{u as i,c as n,j as e,a as s,k as a,ag as d,o}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"Weird",-1),h=["innerHTML"],c=d("",7),v=JSON.parse('{"title":"Weird","description":"","frontmatter":{"public":"true","slug":"weird","title":"Weird","prev":false,"next":false},"headers":[],"relativePath":"garden/weird/index.md","filePath":"garden/weird/index.md"}'),m={name:"garden/weird/index.md"},b=Object.assign(m,{setup(p){const r=i();return(u,f)=>(o(),n("div",null,[l,e("p",null,[s("114 words, ~1 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,h)]),c]))}});export{v as __pageData,b as default}; diff --git a/assets/garden_weird_index.md.H-M1_Y4d.js b/assets/garden_weird_index.md.H-M1_Y4d.js new file mode 100644 index 00000000..40c79fe1 --- /dev/null +++ b/assets/garden_weird_index.md.H-M1_Y4d.js @@ -0,0 +1 @@ +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as n,Q as e,K as s,u as a,ag as d,p as o}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"Weird",-1),h=["innerHTML"],c=d('
Referenced by:CommuneFedi v2My Personal WebsiteThe Small Web

Weird is an Open Source project by the Commune team currently in development

Aims to make creating Personal Websites with Federated Identity available to everyone

  • Also plans on having paid tiers for giving people access to single user instances of various Fediverse tools

Long term, Weird wants to build a new better fediverse

',7),v=JSON.parse('{"title":"Weird","description":"","frontmatter":{"public":"true","slug":"weird","title":"Weird","prev":false,"next":false},"headers":[],"relativePath":"garden/weird/index.md","filePath":"garden/weird/index.md"}'),m={name:"garden/weird/index.md"},b=Object.assign(m,{setup(p){const r=i();return(u,f)=>(o(),n("div",null,[l,e("p",null,[s("114 words, ~1 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,h)]),c]))}});export{v as __pageData,b as default}; diff --git a/assets/garden_weird_index.md.H-M1_Y4d.lean.js b/assets/garden_weird_index.md.H-M1_Y4d.lean.js new file mode 100644 index 00000000..dd4957e3 --- /dev/null +++ b/assets/garden_weird_index.md.H-M1_Y4d.lean.js @@ -0,0 +1 @@ +import{d as t}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as n,Q as e,K as s,u as a,ag as d,p as o}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"Weird",-1),h=["innerHTML"],c=d("",7),v=JSON.parse('{"title":"Weird","description":"","frontmatter":{"public":"true","slug":"weird","title":"Weird","prev":false,"next":false},"headers":[],"relativePath":"garden/weird/index.md","filePath":"garden/weird/index.md"}'),m={name:"garden/weird/index.md"},b=Object.assign(m,{setup(p){const r=i();return(u,f)=>(o(),n("div",null,[l,e("p",null,[s("114 words, ~1 minute read. "),e("span",{innerHTML:a(t)[`site/${a(r).page.value.relativePath}`]},null,8,h)]),c]))}});export{v as __pageData,b as default}; diff --git a/assets/guide-to-incrementals_design_criticism_index.md.B84_a_FO.js b/assets/guide-to-incrementals_design_criticism_index.md.BSUq6GVs.js similarity index 97% rename from assets/guide-to-incrementals_design_criticism_index.md.B84_a_FO.js rename to assets/guide-to-incrementals_design_criticism_index.md.BSUq6GVs.js index bdb633a3..1ba37315 100644 --- a/assets/guide-to-incrementals_design_criticism_index.md.B84_a_FO.js +++ b/assets/guide-to-incrementals_design_criticism_index.md.BSUq6GVs.js @@ -1 +1 @@ -import{d as i}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as o,j as e,a as s,k as t,ag as r,o as l}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals___Navigating Criticism",-1),c=["innerHTML"],u=r('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

Developing games is fun and exciting and teaches a lot of wonderful skills - I enthusiastically encourage anyone with an interest in game development to try it out - and incremental games are a wonderful way to get started. However, there are many challenges young and inexperienced developers have to face, and I think the hardest one - harder than coding, debugging, balancing, etc. - is handling criticism. When you put your heart and soul into a game it is natural to feel very vulnerable. While I think there's a lot communities can do to ensure they're welcoming, positive and constructive with their criticisms, inevitably you will eventually read some, and potentially a lot, of comments that can deeply affect you. No one is immune to this, from young incremental game developers to the largest content creators you can think of. That's why it's important to be able to process and navigate criticism, because ultimately collecting feedback is essential to the journey to becoming a better developer. On this page, we'll explore how to embrace criticism, grow from it, and continue to post your games publicly with confidence.

Reading Feedback

Game development is a skill that takes time and practice to get truly great at. Criticism and other constructive feedback are vital to continually improving. It's useful to look at the criticism as solely a tool for improving this game and future games - that is to say, it should never be used against you as a person. Insults towards the developer(s) themselves are never okay and should not be allowed within whatever community you're sharing your works in. If you do come across a comment you interpret as an attack upon your person, you should report it. For other negative comments, try not to internalize them; instead, focus on improving the game. By distancing your own identity from your work emotionally, you can better analyze the game and use the feedback to your advantage.

Not all feedback is made equal, and you don't need to feel compelled to read and obey every piece of feedback you receive. Learn to distinguish between constructive feedback and unhelpful comments. Constructive feedback typically offers specific suggestions for improvement, while unhelpful comments are often vague or hurtful. Prioritize the former and disregard the latter. That said, most feedback you get will not be from game developers, so take specific suggestions with a grain of salt. Determine the actual problem they're experiencing, and design what you believe the best solution to that problem would be, regardless if that's the specific solution the player asked for. And keep in mind, due to different player preferences you'll never satisfy everyone, and you don't need to. Ultimately if even just you find the game fun, then that's a success.

Seeking Feedback

When deciding where to share your game, consider the type of players you anticipate getting, and the kind of feedback you can anticipate receiving. Different communities will have different levels of support for learning developers, and certain communities may prefer certain types of games or mechanics. It's important to get a diverse set of feedback focused on players you think will enjoy the specific game you're making.

Collecting feedback from other game developers is incredibly helpful. They've trained themselves to recognize good and bad game design and how to articulate the differences, and from my experience are much more likely to leave positive and constructive comments since they've been in your shoes before! They understand the struggles and can offer guidance and emotional support.

Responding to Feedback

Negative feedback can naturally feel like an attack, and it's okay to get angry. However, lashing back is never the appropriate response. It's best to cool off IRL, and keep in mind all the positive comments you've received. There's a concept in Psychology called negative bias that explains how negative feedback tends to stick with us much more prominently than positive feedback, so it's useful to regularly remind yourself of all the positive feedback you've received. Celebrate your successes, no matter how small they may seem - getting a game to a state you can publicly share it with people is an accomplishment in and of itself!

Remember your passion and your initial reasons for getting into game development. The journey will have its ups and downs, but staying true to your vision and passion will keep you motivated.

',12),v=JSON.parse('{"title":"Guide to Incrementals/Navigating Criticism","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/navigating-criticism","title":"Guide to Incrementals/Navigating Criticism","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/design/criticism/index.md","filePath":"guide-to-incrementals/design/criticism/index.md"}'),m={name:"guide-to-incrementals/design/criticism/index.md"},b=Object.assign(m,{setup(h){const a=n();return(g,p)=>(l(),o("div",null,[d,e("p",null,[s("747 words, ~4 minute read. "),e("span",{innerHTML:t(i)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),u]))}});export{v as __pageData,b as default}; +import{d as i}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as o,Q as e,K as s,u as t,ag as r,p as l}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals___Navigating Criticism",-1),c=["innerHTML"],u=r('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

Developing games is fun and exciting and teaches a lot of wonderful skills - I enthusiastically encourage anyone with an interest in game development to try it out - and incremental games are a wonderful way to get started. However, there are many challenges young and inexperienced developers have to face, and I think the hardest one - harder than coding, debugging, balancing, etc. - is handling criticism. When you put your heart and soul into a game it is natural to feel very vulnerable. While I think there's a lot communities can do to ensure they're welcoming, positive and constructive with their criticisms, inevitably you will eventually read some, and potentially a lot, of comments that can deeply affect you. No one is immune to this, from young incremental game developers to the largest content creators you can think of. That's why it's important to be able to process and navigate criticism, because ultimately collecting feedback is essential to the journey to becoming a better developer. On this page, we'll explore how to embrace criticism, grow from it, and continue to post your games publicly with confidence.

Reading Feedback

Game development is a skill that takes time and practice to get truly great at. Criticism and other constructive feedback are vital to continually improving. It's useful to look at the criticism as solely a tool for improving this game and future games - that is to say, it should never be used against you as a person. Insults towards the developer(s) themselves are never okay and should not be allowed within whatever community you're sharing your works in. If you do come across a comment you interpret as an attack upon your person, you should report it. For other negative comments, try not to internalize them; instead, focus on improving the game. By distancing your own identity from your work emotionally, you can better analyze the game and use the feedback to your advantage.

Not all feedback is made equal, and you don't need to feel compelled to read and obey every piece of feedback you receive. Learn to distinguish between constructive feedback and unhelpful comments. Constructive feedback typically offers specific suggestions for improvement, while unhelpful comments are often vague or hurtful. Prioritize the former and disregard the latter. That said, most feedback you get will not be from game developers, so take specific suggestions with a grain of salt. Determine the actual problem they're experiencing, and design what you believe the best solution to that problem would be, regardless if that's the specific solution the player asked for. And keep in mind, due to different player preferences you'll never satisfy everyone, and you don't need to. Ultimately if even just you find the game fun, then that's a success.

Seeking Feedback

When deciding where to share your game, consider the type of players you anticipate getting, and the kind of feedback you can anticipate receiving. Different communities will have different levels of support for learning developers, and certain communities may prefer certain types of games or mechanics. It's important to get a diverse set of feedback focused on players you think will enjoy the specific game you're making.

Collecting feedback from other game developers is incredibly helpful. They've trained themselves to recognize good and bad game design and how to articulate the differences, and from my experience are much more likely to leave positive and constructive comments since they've been in your shoes before! They understand the struggles and can offer guidance and emotional support.

Responding to Feedback

Negative feedback can naturally feel like an attack, and it's okay to get angry. However, lashing back is never the appropriate response. It's best to cool off IRL, and keep in mind all the positive comments you've received. There's a concept in Psychology called negative bias that explains how negative feedback tends to stick with us much more prominently than positive feedback, so it's useful to regularly remind yourself of all the positive feedback you've received. Celebrate your successes, no matter how small they may seem - getting a game to a state you can publicly share it with people is an accomplishment in and of itself!

Remember your passion and your initial reasons for getting into game development. The journey will have its ups and downs, but staying true to your vision and passion will keep you motivated.

',12),v=JSON.parse('{"title":"Guide to Incrementals/Navigating Criticism","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/navigating-criticism","title":"Guide to Incrementals/Navigating Criticism","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/design/criticism/index.md","filePath":"guide-to-incrementals/design/criticism/index.md"}'),m={name:"guide-to-incrementals/design/criticism/index.md"},b=Object.assign(m,{setup(h){const a=n();return(g,p)=>(l(),o("div",null,[d,e("p",null,[s("747 words, ~4 minute read. "),e("span",{innerHTML:t(i)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),u]))}});export{v as __pageData,b as default}; diff --git a/assets/guide-to-incrementals_design_criticism_index.md.B84_a_FO.lean.js b/assets/guide-to-incrementals_design_criticism_index.md.BSUq6GVs.lean.js similarity index 79% rename from assets/guide-to-incrementals_design_criticism_index.md.B84_a_FO.lean.js rename to assets/guide-to-incrementals_design_criticism_index.md.BSUq6GVs.lean.js index 1a1c1472..da8b2219 100644 --- a/assets/guide-to-incrementals_design_criticism_index.md.B84_a_FO.lean.js +++ b/assets/guide-to-incrementals_design_criticism_index.md.BSUq6GVs.lean.js @@ -1 +1 @@ -import{d as i}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as o,j as e,a as s,k as t,ag as r,o as l}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals___Navigating Criticism",-1),c=["innerHTML"],u=r("",12),v=JSON.parse('{"title":"Guide to Incrementals/Navigating Criticism","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/navigating-criticism","title":"Guide to Incrementals/Navigating Criticism","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/design/criticism/index.md","filePath":"guide-to-incrementals/design/criticism/index.md"}'),m={name:"guide-to-incrementals/design/criticism/index.md"},b=Object.assign(m,{setup(h){const a=n();return(g,p)=>(l(),o("div",null,[d,e("p",null,[s("747 words, ~4 minute read. "),e("span",{innerHTML:t(i)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),u]))}});export{v as __pageData,b as default}; +import{d as i}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as o,Q as e,K as s,u as t,ag as r,p as l}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals___Navigating Criticism",-1),c=["innerHTML"],u=r("",12),v=JSON.parse('{"title":"Guide to Incrementals/Navigating Criticism","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/navigating-criticism","title":"Guide to Incrementals/Navigating Criticism","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/design/criticism/index.md","filePath":"guide-to-incrementals/design/criticism/index.md"}'),m={name:"guide-to-incrementals/design/criticism/index.md"},b=Object.assign(m,{setup(h){const a=n();return(g,p)=>(l(),o("div",null,[d,e("p",null,[s("747 words, ~4 minute read. "),e("span",{innerHTML:t(i)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),u]))}});export{v as __pageData,b as default}; diff --git a/assets/guide-to-incrementals_index.md.BcJvnxZ-.js b/assets/guide-to-incrementals_index.md.D0no5q0d.js similarity index 94% rename from assets/guide-to-incrementals_index.md.BcJvnxZ-.js rename to assets/guide-to-incrementals_index.md.D0no5q0d.js index 5de00ebe..a53bf57f 100644 --- a/assets/guide-to-incrementals_index.md.BcJvnxZ-.js +++ b/assets/guide-to-incrementals_index.md.D0no5q0d.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as i,c as o,j as e,a as s,k as a,ag as r,o as l}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals",-1),m=["innerHTML"],c=r('
Referenced by:My Personal Website

This is a comprehensive guide to Incremental Games, a genre of video games. It will explore defining the genre, why it's appealing, and how to design and build your own incremental game. Along the way will be interactive examples, snippets from other creators, and relevant material to contextualize everything.

Note: This is an incomplete document. I want to keep adding opinions and opposing views from other incremental games developers, and add interactive examples to illustrate various points regarding game design and balancing. Consider this a living document - and see the changelog at the end.

Why am I making this?

That's a good question! What authority do I have to be making this guide? I haven't made the best incremental games, nor the most incremental games, certainly not the most popular ones either. But I do have some formal education in game development, know a lot of incremental game devs (as well as other game devs), and have a passionate interest in ludology, classifying genres, etc. I've also made a couple of incremental games) myself.

If you have any additional questions about my credentials or anything on this site, feel free to reach out!

Ludology

Making an Incremental

',11),y=JSON.parse('{"title":"Guide to Incrementals","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals","title":"Guide to Incrementals","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/index.md","filePath":"guide-to-incrementals/index.md"}'),g={name:"guide-to-incrementals/index.md"},v=Object.assign(g,{setup(h){const t=i();return(u,p)=>(l(),o("div",null,[d,e("p",null,[s("230 words, ~1 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),c]))}});export{y as __pageData,v as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as o,Q as e,K as s,u as a,ag as r,p as l}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals",-1),m=["innerHTML"],c=r('
Referenced by:My Personal Website

This is a comprehensive guide to Incremental Games, a genre of video games. It will explore defining the genre, why it's appealing, and how to design and build your own incremental game. Along the way will be interactive examples, snippets from other creators, and relevant material to contextualize everything.

Note: This is an incomplete document. I want to keep adding opinions and opposing views from other incremental games developers, and add interactive examples to illustrate various points regarding game design and balancing. Consider this a living document - and see the changelog at the end.

Why am I making this?

That's a good question! What authority do I have to be making this guide? I haven't made the best incremental games, nor the most incremental games, certainly not the most popular ones either. But I do have some formal education in game development, know a lot of incremental game devs (as well as other game devs), and have a passionate interest in ludology, classifying genres, etc. I've also made a couple of incremental games) myself.

If you have any additional questions about my credentials or anything on this site, feel free to reach out!

Ludology

Making an Incremental

',11),y=JSON.parse('{"title":"Guide to Incrementals","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals","title":"Guide to Incrementals","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/index.md","filePath":"guide-to-incrementals/index.md"}'),g={name:"guide-to-incrementals/index.md"},v=Object.assign(g,{setup(h){const t=i();return(u,p)=>(l(),o("div",null,[d,e("p",null,[s("230 words, ~1 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),c]))}});export{y as __pageData,v as default}; diff --git a/assets/guide-to-incrementals_index.md.BcJvnxZ-.lean.js b/assets/guide-to-incrementals_index.md.D0no5q0d.lean.js similarity index 76% rename from assets/guide-to-incrementals_index.md.BcJvnxZ-.lean.js rename to assets/guide-to-incrementals_index.md.D0no5q0d.lean.js index 14797ef5..d58fb86e 100644 --- a/assets/guide-to-incrementals_index.md.BcJvnxZ-.lean.js +++ b/assets/guide-to-incrementals_index.md.D0no5q0d.lean.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as i,c as o,j as e,a as s,k as a,ag as r,o as l}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals",-1),m=["innerHTML"],c=r("",11),y=JSON.parse('{"title":"Guide to Incrementals","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals","title":"Guide to Incrementals","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/index.md","filePath":"guide-to-incrementals/index.md"}'),g={name:"guide-to-incrementals/index.md"},v=Object.assign(g,{setup(h){const t=i();return(u,p)=>(l(),o("div",null,[d,e("p",null,[s("230 words, ~1 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),c]))}});export{y as __pageData,v as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as o,Q as e,K as s,u as a,ag as r,p as l}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals",-1),m=["innerHTML"],c=r("",11),y=JSON.parse('{"title":"Guide to Incrementals","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals","title":"Guide to Incrementals","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/index.md","filePath":"guide-to-incrementals/index.md"}'),g={name:"guide-to-incrementals/index.md"},v=Object.assign(g,{setup(h){const t=i();return(u,p)=>(l(),o("div",null,[d,e("p",null,[s("230 words, ~1 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),c]))}});export{y as __pageData,v as default}; diff --git a/assets/guide-to-incrementals_ludology_appeal-developers_index.md.CIgpgpNd.js b/assets/guide-to-incrementals_ludology_appeal-developers_index.md.BdUXpm07.js similarity index 96% rename from assets/guide-to-incrementals_ludology_appeal-developers_index.md.CIgpgpNd.js rename to assets/guide-to-incrementals_ludology_appeal-developers_index.md.BdUXpm07.js index 0f0e04fd..49f7bee9 100644 --- a/assets/guide-to-incrementals_ludology_appeal-developers_index.md.CIgpgpNd.js +++ b/assets/guide-to-incrementals_ludology_appeal-developers_index.md.BdUXpm07.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as o,c as i,j as e,a as r,k as a,ag as s,o as l}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals___Appeal to Developers",-1),m=["innerHTML"],c=s('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

There are a lot of developers in the incremental games community - the genre seems to draw them in, and convert a lot of players into developers. Let's explore the reasons why this genre appeals to developers.

Incrementals are Easy to Make

Compared to other genres, incrementals have quite low expectations. You don't need to make fancy art, or music, or lay things out nicely. If you can make a button and learn the few lines of code necessary to make a number go up, you can make an incremental. This low threshold makes the genre perfect for those who are actively learning to code and haven't developed any gamedev-related skills yet.

Additionally, unlike other genres incrementals are uniquely easy to implement in a normal web page - no need to worry about rendering sprites, moving them around, implementing physics, etc. New developers can just use HTML to add a button, and the game is now available in your browser. You don't need to choose an engine, have admin privileges, or hell for the dedicated you don't even need a computer - there are tools for web development that run in the browser itself, so you can technically use your phone if that's all you have.

Javascript is a perfectly viable language for making web games, whereas other genres are typically going to require using other more difficult languages to learn. There are countless javascript tutorials that start from 0 knowledge of programming, making it incredibly accessible to beginners.

Players are Easy to Find

Once you've finished your game and uploaded it on github pages or itch or just copied the link if you're using glitch or replit (all of which are easy to do), anyone can now play the game in their browser. This low barrier to entry has shown tremendous success in getting completely unknown developers to have thousands of plays.

The incremental games community, which mostly centers around r/incremental_games, is always looking for new games and tends to flood any new ones posted with initial players.

Having your games be played can be incredibly motivating, and the community makes it quite clear that you can expect players to play your game. These communities - both for incremental games in general as well as game-specific communities - tend to be very developer friendly as well. A lot of the developers know each other, and welcome new developers with open arms, often with dedicated channels for programming help and discussions.

Monetization

I'd like to clarify that everything I've said above mainly applies to web-based incrementals. Incremental games are also incredibly popular on mobile, but with a much different culture and community. Many mobile gamers will still participate in the web-focused community for the culture. This web-focused community has a culture that has been criticized for being "anti-monetization". Ads, IAPs, and similar forms of monetization are often criticized, mainly due to the abundance of completely non-monetized games available from hobbyist developers. There are exceptions, like paid games often being considered fine, like Increlution or Stuck in Time, or donation ware games like kittens game, but even popular games that have IAP see some level of regular criticism, like NGU Idle, Idle Skilling, or Idle Pins. A large part of this can be explained by the community being hyper-aware of the addictive) nature of this genre and its susceptibility to exploiting players.

On mobile, however, monetization is the norm and expected. If an incremental game is available on mobile, it almost certainly will be monetized, and mobile players are aware and accepting of that. Mobile incremental games, due to their addictive nature, tend to make a lot of money. It's very lucrative, and therefore these games are quite abundant on mobile storefronts.

',14),b=JSON.parse('{"title":"Guide to Incrementals/Appeal to Developers","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/appeal-to-developers","title":"Guide to Incrementals/Appeal to Developers","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/ludology/appeal-developers/index.md","filePath":"guide-to-incrementals/ludology/appeal-developers/index.md"}'),p={name:"guide-to-incrementals/ludology/appeal-developers/index.md"},v=Object.assign(p,{setup(h){const t=o();return(u,g)=>(l(),i("div",null,[d,e("p",null,[r("636 words, ~3 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),c]))}});export{b as __pageData,v as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as o,q as i,Q as e,K as r,u as a,ag as s,p as l}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals___Appeal to Developers",-1),m=["innerHTML"],c=s('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

There are a lot of developers in the incremental games community - the genre seems to draw them in, and convert a lot of players into developers. Let's explore the reasons why this genre appeals to developers.

Incrementals are Easy to Make

Compared to other genres, incrementals have quite low expectations. You don't need to make fancy art, or music, or lay things out nicely. If you can make a button and learn the few lines of code necessary to make a number go up, you can make an incremental. This low threshold makes the genre perfect for those who are actively learning to code and haven't developed any gamedev-related skills yet.

Additionally, unlike other genres incrementals are uniquely easy to implement in a normal web page - no need to worry about rendering sprites, moving them around, implementing physics, etc. New developers can just use HTML to add a button, and the game is now available in your browser. You don't need to choose an engine, have admin privileges, or hell for the dedicated you don't even need a computer - there are tools for web development that run in the browser itself, so you can technically use your phone if that's all you have.

Javascript is a perfectly viable language for making web games, whereas other genres are typically going to require using other more difficult languages to learn. There are countless javascript tutorials that start from 0 knowledge of programming, making it incredibly accessible to beginners.

Players are Easy to Find

Once you've finished your game and uploaded it on github pages or itch or just copied the link if you're using glitch or replit (all of which are easy to do), anyone can now play the game in their browser. This low barrier to entry has shown tremendous success in getting completely unknown developers to have thousands of plays.

The incremental games community, which mostly centers around r/incremental_games, is always looking for new games and tends to flood any new ones posted with initial players.

Having your games be played can be incredibly motivating, and the community makes it quite clear that you can expect players to play your game. These communities - both for incremental games in general as well as game-specific communities - tend to be very developer friendly as well. A lot of the developers know each other, and welcome new developers with open arms, often with dedicated channels for programming help and discussions.

Monetization

I'd like to clarify that everything I've said above mainly applies to web-based incrementals. Incremental games are also incredibly popular on mobile, but with a much different culture and community. Many mobile gamers will still participate in the web-focused community for the culture. This web-focused community has a culture that has been criticized for being "anti-monetization". Ads, IAPs, and similar forms of monetization are often criticized, mainly due to the abundance of completely non-monetized games available from hobbyist developers. There are exceptions, like paid games often being considered fine, like Increlution or Stuck in Time, or donation ware games like kittens game, but even popular games that have IAP see some level of regular criticism, like NGU Idle, Idle Skilling, or Idle Pins. A large part of this can be explained by the community being hyper-aware of the addictive) nature of this genre and its susceptibility to exploiting players.

On mobile, however, monetization is the norm and expected. If an incremental game is available on mobile, it almost certainly will be monetized, and mobile players are aware and accepting of that. Mobile incremental games, due to their addictive nature, tend to make a lot of money. It's very lucrative, and therefore these games are quite abundant on mobile storefronts.

',14),b=JSON.parse('{"title":"Guide to Incrementals/Appeal to Developers","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/appeal-to-developers","title":"Guide to Incrementals/Appeal to Developers","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/ludology/appeal-developers/index.md","filePath":"guide-to-incrementals/ludology/appeal-developers/index.md"}'),p={name:"guide-to-incrementals/ludology/appeal-developers/index.md"},v=Object.assign(p,{setup(h){const t=o();return(u,g)=>(l(),i("div",null,[d,e("p",null,[r("636 words, ~3 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),c]))}});export{b as __pageData,v as default}; diff --git a/assets/guide-to-incrementals_ludology_appeal-developers_index.md.CIgpgpNd.lean.js b/assets/guide-to-incrementals_ludology_appeal-developers_index.md.BdUXpm07.lean.js similarity index 80% rename from assets/guide-to-incrementals_ludology_appeal-developers_index.md.CIgpgpNd.lean.js rename to assets/guide-to-incrementals_ludology_appeal-developers_index.md.BdUXpm07.lean.js index 17150772..8754e87d 100644 --- a/assets/guide-to-incrementals_ludology_appeal-developers_index.md.CIgpgpNd.lean.js +++ b/assets/guide-to-incrementals_ludology_appeal-developers_index.md.BdUXpm07.lean.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as o,c as i,j as e,a as r,k as a,ag as s,o as l}from"./chunks/framework.VBE0TPts.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals___Appeal to Developers",-1),m=["innerHTML"],c=s("",14),b=JSON.parse('{"title":"Guide to Incrementals/Appeal to Developers","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/appeal-to-developers","title":"Guide to Incrementals/Appeal to Developers","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/ludology/appeal-developers/index.md","filePath":"guide-to-incrementals/ludology/appeal-developers/index.md"}'),p={name:"guide-to-incrementals/ludology/appeal-developers/index.md"},v=Object.assign(p,{setup(h){const t=o();return(u,g)=>(l(),i("div",null,[d,e("p",null,[r("636 words, ~3 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),c]))}});export{b as __pageData,v as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as o,q as i,Q as e,K as r,u as a,ag as s,p as l}from"./chunks/framework.DvHfxfnp.js";const d=e("h1",{class:"p-name"},"Guide to Incrementals___Appeal to Developers",-1),m=["innerHTML"],c=s("",14),b=JSON.parse('{"title":"Guide to Incrementals/Appeal to Developers","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/appeal-to-developers","title":"Guide to Incrementals/Appeal to Developers","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/ludology/appeal-developers/index.md","filePath":"guide-to-incrementals/ludology/appeal-developers/index.md"}'),p={name:"guide-to-incrementals/ludology/appeal-developers/index.md"},v=Object.assign(p,{setup(h){const t=o();return(u,g)=>(l(),i("div",null,[d,e("p",null,[r("636 words, ~3 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),c]))}});export{b as __pageData,v as default}; diff --git a/assets/guide-to-incrementals_ludology_appeal-gamers_index.md.KF6NxDNl.js b/assets/guide-to-incrementals_ludology_appeal-gamers_index.md.DIzXBzVM.js similarity index 98% rename from assets/guide-to-incrementals_ludology_appeal-gamers_index.md.KF6NxDNl.js rename to assets/guide-to-incrementals_ludology_appeal-gamers_index.md.DIzXBzVM.js index c2353ba4..2ae46643 100644 --- a/assets/guide-to-incrementals_ludology_appeal-gamers_index.md.KF6NxDNl.js +++ b/assets/guide-to-incrementals_ludology_appeal-gamers_index.md.DIzXBzVM.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as i,c as o,j as e,a as s,k as a,ag as r,o as l}from"./chunks/framework.VBE0TPts.js";const h=e("h1",{class:"p-name"},"Guide to Incrementals___Appeal to Players",-1),m=["innerHTML"],g=r('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

This is something that has been discussed and analyzed by many people, and to some extent, I feel like everything that can be said on the topic already has. However, a lot of these analyses are from the perspective of those with not as much experience and involvement within the genre as I'd argue would be necessary for a fully contextualized answer. I'm interested in ludology and part of that includes interpreting games as art, and to that end what constitutes a game, let alone a "good game". Incremental games are oft criticized, unfairly in my biased opinion, of not even constituting games, such as was posited by this polygon article.

Numbers Going Up

This is a very common response to why people enjoy incremental games, although it's not one I find compels me personally, and I suspect it might be a stand-in for progression) or Guide to Incrementals/What is Content?. But reportedly, some people do just like seeing big numbers. I must reiterate I suspect the actual cause is seeing big numbers in context though - if you start at 1e1000 of a currency and get to 1e1001, that isn't going to feel as satisfying as going from 1e10 to 1e100, and in any case, I don't think a button that just adds a zero to your number will feel quite satisfying - I believe its the sense of having made progress, and comparing where you are to where you started and feeling like you've earned your way here that is enjoyable.

Progression

I think a strong sense of progression is seen as very enjoyable to many players of all sorts of genres - engine builder board games, RPGs, rogue_lites_, etc. Incremental games tend to have an extremely exaggerated sense of progression, which makes them very appealing.

Meta-progression is when games have some sort of progression that persists when other progress gets lost - for example, upgrades that persist between runs of a roguelite game. These are common mechanics in incremental games - in fact, its not uncommon to have multiple of these reset mechanics nested on top of each other, each with their own meta-progression. These are satisfying to players, although they can be a bit controversial. These mechanics can often be seen as an optional crutch, and in roguelite games, players often challenge themselves to win without any meta progression. Essentially these challenges argue that meta-progression de-emphasizes player skill by replacing it with time served. Incremental games, through their exaggerated progression, eschew that possibility though - they make it impossible to beat without the meta progression systems, as the meta-progression becomes an entire chapter of the gameplay. I'd argue this does not detract from the game, however, and is actually a part of what makes incremental games, and roguelikes, enjoyable to many players: meta-progression augments the increases in skill the player is naturally gaining as they play. In effect, it's not replacing the skill increase, but exaggerating it to make it feel more real to the player.

Effortlessness

Incremental games are so easy, a lot of them even have you progress while you're not playing! Part of the appeal is being able to feel like you're making progress while doing something actually productive - multitasking, in a way. In this sense, the game is more of a fidget toy - not something to think hard about and play actively, but something to click a few buttons every so often while you're paying attention to a lecture or studying or working. Of course, not all incremental games lend themselves to being played this way - it's specifically "idle" games that work like this. These are games that take an incredibly long amount of time to see all the content, stretching it as thin as possible, but they aren't expecting you to be sitting at your device playing it the entire time. They expect you to leave and come back later to make a bit of progress and repeat the cycle.

If you look at the higher-level play of most games, you'll see them perform difficult feats with ease and speed. They'll achieve a "flow state" that takes all their knowledge and experience of the game and uses it to play the game as instinctively as possible. It's incredible to watch things like Slay the Spire speed runs or competitive DDR-likes. I'd argue the goal of a lot of games with a competitive scene is to get so good that the game becomes effortless. In that sense, a game that allows you to reach that point earlier isn't any less legitimate, but rather lowers the barrier to entry by allowing more people to get "really good" at the game. And to be clear, (most) incremental games aren't trivially easy - they, and to an extent, every game will have some level of learning and improvement over time.

Addiction

A lot of these reasons for why incremental games appeal may have reminded you of why gambling appeals to people, particularly those prone to addiction. Indeed, incremental games are quite often criticized for their similarity to a skinner box. Some have gone as far as to say incremental games as a genre are commenting that all games are skinner boxes). The argument goes that some games are not fun, but rather condition players into continuing to play without actually getting anything from the experience. When tied to real-world money this is seen as predatory, and to a lesser extent, even free games may be feeding the addictive sides of people and making them more prone to seek out gambling or micro-transaction heavy games.

While incremental games can be fun and even healthy in certain contexts, they can exacerbate video game addiction more than other genres. If you feel like playing incremental games is taking priority over other things in your life, or manipulating your sleep schedule, it may be prudent to seek help. See r/StopGaming for resources.

Since incremental games are often built on extrinsic motivations in the form of progression systems, it's hard to argue whether players continue to play because they are enjoying the gameplay, or if they are just conditioned to keep doing it because the game keeps rewarding them. Unfortunately, it can often feel like it's the latter, as there isn't typically anything compelling about the "gameplay" of clicking a button and waiting. There may be a significant overlap between those who enjoy incremental games and those who are most prone to addiction, and there are often posts on r/incremental_games about someone either struggling with or overcoming video game addiction.

Strategy

Incremental games could be considered a subset of strategy games), and inherit the appeals of strategy games. This includes the appeal of feeling like you've found a good solution to a puzzle, or that you're learning more about the game and are improving at making decisions within it.

Note that strategy games are not all the same difficulty, as well. Cookie Clicker is probably easier than Starcraft 2 (although late game may beg to differ). Plenty of incremental games can be used as evidence that "easier" strategies may have their separate appeal to harder strategy games - players like to feel smart and that they figured the game out and have optimized or mastered it, and the game being easier doesn't detract from that sense of accomplishment as much as it allows more and more users to be able to reach the point where they gain that sense.

Avoiding Staleness

Incremental games tend to have "paradigm shifts", where the gameplay changes in a meaningful way at various times throughout the progression of the game. These upset and change the gameplay loop, which helps keep them from stagnating. This constant "freshness" to the gameplay can keep players engaged for longer, compared to a game with a repetitive and static gameplay loop.

Good Game Design

Incremental games tend to show their game design "plainly", so it's more readily apparent if a game has good game design while playing, even if you're not looking for it. While different players have different preferences and might enjoy different types of games more than others, there are underlying good and bad game design principles that players will notice the effects of. To be clear, this isn't talking about stuff like big numbers being enjoyable, where I can comfortably agree to disagree with other players. They don't intrinsically make my experience better, but I'm aware of those for whom it does and I won't argue against their feelings. However, the game designer in me does feel like there are some extremely clear-cut examples of good and bad game design philosophies.

Let's start by giving an example of a mechanic I think can be easily and strongly argued is good game design. There are of course many examples, but a personal favorite of mine is how DOOM encourages aggressive gameplay by linking health drops to melee attacks. It has an intended experience it's trying to give the player - immersing themselves as DOOM guy, who would not hide behind cover when low on health - and this mechanic does a great job at encouraging and effectively teaching players to behave properly. This is in sharp contrast to shooters like Call of Duty, which have you regen health passively, encouraging players to hide behind cover and wait after getting hit. Note that I'm not arguing CoD is poorly designed, as the games have different intended experiences. I'm specifically praising DOOM for having a mechanic that does a good job at ensuring the player has that intended experience.

To contrast with an example I think is bad game design, let's talk about shields in souls-likes. This is a bit of a famous example, and I highly recommend this video essay which spends quite a good bit of time on this topic. Essentially, the argument boils down to players of earlier games in the souls games using shields too much - playing slowly, conservatively, and ultimately having less fun. Players wanted to feel safe, so they ended up playing in a way that ruined the experience for them. The developers solved this by removing shields, apart from an intentionally bad one effectively mocking the playstyle, and it did its job at getting players to play more aggressively, and often have more fun.

To bring the conversation back to incrementals, I'm incredibly opinionated on what makes a good incremental game, which I'll discuss in the game design section. Suffice it to say, incremental games rely more on good game design than other genres, due to not having much to distract from bad game design. This helps (although imperfectly - gamers are a bit too tolerant of bad game design!) well-designed games rise to the top within the genre.

Artistic Merit

The discussion of whether video games are art has resulted in a pretty universal "yes, they are", but with some games the argument may still crop up. The reason why Incremental games are sometimes questioned is due to their perceived lack of complexity. However, even setting aside the fact that if players are having fun then it's not time wasted, I think games can have artistic merit that supersedes the necessity of having (any / engaging / "deep") gameplay. Incremental games are no less legitimate of a game or the "art" label because of any lack perceived lack of depth. For what it's worth, most art can be consumed with more ease than any video game - any painting, movie, sculpture, etc.

A lot of incrementals have a narrative context that can similarly qualify them as art. Cookie Clicker is, as has been pointed out numerous times before, commenting on excess and increasing production beyond any reasonable limits - devolving into increasing production for its own sake. Indeed, a lot of incremental games are written to comment upon various concepts like capitalism or tropes in games, as discussed when defining Incrementals). However, I'd like to argue most incremental games are still art, even without any narrative context. "Art" as a concept is pretty nebulous already, but I personally like those who define it as an act of expression more than any physical result. The creator and the context within which they created the art, and any meaning they put into it, are all relevant and a part of the art itself. Most incremental games have artistic merit from things like why the creator made it, why they chose to make it an incremental game, and why they made any particular design decision. Hell, even if you play through an entire incremental game without a single thought or feeling, that very fact it elicited nothing can itself be artistic merit!

I'm not an art major, and I may be taking a somewhat extreme take on what is art and what has artistic merit, but I'd argue the overall point stands that games, and incremental games specifically, can have artistic merit, which appeals to many gamers.

',29),b=JSON.parse('{"title":"Guide to Incrementals/Appeal to Players","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/appeal-to-players","title":"Guide to Incrementals/Appeal to Players","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/ludology/appeal-gamers/index.md","filePath":"guide-to-incrementals/ludology/appeal-gamers/index.md"}'),d={name:"guide-to-incrementals/ludology/appeal-gamers/index.md"},w=Object.assign(d,{setup(c){const t=i();return(p,u)=>(l(),o("div",null,[h,e("p",null,[s("2166 words, ~12 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),g]))}});export{b as __pageData,w as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as o,Q as e,K as s,u as a,ag as r,p as l}from"./chunks/framework.DvHfxfnp.js";const h=e("h1",{class:"p-name"},"Guide to Incrementals___Appeal to Players",-1),m=["innerHTML"],g=r('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

This is something that has been discussed and analyzed by many people, and to some extent, I feel like everything that can be said on the topic already has. However, a lot of these analyses are from the perspective of those with not as much experience and involvement within the genre as I'd argue would be necessary for a fully contextualized answer. I'm interested in ludology and part of that includes interpreting games as art, and to that end what constitutes a game, let alone a "good game". Incremental games are oft criticized, unfairly in my biased opinion, of not even constituting games, such as was posited by this polygon article.

Numbers Going Up

This is a very common response to why people enjoy incremental games, although it's not one I find compels me personally, and I suspect it might be a stand-in for progression) or Guide to Incrementals/What is Content?. But reportedly, some people do just like seeing big numbers. I must reiterate I suspect the actual cause is seeing big numbers in context though - if you start at 1e1000 of a currency and get to 1e1001, that isn't going to feel as satisfying as going from 1e10 to 1e100, and in any case, I don't think a button that just adds a zero to your number will feel quite satisfying - I believe its the sense of having made progress, and comparing where you are to where you started and feeling like you've earned your way here that is enjoyable.

Progression

I think a strong sense of progression is seen as very enjoyable to many players of all sorts of genres - engine builder board games, RPGs, rogue_lites_, etc. Incremental games tend to have an extremely exaggerated sense of progression, which makes them very appealing.

Meta-progression is when games have some sort of progression that persists when other progress gets lost - for example, upgrades that persist between runs of a roguelite game. These are common mechanics in incremental games - in fact, its not uncommon to have multiple of these reset mechanics nested on top of each other, each with their own meta-progression. These are satisfying to players, although they can be a bit controversial. These mechanics can often be seen as an optional crutch, and in roguelite games, players often challenge themselves to win without any meta progression. Essentially these challenges argue that meta-progression de-emphasizes player skill by replacing it with time served. Incremental games, through their exaggerated progression, eschew that possibility though - they make it impossible to beat without the meta progression systems, as the meta-progression becomes an entire chapter of the gameplay. I'd argue this does not detract from the game, however, and is actually a part of what makes incremental games, and roguelikes, enjoyable to many players: meta-progression augments the increases in skill the player is naturally gaining as they play. In effect, it's not replacing the skill increase, but exaggerating it to make it feel more real to the player.

Effortlessness

Incremental games are so easy, a lot of them even have you progress while you're not playing! Part of the appeal is being able to feel like you're making progress while doing something actually productive - multitasking, in a way. In this sense, the game is more of a fidget toy - not something to think hard about and play actively, but something to click a few buttons every so often while you're paying attention to a lecture or studying or working. Of course, not all incremental games lend themselves to being played this way - it's specifically "idle" games that work like this. These are games that take an incredibly long amount of time to see all the content, stretching it as thin as possible, but they aren't expecting you to be sitting at your device playing it the entire time. They expect you to leave and come back later to make a bit of progress and repeat the cycle.

If you look at the higher-level play of most games, you'll see them perform difficult feats with ease and speed. They'll achieve a "flow state" that takes all their knowledge and experience of the game and uses it to play the game as instinctively as possible. It's incredible to watch things like Slay the Spire speed runs or competitive DDR-likes. I'd argue the goal of a lot of games with a competitive scene is to get so good that the game becomes effortless. In that sense, a game that allows you to reach that point earlier isn't any less legitimate, but rather lowers the barrier to entry by allowing more people to get "really good" at the game. And to be clear, (most) incremental games aren't trivially easy - they, and to an extent, every game will have some level of learning and improvement over time.

Addiction

A lot of these reasons for why incremental games appeal may have reminded you of why gambling appeals to people, particularly those prone to addiction. Indeed, incremental games are quite often criticized for their similarity to a skinner box. Some have gone as far as to say incremental games as a genre are commenting that all games are skinner boxes). The argument goes that some games are not fun, but rather condition players into continuing to play without actually getting anything from the experience. When tied to real-world money this is seen as predatory, and to a lesser extent, even free games may be feeding the addictive sides of people and making them more prone to seek out gambling or micro-transaction heavy games.

While incremental games can be fun and even healthy in certain contexts, they can exacerbate video game addiction more than other genres. If you feel like playing incremental games is taking priority over other things in your life, or manipulating your sleep schedule, it may be prudent to seek help. See r/StopGaming for resources.

Since incremental games are often built on extrinsic motivations in the form of progression systems, it's hard to argue whether players continue to play because they are enjoying the gameplay, or if they are just conditioned to keep doing it because the game keeps rewarding them. Unfortunately, it can often feel like it's the latter, as there isn't typically anything compelling about the "gameplay" of clicking a button and waiting. There may be a significant overlap between those who enjoy incremental games and those who are most prone to addiction, and there are often posts on r/incremental_games about someone either struggling with or overcoming video game addiction.

Strategy

Incremental games could be considered a subset of strategy games), and inherit the appeals of strategy games. This includes the appeal of feeling like you've found a good solution to a puzzle, or that you're learning more about the game and are improving at making decisions within it.

Note that strategy games are not all the same difficulty, as well. Cookie Clicker is probably easier than Starcraft 2 (although late game may beg to differ). Plenty of incremental games can be used as evidence that "easier" strategies may have their separate appeal to harder strategy games - players like to feel smart and that they figured the game out and have optimized or mastered it, and the game being easier doesn't detract from that sense of accomplishment as much as it allows more and more users to be able to reach the point where they gain that sense.

Avoiding Staleness

Incremental games tend to have "paradigm shifts", where the gameplay changes in a meaningful way at various times throughout the progression of the game. These upset and change the gameplay loop, which helps keep them from stagnating. This constant "freshness" to the gameplay can keep players engaged for longer, compared to a game with a repetitive and static gameplay loop.

Good Game Design

Incremental games tend to show their game design "plainly", so it's more readily apparent if a game has good game design while playing, even if you're not looking for it. While different players have different preferences and might enjoy different types of games more than others, there are underlying good and bad game design principles that players will notice the effects of. To be clear, this isn't talking about stuff like big numbers being enjoyable, where I can comfortably agree to disagree with other players. They don't intrinsically make my experience better, but I'm aware of those for whom it does and I won't argue against their feelings. However, the game designer in me does feel like there are some extremely clear-cut examples of good and bad game design philosophies.

Let's start by giving an example of a mechanic I think can be easily and strongly argued is good game design. There are of course many examples, but a personal favorite of mine is how DOOM encourages aggressive gameplay by linking health drops to melee attacks. It has an intended experience it's trying to give the player - immersing themselves as DOOM guy, who would not hide behind cover when low on health - and this mechanic does a great job at encouraging and effectively teaching players to behave properly. This is in sharp contrast to shooters like Call of Duty, which have you regen health passively, encouraging players to hide behind cover and wait after getting hit. Note that I'm not arguing CoD is poorly designed, as the games have different intended experiences. I'm specifically praising DOOM for having a mechanic that does a good job at ensuring the player has that intended experience.

To contrast with an example I think is bad game design, let's talk about shields in souls-likes. This is a bit of a famous example, and I highly recommend this video essay which spends quite a good bit of time on this topic. Essentially, the argument boils down to players of earlier games in the souls games using shields too much - playing slowly, conservatively, and ultimately having less fun. Players wanted to feel safe, so they ended up playing in a way that ruined the experience for them. The developers solved this by removing shields, apart from an intentionally bad one effectively mocking the playstyle, and it did its job at getting players to play more aggressively, and often have more fun.

To bring the conversation back to incrementals, I'm incredibly opinionated on what makes a good incremental game, which I'll discuss in the game design section. Suffice it to say, incremental games rely more on good game design than other genres, due to not having much to distract from bad game design. This helps (although imperfectly - gamers are a bit too tolerant of bad game design!) well-designed games rise to the top within the genre.

Artistic Merit

The discussion of whether video games are art has resulted in a pretty universal "yes, they are", but with some games the argument may still crop up. The reason why Incremental games are sometimes questioned is due to their perceived lack of complexity. However, even setting aside the fact that if players are having fun then it's not time wasted, I think games can have artistic merit that supersedes the necessity of having (any / engaging / "deep") gameplay. Incremental games are no less legitimate of a game or the "art" label because of any lack perceived lack of depth. For what it's worth, most art can be consumed with more ease than any video game - any painting, movie, sculpture, etc.

A lot of incrementals have a narrative context that can similarly qualify them as art. Cookie Clicker is, as has been pointed out numerous times before, commenting on excess and increasing production beyond any reasonable limits - devolving into increasing production for its own sake. Indeed, a lot of incremental games are written to comment upon various concepts like capitalism or tropes in games, as discussed when defining Incrementals). However, I'd like to argue most incremental games are still art, even without any narrative context. "Art" as a concept is pretty nebulous already, but I personally like those who define it as an act of expression more than any physical result. The creator and the context within which they created the art, and any meaning they put into it, are all relevant and a part of the art itself. Most incremental games have artistic merit from things like why the creator made it, why they chose to make it an incremental game, and why they made any particular design decision. Hell, even if you play through an entire incremental game without a single thought or feeling, that very fact it elicited nothing can itself be artistic merit!

I'm not an art major, and I may be taking a somewhat extreme take on what is art and what has artistic merit, but I'd argue the overall point stands that games, and incremental games specifically, can have artistic merit, which appeals to many gamers.

',29),b=JSON.parse('{"title":"Guide to Incrementals/Appeal to Players","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/appeal-to-players","title":"Guide to Incrementals/Appeal to Players","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/ludology/appeal-gamers/index.md","filePath":"guide-to-incrementals/ludology/appeal-gamers/index.md"}'),d={name:"guide-to-incrementals/ludology/appeal-gamers/index.md"},w=Object.assign(d,{setup(c){const t=i();return(p,u)=>(l(),o("div",null,[h,e("p",null,[s("2166 words, ~12 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),g]))}});export{b as __pageData,w as default}; diff --git a/assets/guide-to-incrementals_ludology_appeal-gamers_index.md.KF6NxDNl.lean.js b/assets/guide-to-incrementals_ludology_appeal-gamers_index.md.DIzXBzVM.lean.js similarity index 79% rename from assets/guide-to-incrementals_ludology_appeal-gamers_index.md.KF6NxDNl.lean.js rename to assets/guide-to-incrementals_ludology_appeal-gamers_index.md.DIzXBzVM.lean.js index 35de5e4f..60020279 100644 --- a/assets/guide-to-incrementals_ludology_appeal-gamers_index.md.KF6NxDNl.lean.js +++ b/assets/guide-to-incrementals_ludology_appeal-gamers_index.md.DIzXBzVM.lean.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as i,c as o,j as e,a as s,k as a,ag as r,o as l}from"./chunks/framework.VBE0TPts.js";const h=e("h1",{class:"p-name"},"Guide to Incrementals___Appeal to Players",-1),m=["innerHTML"],g=r("",29),b=JSON.parse('{"title":"Guide to Incrementals/Appeal to Players","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/appeal-to-players","title":"Guide to Incrementals/Appeal to Players","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/ludology/appeal-gamers/index.md","filePath":"guide-to-incrementals/ludology/appeal-gamers/index.md"}'),d={name:"guide-to-incrementals/ludology/appeal-gamers/index.md"},w=Object.assign(d,{setup(c){const t=i();return(p,u)=>(l(),o("div",null,[h,e("p",null,[s("2166 words, ~12 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),g]))}});export{b as __pageData,w as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as i,q as o,Q as e,K as s,u as a,ag as r,p as l}from"./chunks/framework.DvHfxfnp.js";const h=e("h1",{class:"p-name"},"Guide to Incrementals___Appeal to Players",-1),m=["innerHTML"],g=r("",29),b=JSON.parse('{"title":"Guide to Incrementals/Appeal to Players","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/appeal-to-players","title":"Guide to Incrementals/Appeal to Players","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/ludology/appeal-gamers/index.md","filePath":"guide-to-incrementals/ludology/appeal-gamers/index.md"}'),d={name:"guide-to-incrementals/ludology/appeal-gamers/index.md"},w=Object.assign(d,{setup(c){const t=i();return(p,u)=>(l(),o("div",null,[h,e("p",null,[s("2166 words, ~12 minute read. "),e("span",{innerHTML:a(n)[`site/${a(t).page.value.relativePath}`]},null,8,m)]),g]))}});export{b as __pageData,w as default}; diff --git a/assets/guide-to-incrementals_ludology_content_index.md.CIJoP_r0.js b/assets/guide-to-incrementals_ludology_content_index.md.BFqVGpC-.js similarity index 98% rename from assets/guide-to-incrementals_ludology_content_index.md.CIJoP_r0.js rename to assets/guide-to-incrementals_ludology_content_index.md.BFqVGpC-.js index 698ad3c4..b7a26809 100644 --- a/assets/guide-to-incrementals_ludology_content_index.md.CIJoP_r0.js +++ b/assets/guide-to-incrementals_ludology_content_index.md.BFqVGpC-.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as o,c as i,j as e,a as s,k as t,ag as r,o as h}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"Guide to Incrementals___What is Content?",-1),c=["innerHTML"],u=r('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

If you've been in the incremental games community for any amount of time, you'll quickly find the number one thing players want is content. They want as much of it as possible! The most popular incremental games have tons of content, so they just keep stretching on and on and on, introducing mechanic after mechanic, and players love it. In fact, players seem to value the amount of content over the quality of any specific content. However, there's a bit of a lack of understanding concerning what content is, and I'd like to explore what counts as content, and how we measure it. As a baseline definition, I think "content" can just be described as the parts of the game that engage the player, but to truly understand it we need to contextualize what that means and how it affects the gameplay experience.

To clarify the purpose of this page, my goal is not to get (too) nitpicky or to attack games with "low content". There's nothing wrong with short / low-content games - I'm quite a big fan of those games myself! This is mostly targeted toward those who ask for content and settle for "long" games, and those who want to provide content but want to make sure they're not just artificially inflating the game. Ultimately, I suppose the goal is to just reduce the amount of artificially inflated content for the sake of having a "longer" game.

Interaction

I think it should be a fairly non-controversial opinion that time spent solely waiting should not count towards content. That is not including the time reading various effects or making decisions in your head, but rather time spent waiting for a condition to be met so you can re-engage with the game.

That is not to say games should necessarily try to minimize this time. Plenty of games lead towards more infrequent interaction and still get popular. In fact, these games appeal to many gamers who want to have something to check up on in between bursts of working on some other activity. These games seem to have fallen slightly out of fashion amongst modern incremental games, but they're still fully valid. The point I'm trying to make here is just that this time is not content. As an extreme example, a game with no interactions and just a counter that goes up every second could safely be said to have 0 content beyond the time it takes to understand what's going on. If it has a list of "goals" to hit, then the time understanding those goals and a short time after achieving each one could be considered content, but not the idle times in between.

Let's take a look at the opposite end of the spectrum - interaction that is so frequent as to become mindless. This is any mechanic where you need to spam-click something to progress. This may be a more controversial take, but I do not believe this constitutes content either. It does not engage the player, because each consecutive click blends together and they do not individually change the gameplay experience. That is to say, a single click and 100 clicks are not meaningfully different in terms of engaging the player. I'd go as far as to say clicking 100 times would be actively worse, as it's artificially delaying the next piece of actual content, alongside the issues of accessibility and potentially causing RSI.

Repeatable Purchases

Imagine an entity in a game that you can purchase multiple times, each time it performs the same thing but for a higher cost. These are incredibly common, from the buildings in cookie clicker to the units in swarm sim to the IP and EP multipliers in antimatter dimensions. However, how much content is each specific purchase? Is it content beyond the first purchase? Does it have diminishing returns? What if you are oscillating between two different repeatable purchases? How much content is lost when you automate) away a repeatable purchase?

I don't want to take too harsh a stance against repeatable purchases. They're useful tools and can be used in a myriad of interesting ways. I feel they do become "stale" or less meaningful content over time, and this happens exponentially quickly the more frequently it can be purchased. A classic example that I believe goes too far is the IP/EP multipliers in Antimatter Dimensions. I would go as far as to say they are a chore and do not provide any meaningful content after you've bought them a couple of times. It's a method for inflating numbers (effectively making every OOM a 5x step instead of 10x), that punishes the player progression-wise whenever they forget to max it again, and eventually gets automated away as a reward to the player for making enough progress.

Just to voice the other side of this argument, Acamaeda defended the IP multiplier as giving the player a "good" upgrade every OOM. I can understand that to a point and need to clarify I'm mainly criticizing IP/EP multipliers after they've been introduced for a while. In fact, I would defend the multipliers for a short while after they're introduced using the same logic I would use to defend normal dimensions as repeatable purchases, at least pre-infinity. There's "content" to be had in looking at what dimensions will become affordable next, and then choosing which to buy amongst those. The IP/EP multipliers, early into infinity or eternity respectively, provide another option that gets put into that mental queue of things to buy with each OOM reached - although the optimal order is often quite trivial and not particularly engaging.

The IP/EP multipliers are not the only repeatable purchase in antimatter dimensions I take offense to. The time dimensions are also a series of repeatable purchases, that are all so similar and static that it doesn't take long before you never need to put any thought into buying them, how much you're buying at once, or the order you buy them in - you just press max all and move on. The entire tab could've been just the max all button and it would not have made a difference beyond the start of the eternity layer. The normal dimensions technically have this problem as well, but since you're constantly getting antimatter the order feels like it has a larger impact and it's more meaningful content, right up until they're automated away. Infinity dimensions are a compromise between the two, so I'm highlighting time dimensions here as the most egregious.

Following Instructions

We're getting more and more controversial as we go along! Let's talk about how linear content is not content now (in some circumstances). A trend in incremental games is adding difficulty by adding a web of effects that abstract the true change you can expect from any specific purchase or decision you make. If a game is both linear and sufficiently abstracts the effect of player decisions, then the player will no longer be engaging with the content - they'll simply be clicking on things as they become available. This isn't necessarily a bad thing, as plenty of players don't mind this style of gameplay, but I'd argue once you reach a point where players don't bother reading the effects, those interactions are no longer truly content. Note that unlike the previous qualifiers mentioned, this qualifier is based on the player, and therefore subjective. In effect, it's a spectrum where the more complicated the web of effects becomes, the more likely it is to disengage the player.

This over-complicatedness leading to disengaging the player can also happen from non-linear gameplay. If the web of effects becomes sufficiently complicated and finding the optimal progression route too time-consuming to discover, players will seek out guides from other players who've completed the game. The second they do this, the game effectively becomes linearly following the instructions of the guide and all the above criticisms apply. Similarly to as before, though, this is a spectrum and not everyone will seek out a guide at the same level of difficulty.

Automation

Automation is a staple of the genre, but it has certain implications for the design of the game. Why, when new content is introduced, must the older content be automated away - why is it a chore and it feels rewarding to not have to do it again? Why does the new mechanic have such appeal if we know it too will just be automated away later on, and we'll be happy when that happens? It honestly begs the question of why this framework of introducing content and automating the old content is even enjoyable - and nearly nonexistent in other genres. You're not going to reach a point in a platformer game where they just automate the jumping part - that's the core mechanic! Instead, platformers either add new mechanics that build on the core mechanic or at least re-contextualize the core mechanic. However, in incremental games new content very frequently means replacing older content, as opposed to augmenting it.

Admittedly, the above paragraph ignores the obvious answer that separates incremental games in this regard. These mechanics become chores as their frequency increases. The frequency increases to give a sense of progression, and automation is seen as a reward because it now manages what was becoming unmanageable. The new content then comes in and continues the loop to give a stronger sense of progression. That's all good and a fine justification for automating content instead of building upon the base mechanic. It's also much easier to design, as each layer essentially lets you start over instead of needing to think of ideas that conform to the original core mechanic.

So, what's the problem? Even if this trend is justified and easy to implement, there are some other effects it has on the game design. First off, and this is probably a neutral point, incremental games with this cycle of replacing old mechanics with new ones trend towards more and more abstract and further away from any narrative throughline as they add layers. There are only so many justifications for resetting progress, so if a game wants to have several of these layers they're inevitably going to become generic or increasingly loosely associated with the original content. It's most unfortunate, in my opinion when an interesting or innovative core mechanic gets fully automated once a generic "prestige" layer is unlocked.

A recent example is Really Grass Cutting Incremental, an incremental game about cutting grass (although I'm really criticizing the Roblox game it's based on). Except, it doesn't continue to be about cutting grass. After you buy enough upgrades to increase your grass cutting and level up sufficiently you "prestige", an abstract term that in this case means you reset all your progress to get some currency to buy upgrades that do the same things as the original upgrades, but these won't reset on future prestiges. You'll eventually be able to "crystallize", which means you reset all your progress to get some currency to buy upgrades that do the same things as the original upgrades (and a couple of new ones) and won't reset on future crystallizes. Fine. You'll progress a bit, complete some challenges, and finally get to... grasshop? Grasshopping is this mechanic where you reset all your progress to get some resource that isn't for buying upgrades - this time you just unlock different modifiers on everything based on their amount. You may have gotten the point by now, but there are also "steelie" resets which give you steel for some reason, before unlocking a factory with various machines - none of which are directly tied to cutting grass, and start gathering things like oil and reset for rocket parts and reset to go to space and so on and so on. Throughout all of this there is absolutely no narrative justification or throughline for the direction the game is going, or why cutting grass is still relevant when we're collecting things like rocket parts. I may be going a little hard on GCI, but it is far from alone.

Tips for Developers

If you're a developer, by this point you should have a pretty decent idea of how to create "true" content in your game. Here are some other specific tips I'd suggest:

An upgrade that simply unlocks another upgrade trivially isn't content. However, many games have an upgrade that just unlocks a feature, which then has a wait or other requirements before it can be used. Try to make sure when you unlock a feature, there is immediately something to do with the feature - for example, perhaps give them a small amount of the new currency it unlocks, if applicable.

If you don't have a large web of effects, and can definitively say the impact of a purchase is to multiply the gain of the cost currency by N, and the next purchase costs N times the amount of that same currency, then this purchase effectively made no difference and it may have made more sense to just go directly to the next upgrade. That said, having effects based on things like the number of purchases made will quickly invalidate this tip.

',25),b=JSON.parse('{"title":"Guide to Incrementals/What is Content?","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/what-is-content-","title":"Guide to Incrementals/What is Content?","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/ludology/content/index.md","filePath":"guide-to-incrementals/ludology/content/index.md"}'),m={name:"guide-to-incrementals/ludology/content/index.md"},w=Object.assign(m,{setup(d){const a=o();return(g,p)=>(h(),i("div",null,[l,e("p",null,[s("2092 words, ~11 minute read. "),e("span",{innerHTML:t(n)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),u]))}});export{b as __pageData,w as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as o,q as i,Q as e,K as s,u as t,ag as r,p as h}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"Guide to Incrementals___What is Content?",-1),c=["innerHTML"],u=r('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

If you've been in the incremental games community for any amount of time, you'll quickly find the number one thing players want is content. They want as much of it as possible! The most popular incremental games have tons of content, so they just keep stretching on and on and on, introducing mechanic after mechanic, and players love it. In fact, players seem to value the amount of content over the quality of any specific content. However, there's a bit of a lack of understanding concerning what content is, and I'd like to explore what counts as content, and how we measure it. As a baseline definition, I think "content" can just be described as the parts of the game that engage the player, but to truly understand it we need to contextualize what that means and how it affects the gameplay experience.

To clarify the purpose of this page, my goal is not to get (too) nitpicky or to attack games with "low content". There's nothing wrong with short / low-content games - I'm quite a big fan of those games myself! This is mostly targeted toward those who ask for content and settle for "long" games, and those who want to provide content but want to make sure they're not just artificially inflating the game. Ultimately, I suppose the goal is to just reduce the amount of artificially inflated content for the sake of having a "longer" game.

Interaction

I think it should be a fairly non-controversial opinion that time spent solely waiting should not count towards content. That is not including the time reading various effects or making decisions in your head, but rather time spent waiting for a condition to be met so you can re-engage with the game.

That is not to say games should necessarily try to minimize this time. Plenty of games lead towards more infrequent interaction and still get popular. In fact, these games appeal to many gamers who want to have something to check up on in between bursts of working on some other activity. These games seem to have fallen slightly out of fashion amongst modern incremental games, but they're still fully valid. The point I'm trying to make here is just that this time is not content. As an extreme example, a game with no interactions and just a counter that goes up every second could safely be said to have 0 content beyond the time it takes to understand what's going on. If it has a list of "goals" to hit, then the time understanding those goals and a short time after achieving each one could be considered content, but not the idle times in between.

Let's take a look at the opposite end of the spectrum - interaction that is so frequent as to become mindless. This is any mechanic where you need to spam-click something to progress. This may be a more controversial take, but I do not believe this constitutes content either. It does not engage the player, because each consecutive click blends together and they do not individually change the gameplay experience. That is to say, a single click and 100 clicks are not meaningfully different in terms of engaging the player. I'd go as far as to say clicking 100 times would be actively worse, as it's artificially delaying the next piece of actual content, alongside the issues of accessibility and potentially causing RSI.

Repeatable Purchases

Imagine an entity in a game that you can purchase multiple times, each time it performs the same thing but for a higher cost. These are incredibly common, from the buildings in cookie clicker to the units in swarm sim to the IP and EP multipliers in antimatter dimensions. However, how much content is each specific purchase? Is it content beyond the first purchase? Does it have diminishing returns? What if you are oscillating between two different repeatable purchases? How much content is lost when you automate) away a repeatable purchase?

I don't want to take too harsh a stance against repeatable purchases. They're useful tools and can be used in a myriad of interesting ways. I feel they do become "stale" or less meaningful content over time, and this happens exponentially quickly the more frequently it can be purchased. A classic example that I believe goes too far is the IP/EP multipliers in Antimatter Dimensions. I would go as far as to say they are a chore and do not provide any meaningful content after you've bought them a couple of times. It's a method for inflating numbers (effectively making every OOM a 5x step instead of 10x), that punishes the player progression-wise whenever they forget to max it again, and eventually gets automated away as a reward to the player for making enough progress.

Just to voice the other side of this argument, Acamaeda defended the IP multiplier as giving the player a "good" upgrade every OOM. I can understand that to a point and need to clarify I'm mainly criticizing IP/EP multipliers after they've been introduced for a while. In fact, I would defend the multipliers for a short while after they're introduced using the same logic I would use to defend normal dimensions as repeatable purchases, at least pre-infinity. There's "content" to be had in looking at what dimensions will become affordable next, and then choosing which to buy amongst those. The IP/EP multipliers, early into infinity or eternity respectively, provide another option that gets put into that mental queue of things to buy with each OOM reached - although the optimal order is often quite trivial and not particularly engaging.

The IP/EP multipliers are not the only repeatable purchase in antimatter dimensions I take offense to. The time dimensions are also a series of repeatable purchases, that are all so similar and static that it doesn't take long before you never need to put any thought into buying them, how much you're buying at once, or the order you buy them in - you just press max all and move on. The entire tab could've been just the max all button and it would not have made a difference beyond the start of the eternity layer. The normal dimensions technically have this problem as well, but since you're constantly getting antimatter the order feels like it has a larger impact and it's more meaningful content, right up until they're automated away. Infinity dimensions are a compromise between the two, so I'm highlighting time dimensions here as the most egregious.

Following Instructions

We're getting more and more controversial as we go along! Let's talk about how linear content is not content now (in some circumstances). A trend in incremental games is adding difficulty by adding a web of effects that abstract the true change you can expect from any specific purchase or decision you make. If a game is both linear and sufficiently abstracts the effect of player decisions, then the player will no longer be engaging with the content - they'll simply be clicking on things as they become available. This isn't necessarily a bad thing, as plenty of players don't mind this style of gameplay, but I'd argue once you reach a point where players don't bother reading the effects, those interactions are no longer truly content. Note that unlike the previous qualifiers mentioned, this qualifier is based on the player, and therefore subjective. In effect, it's a spectrum where the more complicated the web of effects becomes, the more likely it is to disengage the player.

This over-complicatedness leading to disengaging the player can also happen from non-linear gameplay. If the web of effects becomes sufficiently complicated and finding the optimal progression route too time-consuming to discover, players will seek out guides from other players who've completed the game. The second they do this, the game effectively becomes linearly following the instructions of the guide and all the above criticisms apply. Similarly to as before, though, this is a spectrum and not everyone will seek out a guide at the same level of difficulty.

Automation

Automation is a staple of the genre, but it has certain implications for the design of the game. Why, when new content is introduced, must the older content be automated away - why is it a chore and it feels rewarding to not have to do it again? Why does the new mechanic have such appeal if we know it too will just be automated away later on, and we'll be happy when that happens? It honestly begs the question of why this framework of introducing content and automating the old content is even enjoyable - and nearly nonexistent in other genres. You're not going to reach a point in a platformer game where they just automate the jumping part - that's the core mechanic! Instead, platformers either add new mechanics that build on the core mechanic or at least re-contextualize the core mechanic. However, in incremental games new content very frequently means replacing older content, as opposed to augmenting it.

Admittedly, the above paragraph ignores the obvious answer that separates incremental games in this regard. These mechanics become chores as their frequency increases. The frequency increases to give a sense of progression, and automation is seen as a reward because it now manages what was becoming unmanageable. The new content then comes in and continues the loop to give a stronger sense of progression. That's all good and a fine justification for automating content instead of building upon the base mechanic. It's also much easier to design, as each layer essentially lets you start over instead of needing to think of ideas that conform to the original core mechanic.

So, what's the problem? Even if this trend is justified and easy to implement, there are some other effects it has on the game design. First off, and this is probably a neutral point, incremental games with this cycle of replacing old mechanics with new ones trend towards more and more abstract and further away from any narrative throughline as they add layers. There are only so many justifications for resetting progress, so if a game wants to have several of these layers they're inevitably going to become generic or increasingly loosely associated with the original content. It's most unfortunate, in my opinion when an interesting or innovative core mechanic gets fully automated once a generic "prestige" layer is unlocked.

A recent example is Really Grass Cutting Incremental, an incremental game about cutting grass (although I'm really criticizing the Roblox game it's based on). Except, it doesn't continue to be about cutting grass. After you buy enough upgrades to increase your grass cutting and level up sufficiently you "prestige", an abstract term that in this case means you reset all your progress to get some currency to buy upgrades that do the same things as the original upgrades, but these won't reset on future prestiges. You'll eventually be able to "crystallize", which means you reset all your progress to get some currency to buy upgrades that do the same things as the original upgrades (and a couple of new ones) and won't reset on future crystallizes. Fine. You'll progress a bit, complete some challenges, and finally get to... grasshop? Grasshopping is this mechanic where you reset all your progress to get some resource that isn't for buying upgrades - this time you just unlock different modifiers on everything based on their amount. You may have gotten the point by now, but there are also "steelie" resets which give you steel for some reason, before unlocking a factory with various machines - none of which are directly tied to cutting grass, and start gathering things like oil and reset for rocket parts and reset to go to space and so on and so on. Throughout all of this there is absolutely no narrative justification or throughline for the direction the game is going, or why cutting grass is still relevant when we're collecting things like rocket parts. I may be going a little hard on GCI, but it is far from alone.

Tips for Developers

If you're a developer, by this point you should have a pretty decent idea of how to create "true" content in your game. Here are some other specific tips I'd suggest:

An upgrade that simply unlocks another upgrade trivially isn't content. However, many games have an upgrade that just unlocks a feature, which then has a wait or other requirements before it can be used. Try to make sure when you unlock a feature, there is immediately something to do with the feature - for example, perhaps give them a small amount of the new currency it unlocks, if applicable.

If you don't have a large web of effects, and can definitively say the impact of a purchase is to multiply the gain of the cost currency by N, and the next purchase costs N times the amount of that same currency, then this purchase effectively made no difference and it may have made more sense to just go directly to the next upgrade. That said, having effects based on things like the number of purchases made will quickly invalidate this tip.

',25),b=JSON.parse('{"title":"Guide to Incrementals/What is Content?","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/what-is-content-","title":"Guide to Incrementals/What is Content?","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/ludology/content/index.md","filePath":"guide-to-incrementals/ludology/content/index.md"}'),m={name:"guide-to-incrementals/ludology/content/index.md"},w=Object.assign(m,{setup(d){const a=o();return(g,p)=>(h(),i("div",null,[l,e("p",null,[s("2092 words, ~11 minute read. "),e("span",{innerHTML:t(n)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),u]))}});export{b as __pageData,w as default}; diff --git a/assets/guide-to-incrementals_ludology_content_index.md.CIJoP_r0.lean.js b/assets/guide-to-incrementals_ludology_content_index.md.BFqVGpC-.lean.js similarity index 79% rename from assets/guide-to-incrementals_ludology_content_index.md.CIJoP_r0.lean.js rename to assets/guide-to-incrementals_ludology_content_index.md.BFqVGpC-.lean.js index 6ad6d657..dc8aefc7 100644 --- a/assets/guide-to-incrementals_ludology_content_index.md.CIJoP_r0.lean.js +++ b/assets/guide-to-incrementals_ludology_content_index.md.BFqVGpC-.lean.js @@ -1 +1 @@ -import{d as n}from"./chunks/git.data.DG5NumsR.js";import{u as o,c as i,j as e,a as s,k as t,ag as r,o as h}from"./chunks/framework.VBE0TPts.js";const l=e("h1",{class:"p-name"},"Guide to Incrementals___What is Content?",-1),c=["innerHTML"],u=r("",25),b=JSON.parse('{"title":"Guide to Incrementals/What is Content?","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/what-is-content-","title":"Guide to Incrementals/What is Content?","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/ludology/content/index.md","filePath":"guide-to-incrementals/ludology/content/index.md"}'),m={name:"guide-to-incrementals/ludology/content/index.md"},w=Object.assign(m,{setup(d){const a=o();return(g,p)=>(h(),i("div",null,[l,e("p",null,[s("2092 words, ~11 minute read. "),e("span",{innerHTML:t(n)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),u]))}});export{b as __pageData,w as default}; +import{d as n}from"./chunks/git.data.DG5NumsR.js";import{M as o,q as i,Q as e,K as s,u as t,ag as r,p as h}from"./chunks/framework.DvHfxfnp.js";const l=e("h1",{class:"p-name"},"Guide to Incrementals___What is Content?",-1),c=["innerHTML"],u=r("",25),b=JSON.parse('{"title":"Guide to Incrementals/What is Content?","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/what-is-content-","title":"Guide to Incrementals/What is Content?","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/ludology/content/index.md","filePath":"guide-to-incrementals/ludology/content/index.md"}'),m={name:"guide-to-incrementals/ludology/content/index.md"},w=Object.assign(m,{setup(d){const a=o();return(g,p)=>(h(),i("div",null,[l,e("p",null,[s("2092 words, ~11 minute read. "),e("span",{innerHTML:t(n)[`site/${t(a).page.value.relativePath}`]},null,8,c)]),u]))}});export{b as __pageData,w as default}; diff --git a/assets/guide-to-incrementals_ludology_definition_index.md.CmTVBDoy.js b/assets/guide-to-incrementals_ludology_definition_index.md.NOaZSuDh.js similarity index 99% rename from assets/guide-to-incrementals_ludology_definition_index.md.CmTVBDoy.js rename to assets/guide-to-incrementals_ludology_definition_index.md.NOaZSuDh.js index 5c0a7b34..9dc7fed2 100644 --- a/assets/guide-to-incrementals_ludology_definition_index.md.CmTVBDoy.js +++ b/assets/guide-to-incrementals_ludology_definition_index.md.NOaZSuDh.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as o,j as e,a as i,k as t,ag as s,o as l}from"./chunks/framework.VBE0TPts.js";const h=e("h1",{class:"p-name"},"Guide to Incrementals___Defining the Genre",-1),m=["innerHTML"],g=s('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

Video games are placed into genres for a variety of reasons. They can give a mental shorthand to set the player's expectations up, they can help a game market itself by its similarities to other, already popular games, and honestly, people just love categorization for its own sake. For this guide, it's important to define the genre so it is clear what games it's even talking about.

This poses a problem. "Incremental" is a horribly vague way to define games. Most games have numbers going up in some form or another. We need a more specific definition - similar to how "strategy" can't just mean any game with any amount of strategy because that would be most games. What specifically differentiates incremental games from the rest?

"Incremental" implies it's a genre defined by a game mechanic, but all those game mechanics it could imply exist in many other games. Having a skill tree or upgrades doesn't make you incremental, and if a reset mechanic is all it takes then every roguelite would be an incremental as well. So clearly there's more to it than that - what makes an incremental an incremental?

I'd like to go over a couple of popular suggestions I've seen on defining the genre here. I have my personal preferences and will state them here, but I don't think there's a truly perfect answer here.

Disclaimer: I mostly play incremental games on my computer, and my definitions will be heavily biased towards the games I'm familiar with.

Incrementals vs Idlers vs Clickers

Oftentimes people refer to this genre as idle games and/or clicker games. You'll even find a trend of oxymoronic game titles that contain both terms. "Incremental games" is the umbrella term both those terms fall under. However, I'd like to argue that not only is it better to just use the term "incremental games", but calling them "idle games" or "clicker games" is wrong. Almost universally, these terms are used interchangeably to refer to the same kind of game, where you start the game click spamming and eventually automate the process. Frankly, that kind of game deserves neither title, and the genre of incremental games has trended away from ever requiring click spamming, as it's a bad mechanic, anyways.

While these games do span a spectrum of how active it requires you to be, and sorting games by that metric can be useful for those looking for a particular experience, the borders of when an incremental game counts as an "idler" is too blurry for the term to be useful. "Incremental games" may not be a great descriptive term for the genre (hence this many thousands of words long page on defining what the genre even is), but it's strictly better than calling them "idler" or "clicker" games. This guide will always use the term "incremental games" unless quoting someone else, as it is the term you typically see on all modern games in the genre.

Incrementals as Parodies

Let's start with one of the most interesting definitions of incremental games. Incremental games appear to be distilled versions of games or genres, "revealing" the naked game design at the core of these games or genres not unlike how parodies comment upon their source material.

To understand what that means, think of how a casino uses skinner boxes to emotionally manipulate its customers to keep playing, but "dressing" up the skinner box with tons of stimuli to hide that ultimately the goal is to condition you into coming back compulsively. The idea that incremental games are parodies means taking the stance that at some level all games are similarly manipulating you, giving dopamine rewards in a way that manipulates you to keep playing while not necessarily giving you any value or fulfillment. Incremental games, then, are any games that plainly display the skinner box, and the manipulative core of the game, at the forefront of the experience.

While incremental games can be fun and even healthy in certain contexts, they can exacerbate video game addiction more than other genres. If you feel like playing incremental games is taking priority over other things in your life, or manipulating your sleep schedule, it may be prudent to seek help. See r/StopGaming for resources.

This "undressing" tends to go hand in hand with a reduced focus on aesthetics, often just printing the game state directly to the screen as text. This makes incremental games much easier to develop, particularly for those with programming skills but not art skills, but that's a tangent for why Incremental Games Guide to Incrementals/Appeal to Developers.

Before I continue, I'd like to make my stance clear that I love games and incremental games, and do not think they should be considered inherently bad or manipulative with the above logic. Skinner boxes are just a way of manipulating behavior via rewards. The games are still fun - that's the reward! I'd believe the real criticism here is that it is "empty fun", or "empty dopamine", that doesn't offer any additional value or sense of fulfillment. I don't think that's inherently bad in moderation, although it can become a problem if the game is manipulating you for profit-seeking, or if you play the game to the detriment of the other parts of your life.

Another interpretation of incremental games as parodies comes from several mainstream incremental games that are also parodies of capitalism, such as cookie clicker and adventure capitalist. It's a very common framework for incremental games to portray the ever-increasing numbers as an insatiable hunger for resources, like the ones observed within capitalism. Therefore, these games are used as evidence that the genre as a whole is about parody and commentary.

Popular videos on incremental games that portray the genre as parodies are Why Idle games make good satire, and how it was ruined. and Bad Game Design - Clicker Games. You may also be interested in this response to the latter video from a fan of incremental games: BadGood Game Design - Clicker Games.

I think that this definition ultimately ascribes a motive to the genre as a whole that only happens to apply to some of the more mainstream titles. There certainly are incremental games commenting on different things, including the genre itself as in the case of The Prestige Tree Classic, The Ascension Tree, or Omega Layers, but certainly not all. And of course, not all games that comment on something or parody something are incremental games! Additionally, a very large majority of incremental games are mobile games using these manipulative strategies to get players to spend as much money as possible - hell, Adventure Capitalist is ostensibly a critique on capitalism but features microtransactions and gameplay that manipulates you into buying them! These profit-seeking incremental games certainly belong within the genre but are hardly parodies when they too use manipulation to serve their interests. Also, from my own anecdotal experience, those who use this definition seem to do so from a fairly surface-level familiarity with the genre, and often in the context of criticizing the genre or the fans thereof.

Incrementals as NGU

Another broad definition often used is that incremental games are games where the focus of the game is "numbers going up". This definition proposes that other genres simply use increasing numbers as a means to an end, but incremental games uniquely only care about the numbers themselves going up. Put another way, it implies there should be no narrative justification for the numbers going up other than "why shouldn't they be going up?"

While this definition is common because it feels easy to understand, it is difficult to formally define. Often phrases are used to describe games using this framework, such as having an "exaggerated sense of progression" or "big" numbers. These terms are vague and don't demonstrate an actual threshold between non-incrementals and incrementals. Most games have a sense of progression, so when is it "exaggerated"? How big are "big" numbers? Most notably, RPGs that are typically not considered incrementals will often pass this definition.

Additionally, a lot of incrementals tend to have some theme guiding the gameplay, or at least the names of mechanics. This makes the line blurred between when numbers are going up for their own sake versus for a contextual reason. I believe this point is best illustrated that, while most RPGs are not considered incremental games, there is a sub-genre of "incremental RPGs" that typically relates to RPGs that perform combat automatically. This definition of incremental games does not support RPGs and "incremental RPGs" being on distinct sides of the line if the only difference between them is manual vs automatic combat.

Incrementals as Strategies

This is a rarer interpretation, but there are similarities between incremental games and strategy games, implying incrementals might just be a sub-genre of strategy games. By this approach, incremental games would be defined by their relation to strategy games, and how they involve player strategy. Incremental games are often large optimization problems - above all else, the actual gameplay the player is performing is deciding what to do next. The consequences of wrong decisions are typically more lenient in incremental games - such as just not making optimal progress - but they certainly get complex.

So if we accept the premise that incrementals could fall under strategy, we still need to define what makes a strategy game an incremental versus some other strategy sub-genre. This is a bit tricky due to one particular sub-genre of strategy games: Factory Builders.

Factory builders, such as Factorio or Satisfactory, are games about gaining ever increasing resources, optimizing production, and expanding more and more. That... sounds pretty similar, doesn't it? In fact, there's been some debate on whether factory builders would fall under the "incremental" umbrella. I think it's safe to say the two are certainly related, and probably have quite a bit of overlap in playerbase.

Roguelites as Incrementals?

Earlier on, I mentioned reset mechanics shouldn't be used in the definition because that could make all roguelites incrementals... But what if it does? A lot of incrementals can be described as games with a strong sense of progression, often with layers of meta-progression. Roguelites fit that bill to a T. What would make roguelites not incremental? I honestly don't think there's a good explanation here, but many fans of incremental games will state they do believe the two genres to be unrelated, even if there's a significant overlap between their player bases due to having similar appealing traits.

At this point, it'd be appropriate to consider what part of the definition of roguelites precludes them from also being incrementals, but that reveals a new problem: What are roguelites? They're usually defined as rogue_likes with meta-progression, but that just pushes the problem back a step: Incrementals aren't the only genre to have difficulties defining themselves, it seems! Roguelikes are another genre where the community argues over the formal definition of their genre, although that means we can borrow from their process of coming to a consensus, and maybe come across a viable definition for incremental games.

The Berlin Interpretation

By far the most popular way of defining roguelikes is the "Berlin Interpretation", which acknowledged the diversity of games within the genre and argued the definition should not be based on any ideals about what the genre ought to be, but rather defined by "its canon". They argued there are a handful of games that can be used to define the canon for roguelikes, and from those games, a list of factors can be derived to determine a game's "roguelikeness". The more factors a game has, the more of a roguelike it is. This strategy is very lenient, allowing a game to not present any specific factor so long as it shows enough, and accounts for the blurriness of any genre definition by not explicitly stating how many factors a game must have to qualify as a definite roguelike.

I believe this strategy for defining genres can be applied to other genres as well. A handful of games can be argued to be the incremental games canon, and a list of factors derived from them can be used to judge any game based on its "incrementalness". I'll propose such a canon and list of factors here, but by no means should it be considered the end-all-be-all.

Note: The "Temple of the roguelike", an authority within the genre, has since replaced the Berlin Interpretation with a new set of factors here: https://blog.roguetemple.com/what-is-a-traditional-roguelike/

The Incremental Games Canon

Alright, time to get controversial. Up til now, I've been trying my best to stay objective and analytical, but now it's time to start making some opinionated decisions. Here is a list of games I think could justifiably make up an Incremental Games Canon:

I chose a variety of games here, biasing towards newer games, purposefully to avoid making a narrow or "traditional" definition. The genre is growing and shouldn't be constrained by the traits of the early popular titles. A lot of these could easily be replaced with other games that are mechanically congruent, so ultimately I'm sure if you asked 10 people for their canon list you'd just get 10 different answers, but I think this should sufficiently allow us to determine what factors make a game have higher "incrementalness".

The Paradigm Shift

The Paradigm Shift is probably the highest possible value factor for an incremental. It's so common that for a while people referred to incrementals that exhibit this trait as "unfolding" games, to the point of trying to replace the term incremental due to their popularity. Paradigm shifts refer to when the gameplay significantly changes. There are too many examples to list here, but notably, every single reset mechanic is typically going to be a paradigm shift. Examples of games with paradigm shifts that aren't tied to reset mechanics include Universal Paperclips and A Dark Room.

There are many reasons for the appeal of paradigm shifts. Oftentimes each mechanic builds on top of the existing mechanics, increasing the complexity of the game in steps so the player can follow along. They provide a sense of mystery, with the player anticipating what will happen next. They shake up the gameplay before it gets too stale - allowing the game to entertain for longer before the sense of Guide to Incrementals/What is Content? dissipates. Of the canon games selected above, I would argue every single one contains a paradigm shift (although I could see someone disagreeing with that statement wrt Increlution).

I should take a moment to say that while I'm hyping up this specific factor, we cannot just reduce the genre definition to "does it have paradigm shifts". Many games have paradigm shifts that are not incremental, so it's just an indicator of incrementalness. Additionally, it can become quite hard to determine how large of a shift is a "paradigm" shift. Take, for example, any game with a skill tree. In some games, each skill node might have a large impact on how you play with the game, and qualify as a paradigm shift for some players. In other games, each skill node might just be a small percentage modifier on some stat that doesn't really impact much more than a slight bias towards an already established mechanic that's newly buffed. Every single canon game may show that it's common amongst incremental games, but could just as easily indicate that they're common in games in general.

High-Value Factors

I won't take as long to discuss the high and low-value factors, as you've already seen most of them brought up earlier on this page. As a reminder, a game does NOT need all of these to be an incremental game, but these are factors that each indicate a strong possibility the game is an incremental, so having several of these means they probably are. These factors apply to most of the canon incremental games.

"Pure UI" Display. Incrementals typically have a textual presentation of the game state - there isn't a visual representation of the entities within the game. The interface is closer to what would be just the UI of a game in another genre or the control panel of a plane. If there is a visual representation, the player is often still interacting with non-diegetic game elements.

Reduced Consequences. Incrementals tend to have reduced repurcussions for misplaying. They very rarely have fail states, where often the largest consequence is simply not progressing - never losing progress.

Optimization Problems. The predominant gameplay of incrementals is typically solving optimization problems, from deciding which purchase to save up for to reasoning and deciding between different mutually exclusive options the game presents.

Resource Management. Incrementals tend to have a lot of resources within the game to keep track of.

Low-Value Factors

These are low-value factors, meaning they aren't as strongly correlated with incremental games. Incremental games may have none of these, and non-incrementals may have several of these - if a game only has low-value factors, they're probably not an incremental.

Fast Numeric Growth. Numbers in incremental games tend to grow faster than in other genres. There are more instances of superlinear growth. The larger the numbers get, the stronger of a signal this factor is.

Automation. As an incremental game progresses, the player often no longer has to deal with earlier mechanics, by having them either happen automatically or otherwise be replaced with an alternative that requires less player interaction.

Goal-Oriented. Incrementals are often heavily reliant on extrinsic motivation to guide the player. Typically this is through some sort of in-game goal to work towards, such as a certain amount of a resource being required to unlock or purchase something new.

Waiting is a Mechanic. In incremental games, the player may come across times where there is no action they can take, and the game will progress automatically instead. The player must wait for some amount of this automatic progress to occur before they can resume interaction with the game.

Are Roguelites Incrementals?

Having made our variation of the Berlin Interpretation for incremental games, we can compare it to the Berlin Interpretation to determine if there's enough overlap that any game that "passes" the Berlin Interpretation would also pass the incremental variant. That is to say, whether any roguelite would also be considered an incremental game.

The meta-progression of an incremental game could arguably be considered a paradigm shift, and certainly adds some resource management. Goal-oriented would probably also apply. I think anything other than those would be a stretch, and in my opinion that just isn't enough to qualify. To be totally honest, I was never expecting to conclude otherwise though 😉

Sub-Genres

There are some trends in incremental games that go beyond just being a commonly used mechanic, such that they deeply affect the rest of the game design. These trends can be used to determine sub-genres within the incremental games umbrella:

Loops games are a sub-genre defined by having a core mechanic related to a loop, where the player is deciding the actions taken per loop. Notable examples include Idle Loops, Stuck in Time, Cavernous II, and Increlution. You may also argue Groundhog Life and Progress Knight fall into this sub-genre.

ITRTG-like games are a sub-genre defined by having a core mechanic based on clearing increasingly difficult battles and often tend to have a lot of different mechanics to become progressively stronger. Notable examples include Idling to Rule the Gods, NGU Idle, and Wizard and Minion Idle.

Polynomial Growth games are a sub-genre defined by having a core mechanic related to a higher degree polynomial. Notable examples include the base layer of Antimatter Dimensions and Swarm Simulator.

Upgrades Games is a category popular on flash games websites that featured games focused on buying upgrades that would allow you to attain more currency in some sort of minigame that would earn you more money to buy more upgrades, which I'd argue now belong under the fold of incremental games. Notable examples include the Learn to Fly series and Upgrade Complete.

Cultivation RPGs are a genre of games, books, and anime popular in China that center around being in a fantasy world with characters getting stronger over time. While few of them get translated into English, a fan of incremental games may find the available games interesting.

',65),b=JSON.parse('{"title":"Guide to Incrementals/Defining the Genre","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/defining-the-genre","title":"Guide to Incrementals/Defining the Genre","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/ludology/definition/index.md","filePath":"guide-to-incrementals/ludology/definition/index.md"}'),c={name:"guide-to-incrementals/ludology/definition/index.md"},w=Object.assign(c,{setup(u){const a=n();return(d,p)=>(l(),o("div",null,[h,e("p",null,[i("3429 words, ~19 minute read. "),e("span",{innerHTML:t(r)[`site/${t(a).page.value.relativePath}`]},null,8,m)]),g]))}});export{b as __pageData,w as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as o,Q as e,K as i,u as t,ag as s,p as l}from"./chunks/framework.DvHfxfnp.js";const h=e("h1",{class:"p-name"},"Guide to Incrementals___Defining the Genre",-1),m=["innerHTML"],g=s('
Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

Video games are placed into genres for a variety of reasons. They can give a mental shorthand to set the player's expectations up, they can help a game market itself by its similarities to other, already popular games, and honestly, people just love categorization for its own sake. For this guide, it's important to define the genre so it is clear what games it's even talking about.

This poses a problem. "Incremental" is a horribly vague way to define games. Most games have numbers going up in some form or another. We need a more specific definition - similar to how "strategy" can't just mean any game with any amount of strategy because that would be most games. What specifically differentiates incremental games from the rest?

"Incremental" implies it's a genre defined by a game mechanic, but all those game mechanics it could imply exist in many other games. Having a skill tree or upgrades doesn't make you incremental, and if a reset mechanic is all it takes then every roguelite would be an incremental as well. So clearly there's more to it than that - what makes an incremental an incremental?

I'd like to go over a couple of popular suggestions I've seen on defining the genre here. I have my personal preferences and will state them here, but I don't think there's a truly perfect answer here.

Disclaimer: I mostly play incremental games on my computer, and my definitions will be heavily biased towards the games I'm familiar with.

Incrementals vs Idlers vs Clickers

Oftentimes people refer to this genre as idle games and/or clicker games. You'll even find a trend of oxymoronic game titles that contain both terms. "Incremental games" is the umbrella term both those terms fall under. However, I'd like to argue that not only is it better to just use the term "incremental games", but calling them "idle games" or "clicker games" is wrong. Almost universally, these terms are used interchangeably to refer to the same kind of game, where you start the game click spamming and eventually automate the process. Frankly, that kind of game deserves neither title, and the genre of incremental games has trended away from ever requiring click spamming, as it's a bad mechanic, anyways.

While these games do span a spectrum of how active it requires you to be, and sorting games by that metric can be useful for those looking for a particular experience, the borders of when an incremental game counts as an "idler" is too blurry for the term to be useful. "Incremental games" may not be a great descriptive term for the genre (hence this many thousands of words long page on defining what the genre even is), but it's strictly better than calling them "idler" or "clicker" games. This guide will always use the term "incremental games" unless quoting someone else, as it is the term you typically see on all modern games in the genre.

Incrementals as Parodies

Let's start with one of the most interesting definitions of incremental games. Incremental games appear to be distilled versions of games or genres, "revealing" the naked game design at the core of these games or genres not unlike how parodies comment upon their source material.

To understand what that means, think of how a casino uses skinner boxes to emotionally manipulate its customers to keep playing, but "dressing" up the skinner box with tons of stimuli to hide that ultimately the goal is to condition you into coming back compulsively. The idea that incremental games are parodies means taking the stance that at some level all games are similarly manipulating you, giving dopamine rewards in a way that manipulates you to keep playing while not necessarily giving you any value or fulfillment. Incremental games, then, are any games that plainly display the skinner box, and the manipulative core of the game, at the forefront of the experience.

While incremental games can be fun and even healthy in certain contexts, they can exacerbate video game addiction more than other genres. If you feel like playing incremental games is taking priority over other things in your life, or manipulating your sleep schedule, it may be prudent to seek help. See r/StopGaming for resources.

This "undressing" tends to go hand in hand with a reduced focus on aesthetics, often just printing the game state directly to the screen as text. This makes incremental games much easier to develop, particularly for those with programming skills but not art skills, but that's a tangent for why Incremental Games Guide to Incrementals/Appeal to Developers.

Before I continue, I'd like to make my stance clear that I love games and incremental games, and do not think they should be considered inherently bad or manipulative with the above logic. Skinner boxes are just a way of manipulating behavior via rewards. The games are still fun - that's the reward! I'd believe the real criticism here is that it is "empty fun", or "empty dopamine", that doesn't offer any additional value or sense of fulfillment. I don't think that's inherently bad in moderation, although it can become a problem if the game is manipulating you for profit-seeking, or if you play the game to the detriment of the other parts of your life.

Another interpretation of incremental games as parodies comes from several mainstream incremental games that are also parodies of capitalism, such as cookie clicker and adventure capitalist. It's a very common framework for incremental games to portray the ever-increasing numbers as an insatiable hunger for resources, like the ones observed within capitalism. Therefore, these games are used as evidence that the genre as a whole is about parody and commentary.

Popular videos on incremental games that portray the genre as parodies are Why Idle games make good satire, and how it was ruined. and Bad Game Design - Clicker Games. You may also be interested in this response to the latter video from a fan of incremental games: BadGood Game Design - Clicker Games.

I think that this definition ultimately ascribes a motive to the genre as a whole that only happens to apply to some of the more mainstream titles. There certainly are incremental games commenting on different things, including the genre itself as in the case of The Prestige Tree Classic, The Ascension Tree, or Omega Layers, but certainly not all. And of course, not all games that comment on something or parody something are incremental games! Additionally, a very large majority of incremental games are mobile games using these manipulative strategies to get players to spend as much money as possible - hell, Adventure Capitalist is ostensibly a critique on capitalism but features microtransactions and gameplay that manipulates you into buying them! These profit-seeking incremental games certainly belong within the genre but are hardly parodies when they too use manipulation to serve their interests. Also, from my own anecdotal experience, those who use this definition seem to do so from a fairly surface-level familiarity with the genre, and often in the context of criticizing the genre or the fans thereof.

Incrementals as NGU

Another broad definition often used is that incremental games are games where the focus of the game is "numbers going up". This definition proposes that other genres simply use increasing numbers as a means to an end, but incremental games uniquely only care about the numbers themselves going up. Put another way, it implies there should be no narrative justification for the numbers going up other than "why shouldn't they be going up?"

While this definition is common because it feels easy to understand, it is difficult to formally define. Often phrases are used to describe games using this framework, such as having an "exaggerated sense of progression" or "big" numbers. These terms are vague and don't demonstrate an actual threshold between non-incrementals and incrementals. Most games have a sense of progression, so when is it "exaggerated"? How big are "big" numbers? Most notably, RPGs that are typically not considered incrementals will often pass this definition.

Additionally, a lot of incrementals tend to have some theme guiding the gameplay, or at least the names of mechanics. This makes the line blurred between when numbers are going up for their own sake versus for a contextual reason. I believe this point is best illustrated that, while most RPGs are not considered incremental games, there is a sub-genre of "incremental RPGs" that typically relates to RPGs that perform combat automatically. This definition of incremental games does not support RPGs and "incremental RPGs" being on distinct sides of the line if the only difference between them is manual vs automatic combat.

Incrementals as Strategies

This is a rarer interpretation, but there are similarities between incremental games and strategy games, implying incrementals might just be a sub-genre of strategy games. By this approach, incremental games would be defined by their relation to strategy games, and how they involve player strategy. Incremental games are often large optimization problems - above all else, the actual gameplay the player is performing is deciding what to do next. The consequences of wrong decisions are typically more lenient in incremental games - such as just not making optimal progress - but they certainly get complex.

So if we accept the premise that incrementals could fall under strategy, we still need to define what makes a strategy game an incremental versus some other strategy sub-genre. This is a bit tricky due to one particular sub-genre of strategy games: Factory Builders.

Factory builders, such as Factorio or Satisfactory, are games about gaining ever increasing resources, optimizing production, and expanding more and more. That... sounds pretty similar, doesn't it? In fact, there's been some debate on whether factory builders would fall under the "incremental" umbrella. I think it's safe to say the two are certainly related, and probably have quite a bit of overlap in playerbase.

Roguelites as Incrementals?

Earlier on, I mentioned reset mechanics shouldn't be used in the definition because that could make all roguelites incrementals... But what if it does? A lot of incrementals can be described as games with a strong sense of progression, often with layers of meta-progression. Roguelites fit that bill to a T. What would make roguelites not incremental? I honestly don't think there's a good explanation here, but many fans of incremental games will state they do believe the two genres to be unrelated, even if there's a significant overlap between their player bases due to having similar appealing traits.

At this point, it'd be appropriate to consider what part of the definition of roguelites precludes them from also being incrementals, but that reveals a new problem: What are roguelites? They're usually defined as rogue_likes with meta-progression, but that just pushes the problem back a step: Incrementals aren't the only genre to have difficulties defining themselves, it seems! Roguelikes are another genre where the community argues over the formal definition of their genre, although that means we can borrow from their process of coming to a consensus, and maybe come across a viable definition for incremental games.

The Berlin Interpretation

By far the most popular way of defining roguelikes is the "Berlin Interpretation", which acknowledged the diversity of games within the genre and argued the definition should not be based on any ideals about what the genre ought to be, but rather defined by "its canon". They argued there are a handful of games that can be used to define the canon for roguelikes, and from those games, a list of factors can be derived to determine a game's "roguelikeness". The more factors a game has, the more of a roguelike it is. This strategy is very lenient, allowing a game to not present any specific factor so long as it shows enough, and accounts for the blurriness of any genre definition by not explicitly stating how many factors a game must have to qualify as a definite roguelike.

I believe this strategy for defining genres can be applied to other genres as well. A handful of games can be argued to be the incremental games canon, and a list of factors derived from them can be used to judge any game based on its "incrementalness". I'll propose such a canon and list of factors here, but by no means should it be considered the end-all-be-all.

Note: The "Temple of the roguelike", an authority within the genre, has since replaced the Berlin Interpretation with a new set of factors here: https://blog.roguetemple.com/what-is-a-traditional-roguelike/

The Incremental Games Canon

Alright, time to get controversial. Up til now, I've been trying my best to stay objective and analytical, but now it's time to start making some opinionated decisions. Here is a list of games I think could justifiably make up an Incremental Games Canon:

I chose a variety of games here, biasing towards newer games, purposefully to avoid making a narrow or "traditional" definition. The genre is growing and shouldn't be constrained by the traits of the early popular titles. A lot of these could easily be replaced with other games that are mechanically congruent, so ultimately I'm sure if you asked 10 people for their canon list you'd just get 10 different answers, but I think this should sufficiently allow us to determine what factors make a game have higher "incrementalness".

The Paradigm Shift

The Paradigm Shift is probably the highest possible value factor for an incremental. It's so common that for a while people referred to incrementals that exhibit this trait as "unfolding" games, to the point of trying to replace the term incremental due to their popularity. Paradigm shifts refer to when the gameplay significantly changes. There are too many examples to list here, but notably, every single reset mechanic is typically going to be a paradigm shift. Examples of games with paradigm shifts that aren't tied to reset mechanics include Universal Paperclips and A Dark Room.

There are many reasons for the appeal of paradigm shifts. Oftentimes each mechanic builds on top of the existing mechanics, increasing the complexity of the game in steps so the player can follow along. They provide a sense of mystery, with the player anticipating what will happen next. They shake up the gameplay before it gets too stale - allowing the game to entertain for longer before the sense of Guide to Incrementals/What is Content? dissipates. Of the canon games selected above, I would argue every single one contains a paradigm shift (although I could see someone disagreeing with that statement wrt Increlution).

I should take a moment to say that while I'm hyping up this specific factor, we cannot just reduce the genre definition to "does it have paradigm shifts". Many games have paradigm shifts that are not incremental, so it's just an indicator of incrementalness. Additionally, it can become quite hard to determine how large of a shift is a "paradigm" shift. Take, for example, any game with a skill tree. In some games, each skill node might have a large impact on how you play with the game, and qualify as a paradigm shift for some players. In other games, each skill node might just be a small percentage modifier on some stat that doesn't really impact much more than a slight bias towards an already established mechanic that's newly buffed. Every single canon game may show that it's common amongst incremental games, but could just as easily indicate that they're common in games in general.

High-Value Factors

I won't take as long to discuss the high and low-value factors, as you've already seen most of them brought up earlier on this page. As a reminder, a game does NOT need all of these to be an incremental game, but these are factors that each indicate a strong possibility the game is an incremental, so having several of these means they probably are. These factors apply to most of the canon incremental games.

"Pure UI" Display. Incrementals typically have a textual presentation of the game state - there isn't a visual representation of the entities within the game. The interface is closer to what would be just the UI of a game in another genre or the control panel of a plane. If there is a visual representation, the player is often still interacting with non-diegetic game elements.

Reduced Consequences. Incrementals tend to have reduced repurcussions for misplaying. They very rarely have fail states, where often the largest consequence is simply not progressing - never losing progress.

Optimization Problems. The predominant gameplay of incrementals is typically solving optimization problems, from deciding which purchase to save up for to reasoning and deciding between different mutually exclusive options the game presents.

Resource Management. Incrementals tend to have a lot of resources within the game to keep track of.

Low-Value Factors

These are low-value factors, meaning they aren't as strongly correlated with incremental games. Incremental games may have none of these, and non-incrementals may have several of these - if a game only has low-value factors, they're probably not an incremental.

Fast Numeric Growth. Numbers in incremental games tend to grow faster than in other genres. There are more instances of superlinear growth. The larger the numbers get, the stronger of a signal this factor is.

Automation. As an incremental game progresses, the player often no longer has to deal with earlier mechanics, by having them either happen automatically or otherwise be replaced with an alternative that requires less player interaction.

Goal-Oriented. Incrementals are often heavily reliant on extrinsic motivation to guide the player. Typically this is through some sort of in-game goal to work towards, such as a certain amount of a resource being required to unlock or purchase something new.

Waiting is a Mechanic. In incremental games, the player may come across times where there is no action they can take, and the game will progress automatically instead. The player must wait for some amount of this automatic progress to occur before they can resume interaction with the game.

Are Roguelites Incrementals?

Having made our variation of the Berlin Interpretation for incremental games, we can compare it to the Berlin Interpretation to determine if there's enough overlap that any game that "passes" the Berlin Interpretation would also pass the incremental variant. That is to say, whether any roguelite would also be considered an incremental game.

The meta-progression of an incremental game could arguably be considered a paradigm shift, and certainly adds some resource management. Goal-oriented would probably also apply. I think anything other than those would be a stretch, and in my opinion that just isn't enough to qualify. To be totally honest, I was never expecting to conclude otherwise though 😉

Sub-Genres

There are some trends in incremental games that go beyond just being a commonly used mechanic, such that they deeply affect the rest of the game design. These trends can be used to determine sub-genres within the incremental games umbrella:

Loops games are a sub-genre defined by having a core mechanic related to a loop, where the player is deciding the actions taken per loop. Notable examples include Idle Loops, Stuck in Time, Cavernous II, and Increlution. You may also argue Groundhog Life and Progress Knight fall into this sub-genre.

ITRTG-like games are a sub-genre defined by having a core mechanic based on clearing increasingly difficult battles and often tend to have a lot of different mechanics to become progressively stronger. Notable examples include Idling to Rule the Gods, NGU Idle, and Wizard and Minion Idle.

Polynomial Growth games are a sub-genre defined by having a core mechanic related to a higher degree polynomial. Notable examples include the base layer of Antimatter Dimensions and Swarm Simulator.

Upgrades Games is a category popular on flash games websites that featured games focused on buying upgrades that would allow you to attain more currency in some sort of minigame that would earn you more money to buy more upgrades, which I'd argue now belong under the fold of incremental games. Notable examples include the Learn to Fly series and Upgrade Complete.

Cultivation RPGs are a genre of games, books, and anime popular in China that center around being in a fantasy world with characters getting stronger over time. While few of them get translated into English, a fan of incremental games may find the available games interesting.

',65),b=JSON.parse('{"title":"Guide to Incrementals/Defining the Genre","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/defining-the-genre","title":"Guide to Incrementals/Defining the Genre","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/ludology/definition/index.md","filePath":"guide-to-incrementals/ludology/definition/index.md"}'),c={name:"guide-to-incrementals/ludology/definition/index.md"},w=Object.assign(c,{setup(u){const a=n();return(d,p)=>(l(),o("div",null,[h,e("p",null,[i("3429 words, ~19 minute read. "),e("span",{innerHTML:t(r)[`site/${t(a).page.value.relativePath}`]},null,8,m)]),g]))}});export{b as __pageData,w as default}; diff --git a/assets/guide-to-incrementals_ludology_definition_index.md.CmTVBDoy.lean.js b/assets/guide-to-incrementals_ludology_definition_index.md.NOaZSuDh.lean.js similarity index 79% rename from assets/guide-to-incrementals_ludology_definition_index.md.CmTVBDoy.lean.js rename to assets/guide-to-incrementals_ludology_definition_index.md.NOaZSuDh.lean.js index 35acfd4a..81906ac0 100644 --- a/assets/guide-to-incrementals_ludology_definition_index.md.CmTVBDoy.lean.js +++ b/assets/guide-to-incrementals_ludology_definition_index.md.NOaZSuDh.lean.js @@ -1 +1 @@ -import{d as r}from"./chunks/git.data.DG5NumsR.js";import{u as n,c as o,j as e,a as i,k as t,ag as s,o as l}from"./chunks/framework.VBE0TPts.js";const h=e("h1",{class:"p-name"},"Guide to Incrementals___Defining the Genre",-1),m=["innerHTML"],g=s("",65),b=JSON.parse('{"title":"Guide to Incrementals/Defining the Genre","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/defining-the-genre","title":"Guide to Incrementals/Defining the Genre","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/ludology/definition/index.md","filePath":"guide-to-incrementals/ludology/definition/index.md"}'),c={name:"guide-to-incrementals/ludology/definition/index.md"},w=Object.assign(c,{setup(u){const a=n();return(d,p)=>(l(),o("div",null,[h,e("p",null,[i("3429 words, ~19 minute read. "),e("span",{innerHTML:t(r)[`site/${t(a).page.value.relativePath}`]},null,8,m)]),g]))}});export{b as __pageData,w as default}; +import{d as r}from"./chunks/git.data.DG5NumsR.js";import{M as n,q as o,Q as e,K as i,u as t,ag as s,p as l}from"./chunks/framework.DvHfxfnp.js";const h=e("h1",{class:"p-name"},"Guide to Incrementals___Defining the Genre",-1),m=["innerHTML"],g=s("",65),b=JSON.parse('{"title":"Guide to Incrementals/Defining the Genre","description":"","frontmatter":{"public":"true","slug":"guide-to-incrementals/defining-the-genre","title":"Guide to Incrementals/Defining the Genre","prev":false,"next":false},"headers":[],"relativePath":"guide-to-incrementals/ludology/definition/index.md","filePath":"guide-to-incrementals/ludology/definition/index.md"}'),c={name:"guide-to-incrementals/ludology/definition/index.md"},w=Object.assign(c,{setup(u){const a=n();return(d,p)=>(l(),o("div",null,[h,e("p",null,[i("3429 words, ~19 minute read. "),e("span",{innerHTML:t(r)[`site/${t(a).page.value.relativePath}`]},null,8,m)]),g]))}});export{b as __pageData,w as default}; diff --git a/assets/index.md.BanIo7zz.js b/assets/index.md.BanIo7zz.js deleted file mode 100644 index 66ea3ea7..00000000 --- a/assets/index.md.BanIo7zz.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as i,s as r,y as c,z as d,c as h,j as e,aA as u,P as p,o as _,p as m,l as f,a as o}from"./chunks/framework.VBE0TPts.js";const t=a=>(m("data-v-136be424"),a=a(),f(),a),g=t(()=>e("h1",{id:"hello",tabindex:"-1"},[o("Hello! "),e("a",{class:"header-anchor",href:"#hello","aria-label":'Permalink to "Hello!"'},"​")],-1)),v=t(()=>e("p",null,[o("I'm Anthony, or The Paper Pilot, and welcome to my "),e("a",{href:"/garden/digital-gardens/"},"digital garden"),o("!")],-1)),b={class:"hero-wrapper"},w=t(()=>e("div",{class:"hole"},null,-1)),x=t(()=>e("svg",null,[e("filter",{id:"displacementFilter"},[e("feTurbulence",{type:"turbulence",baseFrequency:"0.01",numOctaves:"5",result:"turbulence"}),e("feDisplacementMap",{in2:"turbulence",in:"SourceGraphic",scale:"100",xChannelSelector:"R",yChannelSelector:"G"})])],-1)),y=t(()=>e("p",null,"This is a public website collecting all my (public) thoughts and projects all in one place. There are a lot of pages here, that link to each other wiki-style. I suggest starting your browsing with one of the recommended pages that most closely align with your interests 😃.",-1)),H=JSON.parse('{"title":"Hello!","description":"","frontmatter":{"title":"Hello!","prev":false,"next":false},"headers":[],"relativePath":"index.md","filePath":"index.md"}'),S={name:"index.md"},I=Object.assign(S,{setup(a){const s=r(0);function l(n){s.value=n.pageX/window.innerWidth-.5}return c(()=>{window.addEventListener("mousemove",l)}),d(()=>{window.removeEventListener("mousemove",l)}),(n,P)=>(_(),h("div",null,[g,v,e("div",b,[w,e("img",{class:"hero",src:u,style:p(`--x-offset: ${s.value*20}%`)},null,4)]),x,y]))}}),T=i(I,[["__scopeId","data-v-136be424"]]);export{H as __pageData,T as default}; diff --git a/assets/index.md.BanIo7zz.lean.js b/assets/index.md.BanIo7zz.lean.js deleted file mode 100644 index 66ea3ea7..00000000 --- a/assets/index.md.BanIo7zz.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as i,s as r,y as c,z as d,c as h,j as e,aA as u,P as p,o as _,p as m,l as f,a as o}from"./chunks/framework.VBE0TPts.js";const t=a=>(m("data-v-136be424"),a=a(),f(),a),g=t(()=>e("h1",{id:"hello",tabindex:"-1"},[o("Hello! "),e("a",{class:"header-anchor",href:"#hello","aria-label":'Permalink to "Hello!"'},"​")],-1)),v=t(()=>e("p",null,[o("I'm Anthony, or The Paper Pilot, and welcome to my "),e("a",{href:"/garden/digital-gardens/"},"digital garden"),o("!")],-1)),b={class:"hero-wrapper"},w=t(()=>e("div",{class:"hole"},null,-1)),x=t(()=>e("svg",null,[e("filter",{id:"displacementFilter"},[e("feTurbulence",{type:"turbulence",baseFrequency:"0.01",numOctaves:"5",result:"turbulence"}),e("feDisplacementMap",{in2:"turbulence",in:"SourceGraphic",scale:"100",xChannelSelector:"R",yChannelSelector:"G"})])],-1)),y=t(()=>e("p",null,"This is a public website collecting all my (public) thoughts and projects all in one place. There are a lot of pages here, that link to each other wiki-style. I suggest starting your browsing with one of the recommended pages that most closely align with your interests 😃.",-1)),H=JSON.parse('{"title":"Hello!","description":"","frontmatter":{"title":"Hello!","prev":false,"next":false},"headers":[],"relativePath":"index.md","filePath":"index.md"}'),S={name:"index.md"},I=Object.assign(S,{setup(a){const s=r(0);function l(n){s.value=n.pageX/window.innerWidth-.5}return c(()=>{window.addEventListener("mousemove",l)}),d(()=>{window.removeEventListener("mousemove",l)}),(n,P)=>(_(),h("div",null,[g,v,e("div",b,[w,e("img",{class:"hero",src:u,style:p(`--x-offset: ${s.value*20}%`)},null,4)]),x,y]))}}),T=i(I,[["__scopeId","data-v-136be424"]]);export{H as __pageData,T as default}; diff --git a/assets/index.md.DTY4Urhb.js b/assets/index.md.DTY4Urhb.js new file mode 100644 index 00000000..7ec897bc --- /dev/null +++ b/assets/index.md.DTY4Urhb.js @@ -0,0 +1,55 @@ +import{k as M,C as n,p as h,q as y,I as o,E as r,u as e,F as b,_ as C,r as U,o as F,m as P,Q as s,aA as O,x as k,D as B,ae as I,R as $,S as A,K as m}from"./chunks/framework.DvHfxfnp.js";import{r as G,N as g,A as H,K as S,R as N,_ as V,V as R,n as w,t as E}from"./chunks/theme.Bb5kJd_v.js";const T=` +varying vec2 vUv; + +void main() { + vec4 modelPosition = modelMatrix * vec4(position, 1.0); + vec4 viewPosition = viewMatrix * modelPosition; + gl_Position = projectionMatrix * viewPosition; + vUv = uv / .8 - 0.1; +} +`,x=` +precision mediump float; +uniform vec3 uColor; +uniform float uTime; +uniform float uSeed; +uniform vec2 uMouse; +varying vec2 vUv; +`,L=M({__name:"Hole",setup(i){const{sizes:t}=G(),a={uColor:{value:new R(.23,.26,.32)},uSeed:{value:Math.random()*100}},l=` +${w} +${x} + +vec4 getColor(vec2 pos) { + float dst = distance(pos, vec2(0.5, 0.5)); + if (dst < 0.475) { + return vec4(uColor, 1.); + } else if (dst < 0.5) { + return vec4(.83, .83, .83, 1.); + } + return vec4(0.); +} + +void main() { + vec2 distortion = vec2(0., 0.); + distortion.x += (snoise(vec3(vUv * 50., 0. + uSeed))) / 200.; + distortion.y += (snoise(vec3(vUv * 50., 10. + uSeed))) / 200.; + distortion.x += (snoise(vec3(vUv * 5., 20. + uSeed))) / 8.; + distortion.y += (snoise(vec3(vUv * 5., 30. + uSeed))) / 8.; + gl_FragColor = getColor(vUv + distortion); +} +`,p=` +${w} +${x} +void main() { + vec2 distortion = vec2(0., 0.); + distortion.x += (snoise(vec3(vUv * 50., 0. + uSeed))) / 200.; + distortion.y += (snoise(vec3(vUv * 50., 10. + uSeed))) / 200.; + distortion.x += (snoise(vec3(vUv * 5., 20. + uSeed))) / 8.; + distortion.y += (snoise(vec3(vUv * 5., 30. + uSeed))) / 8.; + float dst = distance(vUv + distortion, vec2(0.5, 0.5)); + if (dst < 0.475) { + gl_FragColor = vec4(1.); + return; + } + discard; +} +`;return(_,f)=>{const c=n("TresCircleGeometry"),d=n("TresShaderMaterial"),u=n("TresMesh");return h(),y(b,null,[o(u,{position:[Math.min(e(t).width.value,e(t).height.value)/2*.05,Math.min(e(t).width.value,e(t).height.value)/2*.05,0]},{default:r(()=>[o(c,{args:[Math.min(e(t).width.value,e(t).height.value)/2*.9,360]},null,8,["args"]),o(d,{vertexShader:T,fragmentShader:l,uniforms:a,blending:e(g),transparent:!0},null,8,["blending"])]),_:1},8,["position"]),o(u,{position:[Math.min(e(t).width.value,e(t).height.value)/2*.05,Math.min(e(t).width.value,e(t).height.value)/2*.05,0],renderOrder:0},{default:r(()=>[o(c,{args:[Math.min(e(t).width.value,e(t).height.value)/2*.9,360]},null,8,["args"]),o(d,{vertexShader:T,fragmentShader:p,uniforms:a,blending:e(g),colorWrite:!1,depthWrite:!1,depthTest:!1,stencilWrite:!0,stencilRef:1,stencilFunc:e(H),stencilFail:e(S),stencilZFail:e(S),stencilZPass:e(N)},null,8,["blending","stencilFunc","stencilFail","stencilZFail","stencilZPass"])]),_:1},8,["position"]),o(V,{mask:1})],64)}}}),v=i=>($("data-v-01cfbdb8"),i=i(),A(),i),W=v(()=>s("h1",{id:"hello",tabindex:"-1"},[m("Hello! "),s("a",{class:"header-anchor",href:"#hello","aria-label":'Permalink to "Hello!"'},"​")],-1)),Z=v(()=>s("p",null,[m("I'm Anthony, or The Paper Pilot, and welcome to my "),s("a",{href:"/garden/digital-gardens/"},"digital garden"),m("!")],-1)),j={class:"hero-wrapper"},D=v(()=>s("svg",null,[s("filter",{id:"displacementFilter"},[s("feTurbulence",{type:"turbulence",baseFrequency:"0.01",numOctaves:"5",result:"turbulence"}),s("feDisplacementMap",{in2:"turbulence",in:"SourceGraphic",scale:"100",xChannelSelector:"R",yChannelSelector:"G"})])],-1)),K=v(()=>s("p",null,"This is a public website collecting all my (public) thoughts and projects all in one place. There are a lot of pages here, that link to each other wiki-style. I suggest starting your browsing with one of the recommended pages that most closely align with your interests 😃.",-1)),X=JSON.parse('{"title":"Hello!","description":"","frontmatter":{"title":"Hello!","prev":false,"next":false},"headers":[],"relativePath":"index.md","filePath":"index.md"}'),q={name:"index.md"},z=Object.assign(q,{setup(i){const t=U(0);function a(l){t.value=l.pageX/window.innerWidth-.5}return F(()=>{window.addEventListener("mousemove",a)}),P(()=>{window.removeEventListener("mousemove",a)}),(l,p)=>{const _=n("TresOrthographicCamera"),f=n("TresAmbientLight"),c=n("TresTorusGeometry"),d=n("TresMeshBasicMaterial"),u=n("TresMesh");return h(),y("div",null,[W,Z,s("div",j,[o(e(E),{stencil:!0},{default:r(()=>[o(_,{position:[0,0,10]}),o(f,{intensity:1}),o(u,null,{default:r(()=>[o(c,{args:[1,.5,16,32]}),o(d,{color:"orange"})]),_:1}),(h(),B(I,null,{default:r(()=>[o(L)]),_:1}))]),_:1}),s("img",{class:"hero",src:O,style:k(`--x-offset: ${t.value*20}%`)},null,4)]),D,K])}}}),Y=C(z,[["__scopeId","data-v-01cfbdb8"]]);export{X as __pageData,Y as default}; diff --git a/assets/index.md.DTY4Urhb.lean.js b/assets/index.md.DTY4Urhb.lean.js new file mode 100644 index 00000000..7ec897bc --- /dev/null +++ b/assets/index.md.DTY4Urhb.lean.js @@ -0,0 +1,55 @@ +import{k as M,C as n,p as h,q as y,I as o,E as r,u as e,F as b,_ as C,r as U,o as F,m as P,Q as s,aA as O,x as k,D as B,ae as I,R as $,S as A,K as m}from"./chunks/framework.DvHfxfnp.js";import{r as G,N as g,A as H,K as S,R as N,_ as V,V as R,n as w,t as E}from"./chunks/theme.Bb5kJd_v.js";const T=` +varying vec2 vUv; + +void main() { + vec4 modelPosition = modelMatrix * vec4(position, 1.0); + vec4 viewPosition = viewMatrix * modelPosition; + gl_Position = projectionMatrix * viewPosition; + vUv = uv / .8 - 0.1; +} +`,x=` +precision mediump float; +uniform vec3 uColor; +uniform float uTime; +uniform float uSeed; +uniform vec2 uMouse; +varying vec2 vUv; +`,L=M({__name:"Hole",setup(i){const{sizes:t}=G(),a={uColor:{value:new R(.23,.26,.32)},uSeed:{value:Math.random()*100}},l=` +${w} +${x} + +vec4 getColor(vec2 pos) { + float dst = distance(pos, vec2(0.5, 0.5)); + if (dst < 0.475) { + return vec4(uColor, 1.); + } else if (dst < 0.5) { + return vec4(.83, .83, .83, 1.); + } + return vec4(0.); +} + +void main() { + vec2 distortion = vec2(0., 0.); + distortion.x += (snoise(vec3(vUv * 50., 0. + uSeed))) / 200.; + distortion.y += (snoise(vec3(vUv * 50., 10. + uSeed))) / 200.; + distortion.x += (snoise(vec3(vUv * 5., 20. + uSeed))) / 8.; + distortion.y += (snoise(vec3(vUv * 5., 30. + uSeed))) / 8.; + gl_FragColor = getColor(vUv + distortion); +} +`,p=` +${w} +${x} +void main() { + vec2 distortion = vec2(0., 0.); + distortion.x += (snoise(vec3(vUv * 50., 0. + uSeed))) / 200.; + distortion.y += (snoise(vec3(vUv * 50., 10. + uSeed))) / 200.; + distortion.x += (snoise(vec3(vUv * 5., 20. + uSeed))) / 8.; + distortion.y += (snoise(vec3(vUv * 5., 30. + uSeed))) / 8.; + float dst = distance(vUv + distortion, vec2(0.5, 0.5)); + if (dst < 0.475) { + gl_FragColor = vec4(1.); + return; + } + discard; +} +`;return(_,f)=>{const c=n("TresCircleGeometry"),d=n("TresShaderMaterial"),u=n("TresMesh");return h(),y(b,null,[o(u,{position:[Math.min(e(t).width.value,e(t).height.value)/2*.05,Math.min(e(t).width.value,e(t).height.value)/2*.05,0]},{default:r(()=>[o(c,{args:[Math.min(e(t).width.value,e(t).height.value)/2*.9,360]},null,8,["args"]),o(d,{vertexShader:T,fragmentShader:l,uniforms:a,blending:e(g),transparent:!0},null,8,["blending"])]),_:1},8,["position"]),o(u,{position:[Math.min(e(t).width.value,e(t).height.value)/2*.05,Math.min(e(t).width.value,e(t).height.value)/2*.05,0],renderOrder:0},{default:r(()=>[o(c,{args:[Math.min(e(t).width.value,e(t).height.value)/2*.9,360]},null,8,["args"]),o(d,{vertexShader:T,fragmentShader:p,uniforms:a,blending:e(g),colorWrite:!1,depthWrite:!1,depthTest:!1,stencilWrite:!0,stencilRef:1,stencilFunc:e(H),stencilFail:e(S),stencilZFail:e(S),stencilZPass:e(N)},null,8,["blending","stencilFunc","stencilFail","stencilZFail","stencilZPass"])]),_:1},8,["position"]),o(V,{mask:1})],64)}}}),v=i=>($("data-v-01cfbdb8"),i=i(),A(),i),W=v(()=>s("h1",{id:"hello",tabindex:"-1"},[m("Hello! "),s("a",{class:"header-anchor",href:"#hello","aria-label":'Permalink to "Hello!"'},"​")],-1)),Z=v(()=>s("p",null,[m("I'm Anthony, or The Paper Pilot, and welcome to my "),s("a",{href:"/garden/digital-gardens/"},"digital garden"),m("!")],-1)),j={class:"hero-wrapper"},D=v(()=>s("svg",null,[s("filter",{id:"displacementFilter"},[s("feTurbulence",{type:"turbulence",baseFrequency:"0.01",numOctaves:"5",result:"turbulence"}),s("feDisplacementMap",{in2:"turbulence",in:"SourceGraphic",scale:"100",xChannelSelector:"R",yChannelSelector:"G"})])],-1)),K=v(()=>s("p",null,"This is a public website collecting all my (public) thoughts and projects all in one place. There are a lot of pages here, that link to each other wiki-style. I suggest starting your browsing with one of the recommended pages that most closely align with your interests 😃.",-1)),X=JSON.parse('{"title":"Hello!","description":"","frontmatter":{"title":"Hello!","prev":false,"next":false},"headers":[],"relativePath":"index.md","filePath":"index.md"}'),q={name:"index.md"},z=Object.assign(q,{setup(i){const t=U(0);function a(l){t.value=l.pageX/window.innerWidth-.5}return F(()=>{window.addEventListener("mousemove",a)}),P(()=>{window.removeEventListener("mousemove",a)}),(l,p)=>{const _=n("TresOrthographicCamera"),f=n("TresAmbientLight"),c=n("TresTorusGeometry"),d=n("TresMeshBasicMaterial"),u=n("TresMesh");return h(),y("div",null,[W,Z,s("div",j,[o(e(E),{stencil:!0},{default:r(()=>[o(_,{position:[0,0,10]}),o(f,{intensity:1}),o(u,null,{default:r(()=>[o(c,{args:[1,.5,16,32]}),o(d,{color:"orange"})]),_:1}),(h(),B(I,null,{default:r(()=>[o(L)]),_:1}))]),_:1}),s("img",{class:"hero",src:O,style:k(`--x-offset: ${t.value*20}%`)},null,4)]),D,K])}}}),Y=C(z,[["__scopeId","data-v-01cfbdb8"]]);export{X as __pageData,Y as default}; diff --git a/assets/now_index.md.CdesjOn4.js b/assets/now_index.md.BMPjLpxb.js similarity index 93% rename from assets/now_index.md.CdesjOn4.js rename to assets/now_index.md.BMPjLpxb.js index 3f58a896..ef2a0c3c 100644 --- a/assets/now_index.md.CdesjOn4.js +++ b/assets/now_index.md.BMPjLpxb.js @@ -1 +1 @@ -import{d as o}from"./chunks/git.data.DG5NumsR.js";import{u as t,c as i,j as e,a as r,k as a,ag as l,o as s}from"./chunks/framework.VBE0TPts.js";const c=e("h1",{class:"p-name"},"/now",-1),m=["innerHTML"],h=l('

This "now page" offers a big picture glimpse into what I’m focused on at this point in my life. What is a now page?

IndieWeb

I've been learning a lot about The Small Web (or the various other names it goes by). I've been working on this website and implementing the various IndieWeb building blocks

I'm also working on a proposal for adding The IndieWeb/Signature Blocks to your notes

Commune

While I'm not contributing to the project directly, I'm following along and participating with the discussions and designs of Commune.

I'm working on a mockup of what an app could look like that treats incoming messages, emails, etc. differently based on user defined rules, with a focus on moving them into personal or communal digital gardens.

Incremental Social

I'm running and improving the social media site Incremental Social, along with CardboardEmpress.

Chromatic Lattice

I'm working on a multiplayer incremental game. That's all that's known publicly for now 😜.

Kronos

I'm working on a long single player narratively driven incremental game. This is a very long-term project.

',14),w=JSON.parse('{"title":"/now","description":"","frontmatter":{"public":"true","slug":"now","title":"/now","prev":false,"next":false},"headers":[],"relativePath":"now/index.md","filePath":"now/index.md"}'),d={name:"now/index.md"},_=Object.assign(d,{setup(p){const n=t();return(u,g)=>(s(),i("div",null,[c,e("p",null,[r("181 words, ~1 minute read. "),e("span",{innerHTML:a(o)[`site/${a(n).page.value.relativePath}`]},null,8,m)]),h]))}});export{w as __pageData,_ as default}; +import{d as o}from"./chunks/git.data.DG5NumsR.js";import{M as t,q as i,Q as e,K as r,u as a,ag as l,p as s}from"./chunks/framework.DvHfxfnp.js";const c=e("h1",{class:"p-name"},"/now",-1),m=["innerHTML"],h=l('

This "now page" offers a big picture glimpse into what I’m focused on at this point in my life. What is a now page?

IndieWeb

I've been learning a lot about The Small Web (or the various other names it goes by). I've been working on this website and implementing the various IndieWeb building blocks

I'm also working on a proposal for adding The IndieWeb/Signature Blocks to your notes

Commune

While I'm not contributing to the project directly, I'm following along and participating with the discussions and designs of Commune.

I'm working on a mockup of what an app could look like that treats incoming messages, emails, etc. differently based on user defined rules, with a focus on moving them into personal or communal digital gardens.

Incremental Social

I'm running and improving the social media site Incremental Social, along with CardboardEmpress.

Chromatic Lattice

I'm working on a multiplayer incremental game. That's all that's known publicly for now 😜.

Kronos

I'm working on a long single player narratively driven incremental game. This is a very long-term project.

',14),w=JSON.parse('{"title":"/now","description":"","frontmatter":{"public":"true","slug":"now","title":"/now","prev":false,"next":false},"headers":[],"relativePath":"now/index.md","filePath":"now/index.md"}'),d={name:"now/index.md"},_=Object.assign(d,{setup(p){const n=t();return(u,g)=>(s(),i("div",null,[c,e("p",null,[r("181 words, ~1 minute read. "),e("span",{innerHTML:a(o)[`site/${a(n).page.value.relativePath}`]},null,8,m)]),h]))}});export{w as __pageData,_ as default}; diff --git a/assets/now_index.md.CdesjOn4.lean.js b/assets/now_index.md.BMPjLpxb.lean.js similarity index 72% rename from assets/now_index.md.CdesjOn4.lean.js rename to assets/now_index.md.BMPjLpxb.lean.js index fb56b169..9c6b06c7 100644 --- a/assets/now_index.md.CdesjOn4.lean.js +++ b/assets/now_index.md.BMPjLpxb.lean.js @@ -1 +1 @@ -import{d as o}from"./chunks/git.data.DG5NumsR.js";import{u as t,c as i,j as e,a as r,k as a,ag as l,o as s}from"./chunks/framework.VBE0TPts.js";const c=e("h1",{class:"p-name"},"/now",-1),m=["innerHTML"],h=l("",14),w=JSON.parse('{"title":"/now","description":"","frontmatter":{"public":"true","slug":"now","title":"/now","prev":false,"next":false},"headers":[],"relativePath":"now/index.md","filePath":"now/index.md"}'),d={name:"now/index.md"},_=Object.assign(d,{setup(p){const n=t();return(u,g)=>(s(),i("div",null,[c,e("p",null,[r("181 words, ~1 minute read. "),e("span",{innerHTML:a(o)[`site/${a(n).page.value.relativePath}`]},null,8,m)]),h]))}});export{w as __pageData,_ as default}; +import{d as o}from"./chunks/git.data.DG5NumsR.js";import{M as t,q as i,Q as e,K as r,u as a,ag as l,p as s}from"./chunks/framework.DvHfxfnp.js";const c=e("h1",{class:"p-name"},"/now",-1),m=["innerHTML"],h=l("",14),w=JSON.parse('{"title":"/now","description":"","frontmatter":{"public":"true","slug":"now","title":"/now","prev":false,"next":false},"headers":[],"relativePath":"now/index.md","filePath":"now/index.md"}'),d={name:"now/index.md"},_=Object.assign(d,{setup(p){const n=t();return(u,g)=>(s(),i("div",null,[c,e("p",null,[r("181 words, ~1 minute read. "),e("span",{innerHTML:a(o)[`site/${a(n).page.value.relativePath}`]},null,8,m)]),h]))}});export{w as __pageData,_ as default}; diff --git a/assets/public_gamedevtree_2.0-format-changes.md.DWZ5VgEH.js b/assets/public_gamedevtree_2.0-format-changes.md.DRd3bhvM.js similarity index 82% rename from assets/public_gamedevtree_2.0-format-changes.md.DWZ5VgEH.js rename to assets/public_gamedevtree_2.0-format-changes.md.DRd3bhvM.js index 993235a6..b0cb372b 100644 --- a/assets/public_gamedevtree_2.0-format-changes.md.DWZ5VgEH.js +++ b/assets/public_gamedevtree_2.0-format-changes.md.DRd3bhvM.js @@ -1 +1 @@ -import{_ as e,c as a,o as t,ag as o}from"./chunks/framework.VBE0TPts.js";const p=JSON.parse('{"title":"2.0 format changes","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/2.0-format-changes.md","filePath":"public/gamedevtree/2.0-format-changes.md"}'),i={name:"public/gamedevtree/2.0-format-changes.md"},n=o('

2.0 format changes

  • Temp format is changed from temp.something[layer] to temp[layer].something, for consistency
  • Challenges are now saved as an object with the amount of completions in each spot. (This will break saves.)
  • effectDisplay in Challenges and Upgrades no longer takes an argument, and neither does effect for Buyables
  • Buyable cost can take an argument for amount of buyables, but it needs to function if no argument is supplied (it should do the cost for the next purchase).
  • Generation of Points now happens in the main game loop (not in a layer update function), enabled by canGenPoints in game.js.
  • Changed fullLayerReset to layerDataReset, which takes an array of names of values to keep

In addition, many names were changed, mostly expanding abbreviations:

All instances of:

  • chall -> challenge
  • unl -> unlocked
  • upg -> upgrade (besides CSS)
  • amt -> amount
  • desc -> description
  • resCeil -> roundUpCost
  • order -> unlockOrder
  • incr_order -> increaseUnlockOrder

Challenges:

  • desc -> challengeDescription
  • reward -> rewardDescription
  • effect -> rewardEffect
  • effectDisplay -> rewardDisplay
  • active -> challengeActive
',7),l=[n];function s(r,c,d,g,h,m){return t(),a("div",null,l)}const u=e(i,[["render",s]]);export{p as __pageData,u as default}; +import{_ as e,q as a,p as t,ag as i}from"./chunks/framework.DvHfxfnp.js";const f=JSON.parse('{"title":"2.0 format changes","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/2.0-format-changes.md","filePath":"public/gamedevtree/2.0-format-changes.md"}'),o={name:"public/gamedevtree/2.0-format-changes.md"},n=i('

2.0 format changes

  • Temp format is changed from temp.something[layer] to temp[layer].something, for consistency
  • Challenges are now saved as an object with the amount of completions in each spot. (This will break saves.)
  • effectDisplay in Challenges and Upgrades no longer takes an argument, and neither does effect for Buyables
  • Buyable cost can take an argument for amount of buyables, but it needs to function if no argument is supplied (it should do the cost for the next purchase).
  • Generation of Points now happens in the main game loop (not in a layer update function), enabled by canGenPoints in game.js.
  • Changed fullLayerReset to layerDataReset, which takes an array of names of values to keep

In addition, many names were changed, mostly expanding abbreviations:

All instances of:

  • chall -> challenge
  • unl -> unlocked
  • upg -> upgrade (besides CSS)
  • amt -> amount
  • desc -> description
  • resCeil -> roundUpCost
  • order -> unlockOrder
  • incr_order -> increaseUnlockOrder

Challenges:

  • desc -> challengeDescription
  • reward -> rewardDescription
  • effect -> rewardEffect
  • effectDisplay -> rewardDisplay
  • active -> challengeActive
',7),l=[n];function s(r,c,d,g,h,m){return t(),a("div",null,l)}const u=e(o,[["render",s]]);export{f as __pageData,u as default}; diff --git a/assets/public_gamedevtree_2.0-format-changes.md.DRd3bhvM.lean.js b/assets/public_gamedevtree_2.0-format-changes.md.DRd3bhvM.lean.js new file mode 100644 index 00000000..d39e6eb9 --- /dev/null +++ b/assets/public_gamedevtree_2.0-format-changes.md.DRd3bhvM.lean.js @@ -0,0 +1 @@ +import{_ as e,q as a,p as t,ag as i}from"./chunks/framework.DvHfxfnp.js";const f=JSON.parse('{"title":"2.0 format changes","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/2.0-format-changes.md","filePath":"public/gamedevtree/2.0-format-changes.md"}'),o={name:"public/gamedevtree/2.0-format-changes.md"},n=i("",7),l=[n];function s(r,c,d,g,h,m){return t(),a("div",null,l)}const u=e(o,[["render",s]]);export{f as __pageData,u as default}; diff --git a/assets/public_gamedevtree_2.0-format-changes.md.DWZ5VgEH.lean.js b/assets/public_gamedevtree_2.0-format-changes.md.DWZ5VgEH.lean.js deleted file mode 100644 index e1e77fa7..00000000 --- a/assets/public_gamedevtree_2.0-format-changes.md.DWZ5VgEH.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as e,c as a,o as t,ag as o}from"./chunks/framework.VBE0TPts.js";const p=JSON.parse('{"title":"2.0 format changes","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/2.0-format-changes.md","filePath":"public/gamedevtree/2.0-format-changes.md"}'),i={name:"public/gamedevtree/2.0-format-changes.md"},n=o("",7),l=[n];function s(r,c,d,g,h,m){return t(),a("div",null,l)}const u=e(i,[["render",s]]);export{p as __pageData,u as default}; diff --git a/assets/public_gamedevtree_README.md.B6IoVQ-I.js b/assets/public_gamedevtree_README.md.DVS2_5Qr.js similarity index 83% rename from assets/public_gamedevtree_README.md.B6IoVQ-I.js rename to assets/public_gamedevtree_README.md.DVS2_5Qr.js index 3f920343..88aca9cd 100644 --- a/assets/public_gamedevtree_README.md.B6IoVQ-I.js +++ b/assets/public_gamedevtree_README.md.DVS2_5Qr.js @@ -1 +1 @@ -import{_ as o,c as a,o as r,j as e,a as t}from"./chunks/framework.VBE0TPts.js";const k=JSON.parse('{"title":"The-Modding-Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/README.md","filePath":"public/gamedevtree/README.md"}'),i={name:"public/gamedevtree/README.md"},n=e("h1",{id:"the-modding-tree",tabindex:"-1"},[t("The-Modding-Tree "),e("a",{class:"header-anchor",href:"#the-modding-tree","aria-label":'Permalink to "The-Modding-Tree"'},"​")],-1),s=e("p",null,"A modified version of The Prestige Tree that is much easier to mod. It still requires programming knowledge, but it's mostly pretty easy things and copy/pasting.",-1),d=e("p",null,[e("a",{href:"./docs/getting-started"},"Look here for a tutorial on getting started with modding with TMT")],-1),l=e("p",null,[t("You can look in the "),e("a",{href:"./docs/!general-info"},"documentation"),t(" for more information on how it all works, or look at the code in layers.js to see what it all looks like.")],-1),c=[n,s,d,l];function h(m,g,p,_,f,u){return r(),a("div",null,c)}const E=o(i,[["render",h]]);export{k as __pageData,E as default}; +import{_ as o,q as a,p as r,Q as e,K as t}from"./chunks/framework.DvHfxfnp.js";const k=JSON.parse('{"title":"The-Modding-Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/README.md","filePath":"public/gamedevtree/README.md"}'),i={name:"public/gamedevtree/README.md"},n=e("h1",{id:"the-modding-tree",tabindex:"-1"},[t("The-Modding-Tree "),e("a",{class:"header-anchor",href:"#the-modding-tree","aria-label":'Permalink to "The-Modding-Tree"'},"​")],-1),s=e("p",null,"A modified version of The Prestige Tree that is much easier to mod. It still requires programming knowledge, but it's mostly pretty easy things and copy/pasting.",-1),d=e("p",null,[e("a",{href:"./docs/getting-started"},"Look here for a tutorial on getting started with modding with TMT")],-1),l=e("p",null,[t("You can look in the "),e("a",{href:"./docs/!general-info"},"documentation"),t(" for more information on how it all works, or look at the code in layers.js to see what it all looks like.")],-1),c=[n,s,d,l];function h(m,p,g,_,f,u){return r(),a("div",null,c)}const E=o(i,[["render",h]]);export{k as __pageData,E as default}; diff --git a/assets/public_gamedevtree_README.md.B6IoVQ-I.lean.js b/assets/public_gamedevtree_README.md.DVS2_5Qr.lean.js similarity index 83% rename from assets/public_gamedevtree_README.md.B6IoVQ-I.lean.js rename to assets/public_gamedevtree_README.md.DVS2_5Qr.lean.js index 3f920343..88aca9cd 100644 --- a/assets/public_gamedevtree_README.md.B6IoVQ-I.lean.js +++ b/assets/public_gamedevtree_README.md.DVS2_5Qr.lean.js @@ -1 +1 @@ -import{_ as o,c as a,o as r,j as e,a as t}from"./chunks/framework.VBE0TPts.js";const k=JSON.parse('{"title":"The-Modding-Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/README.md","filePath":"public/gamedevtree/README.md"}'),i={name:"public/gamedevtree/README.md"},n=e("h1",{id:"the-modding-tree",tabindex:"-1"},[t("The-Modding-Tree "),e("a",{class:"header-anchor",href:"#the-modding-tree","aria-label":'Permalink to "The-Modding-Tree"'},"​")],-1),s=e("p",null,"A modified version of The Prestige Tree that is much easier to mod. It still requires programming knowledge, but it's mostly pretty easy things and copy/pasting.",-1),d=e("p",null,[e("a",{href:"./docs/getting-started"},"Look here for a tutorial on getting started with modding with TMT")],-1),l=e("p",null,[t("You can look in the "),e("a",{href:"./docs/!general-info"},"documentation"),t(" for more information on how it all works, or look at the code in layers.js to see what it all looks like.")],-1),c=[n,s,d,l];function h(m,g,p,_,f,u){return r(),a("div",null,c)}const E=o(i,[["render",h]]);export{k as __pageData,E as default}; +import{_ as o,q as a,p as r,Q as e,K as t}from"./chunks/framework.DvHfxfnp.js";const k=JSON.parse('{"title":"The-Modding-Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/README.md","filePath":"public/gamedevtree/README.md"}'),i={name:"public/gamedevtree/README.md"},n=e("h1",{id:"the-modding-tree",tabindex:"-1"},[t("The-Modding-Tree "),e("a",{class:"header-anchor",href:"#the-modding-tree","aria-label":'Permalink to "The-Modding-Tree"'},"​")],-1),s=e("p",null,"A modified version of The Prestige Tree that is much easier to mod. It still requires programming knowledge, but it's mostly pretty easy things and copy/pasting.",-1),d=e("p",null,[e("a",{href:"./docs/getting-started"},"Look here for a tutorial on getting started with modding with TMT")],-1),l=e("p",null,[t("You can look in the "),e("a",{href:"./docs/!general-info"},"documentation"),t(" for more information on how it all works, or look at the code in layers.js to see what it all looks like.")],-1),c=[n,s,d,l];function h(m,p,g,_,f,u){return r(),a("div",null,c)}const E=o(i,[["render",h]]);export{k as __pageData,E as default}; diff --git a/assets/public_gamedevtree_changelog.md.BFpQdU6f.js b/assets/public_gamedevtree_changelog.md.Bp63oq83.js similarity index 97% rename from assets/public_gamedevtree_changelog.md.BFpQdU6f.js rename to assets/public_gamedevtree_changelog.md.Bp63oq83.js index b79ced07..ac612d15 100644 --- a/assets/public_gamedevtree_changelog.md.BFpQdU6f.js +++ b/assets/public_gamedevtree_changelog.md.Bp63oq83.js @@ -1 +1 @@ -import{_ as e,c as a,o as l,ag as i}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"The Game Dev Tree changelog:","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/changelog.md","filePath":"public/gamedevtree/changelog.md"}'),r={name:"public/gamedevtree/changelog.md"},o=i('

The Game Dev Tree changelog:

v1.0.4 Version Bump [rebalanced,debuggedx3] - 2020-11-09

  • Fixed refactorings 2, 3, and 4 not actually affecting productivity

v1.0.3 Version Bump [rebalanced,debuggedx2] - 2020-11-08

  • Fixed API milestone 4 not working

v1.0.2 Version Bump [rebalanced,debugged] - 2020-11-08

  • Fixed tree lines being hidden after hitting "keepGoing" in the victory screen

v1.0.1 Version Bump [rebalanced] - 2020-11-08

  • Buffed several TAs

v1.0 Version Bump - 2020-11-08

  • Finished row 4
  • Added colored text to lore
  • Fixed some visual bugs with milestones
  • Probably other stuff lol its been a week

v0.2.3 Stylish - 2020-10-30

  • Re-styled basically everything
  • Added favicon
  • Added header bar
  • Added changelog

v0.2.2 Row 3 - 2020-10-22

  • Removed debug statement
  • Moved milestones in F layer beneath the buyables

v0.2.1 Row 3 - 2020-10-21

  • Fixed layers hiding
  • Fixed typos/minor issues
  • Fixed S layer being highlighted before you can unlock the layer

v0.2 Row 3 - 2020-10-21

  • Implemented row 3

v0.1.1 Cash Influx [rebalanced] - 2020-10-19

  • Fixed notification issue
  • Rebalanced to make early game faster and late game slower
  • Fixed other minor issues

v0.1 Cash Influx - 2020-10-19

  • Implemented row 2

v0.0 Initial Commit - 2020-10-18

  • Implemented row 1
',25),n=[o];function t(d,h,s,u,c,b){return l(),a("div",null,n)}const g=e(r,[["render",t]]);export{m as __pageData,g as default}; +import{_ as e,q as a,p as l,ag as i}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"The Game Dev Tree changelog:","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/changelog.md","filePath":"public/gamedevtree/changelog.md"}'),r={name:"public/gamedevtree/changelog.md"},o=i('

The Game Dev Tree changelog:

v1.0.4 Version Bump [rebalanced,debuggedx3] - 2020-11-09

  • Fixed refactorings 2, 3, and 4 not actually affecting productivity

v1.0.3 Version Bump [rebalanced,debuggedx2] - 2020-11-08

  • Fixed API milestone 4 not working

v1.0.2 Version Bump [rebalanced,debugged] - 2020-11-08

  • Fixed tree lines being hidden after hitting "keepGoing" in the victory screen

v1.0.1 Version Bump [rebalanced] - 2020-11-08

  • Buffed several TAs

v1.0 Version Bump - 2020-11-08

  • Finished row 4
  • Added colored text to lore
  • Fixed some visual bugs with milestones
  • Probably other stuff lol its been a week

v0.2.3 Stylish - 2020-10-30

  • Re-styled basically everything
  • Added favicon
  • Added header bar
  • Added changelog

v0.2.2 Row 3 - 2020-10-22

  • Removed debug statement
  • Moved milestones in F layer beneath the buyables

v0.2.1 Row 3 - 2020-10-21

  • Fixed layers hiding
  • Fixed typos/minor issues
  • Fixed S layer being highlighted before you can unlock the layer

v0.2 Row 3 - 2020-10-21

  • Implemented row 3

v0.1.1 Cash Influx [rebalanced] - 2020-10-19

  • Fixed notification issue
  • Rebalanced to make early game faster and late game slower
  • Fixed other minor issues

v0.1 Cash Influx - 2020-10-19

  • Implemented row 2

v0.0 Initial Commit - 2020-10-18

  • Implemented row 1
',25),n=[o];function t(d,h,s,u,c,b){return l(),a("div",null,n)}const g=e(r,[["render",t]]);export{m as __pageData,g as default}; diff --git a/assets/public_gamedevtree_changelog.md.BFpQdU6f.lean.js b/assets/public_gamedevtree_changelog.md.Bp63oq83.lean.js similarity index 71% rename from assets/public_gamedevtree_changelog.md.BFpQdU6f.lean.js rename to assets/public_gamedevtree_changelog.md.Bp63oq83.lean.js index 459bf6d6..cbb1913a 100644 --- a/assets/public_gamedevtree_changelog.md.BFpQdU6f.lean.js +++ b/assets/public_gamedevtree_changelog.md.Bp63oq83.lean.js @@ -1 +1 @@ -import{_ as e,c as a,o as l,ag as i}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"The Game Dev Tree changelog:","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/changelog.md","filePath":"public/gamedevtree/changelog.md"}'),r={name:"public/gamedevtree/changelog.md"},o=i("",25),n=[o];function t(d,h,s,u,c,b){return l(),a("div",null,n)}const g=e(r,[["render",t]]);export{m as __pageData,g as default}; +import{_ as e,q as a,p as l,ag as i}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"The Game Dev Tree changelog:","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/changelog.md","filePath":"public/gamedevtree/changelog.md"}'),r={name:"public/gamedevtree/changelog.md"},o=i("",25),n=[o];function t(d,h,s,u,c,b){return l(),a("div",null,n)}const g=e(r,[["render",t]]);export{m as __pageData,g as default}; diff --git a/assets/public_gamedevtree_docs_!general-info.md.B4kcWpV-.js b/assets/public_gamedevtree_docs_!general-info.md.DK2xr3yI.js similarity index 97% rename from assets/public_gamedevtree_docs_!general-info.md.B4kcWpV-.js rename to assets/public_gamedevtree_docs_!general-info.md.DK2xr3yI.js index 25582c20..1312c63f 100644 --- a/assets/public_gamedevtree_docs_!general-info.md.B4kcWpV-.js +++ b/assets/public_gamedevtree_docs_!general-info.md.DK2xr3yI.js @@ -1 +1 @@ -import{_ as e,c as a,o as t,ag as o}from"./chunks/framework.VBE0TPts.js";const b=JSON.parse('{"title":"The-Modding-Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/!general-info.md","filePath":"public/gamedevtree/docs/!general-info.md"}'),n={name:"public/gamedevtree/docs/!general-info.md"},r=o('

The-Modding-Tree

The main way to add content is through creating layers. You can either add a layer directly in the layers object in layersSupportjs, or declare it in another file and then do "addLayer(layername, layerdata)" (good for breaking things up into smaller files). The existing layers are just examples and can be freely deleted. You can also use them as references and a base for your own layers.

The first thing you need to do is to edit the modInfo at the top of game.js to set your modID (a string). A unique modId will prevent your mod's saves from conflicting with other mods.

Most of the time, you won't need to dive deep into the code to create things, but you still can if you really want to.

The Modding Tree uses break_eternity.js to store large values. This means that many numbers are Decimal objects, and must be treated differently. For example, you have to use new Decimal(x) to create a Decimal value instead of a plain number, and perform operations on them by calling functions. e.g, instead of x = x + y, use x = x.add(y).

Almost all values can be either a constant value, or a dynamic value. Dynamic values are defined by putting a function that returns what the value should be at any given time.

All display text can be basic HTML instead (But you can't use most Vue features there).

Table of Contents:

General:

  • Getting Started: Getting your own copy of the code set up with Github Desktop.
  • Main mod info: How to set up general things for your mod in mod.js.
  • Basic layer breakdown: Breaking down the components of a layer with minimal features.
  • Layer features: Explanations of all of the different properties that you can give a layer.
  • Custom Tab Layouts: An optional way to give your tabs a different layout. You can even create entirely new components to use.
  • Updating TMT: Using Github Desktop to update your mod's version of TMT.

Common components

  • Upgrades: How to create upgrades for a layer.
  • Milestones: How to create milestones for a layer.
  • Buyables: Create rebuyable upgrades for your layer (with the option to make them respec-able). Can be used to make Enhancers or Space Buildings.
  • Clickables: A more generalized variant of buyables, for any kind of thing that is sometimes clickable. Between these and Buyables, you can do just about anything.

Other components

  • Challenges: How to create challenges for a layer.
  • Bars: Display some information as a progress bar, gague, or similar. They are highly customizable, and can be horizontal and vertical as well.
  • Subtabs and Microtabs: Create subtabs for your tabs, as well as "microtab" components that you can put inside the tabs.
  • Achievements: How to create achievements for a layer (or for the whole game).
  • Infoboxes: Boxes containing text that can be shown or hidden.
',14),i=[r];function s(l,d,c,h,u,m){return t(),a("div",null,i)}const p=e(n,[["render",s]]);export{b as __pageData,p as default}; +import{_ as e,q as a,p as t,ag as o}from"./chunks/framework.DvHfxfnp.js";const b=JSON.parse('{"title":"The-Modding-Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/!general-info.md","filePath":"public/gamedevtree/docs/!general-info.md"}'),n={name:"public/gamedevtree/docs/!general-info.md"},r=o('

The-Modding-Tree

The main way to add content is through creating layers. You can either add a layer directly in the layers object in layersSupportjs, or declare it in another file and then do "addLayer(layername, layerdata)" (good for breaking things up into smaller files). The existing layers are just examples and can be freely deleted. You can also use them as references and a base for your own layers.

The first thing you need to do is to edit the modInfo at the top of game.js to set your modID (a string). A unique modId will prevent your mod's saves from conflicting with other mods.

Most of the time, you won't need to dive deep into the code to create things, but you still can if you really want to.

The Modding Tree uses break_eternity.js to store large values. This means that many numbers are Decimal objects, and must be treated differently. For example, you have to use new Decimal(x) to create a Decimal value instead of a plain number, and perform operations on them by calling functions. e.g, instead of x = x + y, use x = x.add(y).

Almost all values can be either a constant value, or a dynamic value. Dynamic values are defined by putting a function that returns what the value should be at any given time.

All display text can be basic HTML instead (But you can't use most Vue features there).

Table of Contents:

General:

  • Getting Started: Getting your own copy of the code set up with Github Desktop.
  • Main mod info: How to set up general things for your mod in mod.js.
  • Basic layer breakdown: Breaking down the components of a layer with minimal features.
  • Layer features: Explanations of all of the different properties that you can give a layer.
  • Custom Tab Layouts: An optional way to give your tabs a different layout. You can even create entirely new components to use.
  • Updating TMT: Using Github Desktop to update your mod's version of TMT.

Common components

  • Upgrades: How to create upgrades for a layer.
  • Milestones: How to create milestones for a layer.
  • Buyables: Create rebuyable upgrades for your layer (with the option to make them respec-able). Can be used to make Enhancers or Space Buildings.
  • Clickables: A more generalized variant of buyables, for any kind of thing that is sometimes clickable. Between these and Buyables, you can do just about anything.

Other components

  • Challenges: How to create challenges for a layer.
  • Bars: Display some information as a progress bar, gague, or similar. They are highly customizable, and can be horizontal and vertical as well.
  • Subtabs and Microtabs: Create subtabs for your tabs, as well as "microtab" components that you can put inside the tabs.
  • Achievements: How to create achievements for a layer (or for the whole game).
  • Infoboxes: Boxes containing text that can be shown or hidden.
',14),i=[r];function s(l,d,c,h,u,m){return t(),a("div",null,i)}const p=e(n,[["render",s]]);export{b as __pageData,p as default}; diff --git a/assets/public_gamedevtree_docs_!general-info.md.B4kcWpV-.lean.js b/assets/public_gamedevtree_docs_!general-info.md.DK2xr3yI.lean.js similarity index 72% rename from assets/public_gamedevtree_docs_!general-info.md.B4kcWpV-.lean.js rename to assets/public_gamedevtree_docs_!general-info.md.DK2xr3yI.lean.js index e5aedb5b..1f0d32ea 100644 --- a/assets/public_gamedevtree_docs_!general-info.md.B4kcWpV-.lean.js +++ b/assets/public_gamedevtree_docs_!general-info.md.DK2xr3yI.lean.js @@ -1 +1 @@ -import{_ as e,c as a,o as t,ag as o}from"./chunks/framework.VBE0TPts.js";const b=JSON.parse('{"title":"The-Modding-Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/!general-info.md","filePath":"public/gamedevtree/docs/!general-info.md"}'),n={name:"public/gamedevtree/docs/!general-info.md"},r=o("",14),i=[r];function s(l,d,c,h,u,m){return t(),a("div",null,i)}const p=e(n,[["render",s]]);export{b as __pageData,p as default}; +import{_ as e,q as a,p as t,ag as o}from"./chunks/framework.DvHfxfnp.js";const b=JSON.parse('{"title":"The-Modding-Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/!general-info.md","filePath":"public/gamedevtree/docs/!general-info.md"}'),n={name:"public/gamedevtree/docs/!general-info.md"},r=o("",14),i=[r];function s(l,d,c,h,u,m){return t(),a("div",null,i)}const p=e(n,[["render",s]]);export{b as __pageData,p as default}; diff --git a/assets/public_gamedevtree_docs_achievements.md.C6gZOG4E.js b/assets/public_gamedevtree_docs_achievements.md.jhkjuzaR.js similarity index 97% rename from assets/public_gamedevtree_docs_achievements.md.C6gZOG4E.js rename to assets/public_gamedevtree_docs_achievements.md.jhkjuzaR.js index 7eda1c68..f777abf5 100644 --- a/assets/public_gamedevtree_docs_achievements.md.C6gZOG4E.js +++ b/assets/public_gamedevtree_docs_achievements.md.jhkjuzaR.js @@ -1,4 +1,4 @@ -import{_ as e,c as t,o as a,ag as i}from"./chunks/framework.VBE0TPts.js";const g=JSON.parse('{"title":"Achievements","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/achievements.md","filePath":"public/gamedevtree/docs/achievements.md"}'),s={name:"public/gamedevtree/docs/achievements.md"},n=i(`

Achievements

Achievements are awarded to the player when they meet a certain goal, and give some benefit. Currently, they are pretty basic, but additional features will be added later to help.

You can make global achievements by putting them in a side layer (make its row "side" instead of a number)

Useful functions for dealing with achievements and implementing their effects:

  • hasAchievement(layer, id): determine if the player has the Achievement
  • achievementEffect(layer, id): Returns the current effects of the achievement, if any

Achievements should be formatted like this:

js
    achievements: {
+import{_ as e,q as t,p as a,ag as i}from"./chunks/framework.DvHfxfnp.js";const g=JSON.parse('{"title":"Achievements","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/achievements.md","filePath":"public/gamedevtree/docs/achievements.md"}'),s={name:"public/gamedevtree/docs/achievements.md"},n=i(`

Achievements

Achievements are awarded to the player when they meet a certain goal, and give some benefit. Currently, they are pretty basic, but additional features will be added later to help.

You can make global achievements by putting them in a side layer (make its row "side" instead of a number)

Useful functions for dealing with achievements and implementing their effects:

  • hasAchievement(layer, id): determine if the player has the Achievement
  • achievementEffect(layer, id): Returns the current effects of the achievement, if any

Achievements should be formatted like this:

js
    achievements: {
         rows: # of rows
         cols: # of columns
         11: {
diff --git a/assets/public_gamedevtree_docs_achievements.md.C6gZOG4E.lean.js b/assets/public_gamedevtree_docs_achievements.md.jhkjuzaR.lean.js
similarity index 72%
rename from assets/public_gamedevtree_docs_achievements.md.C6gZOG4E.lean.js
rename to assets/public_gamedevtree_docs_achievements.md.jhkjuzaR.lean.js
index 59eef09e..df3d13b5 100644
--- a/assets/public_gamedevtree_docs_achievements.md.C6gZOG4E.lean.js
+++ b/assets/public_gamedevtree_docs_achievements.md.jhkjuzaR.lean.js
@@ -1 +1 @@
-import{_ as e,c as t,o as a,ag as i}from"./chunks/framework.VBE0TPts.js";const g=JSON.parse('{"title":"Achievements","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/achievements.md","filePath":"public/gamedevtree/docs/achievements.md"}'),s={name:"public/gamedevtree/docs/achievements.md"},n=i("",9),l=[n];function h(o,r,p,c,d,u){return a(),t("div",null,l)}const k=e(s,[["render",h]]);export{g as __pageData,k as default};
+import{_ as e,q as t,p as a,ag as i}from"./chunks/framework.DvHfxfnp.js";const g=JSON.parse('{"title":"Achievements","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/achievements.md","filePath":"public/gamedevtree/docs/achievements.md"}'),s={name:"public/gamedevtree/docs/achievements.md"},n=i("",9),l=[n];function h(o,r,p,c,d,u){return a(),t("div",null,l)}const k=e(s,[["render",h]]);export{g as __pageData,k as default};
diff --git a/assets/public_gamedevtree_docs_bars.md.1NZ3Fz1N.js b/assets/public_gamedevtree_docs_bars.md.CBtj98pG.js
similarity index 96%
rename from assets/public_gamedevtree_docs_bars.md.1NZ3Fz1N.js
rename to assets/public_gamedevtree_docs_bars.md.CBtj98pG.js
index 021bcf88..8767012d 100644
--- a/assets/public_gamedevtree_docs_bars.md.1NZ3Fz1N.js
+++ b/assets/public_gamedevtree_docs_bars.md.CBtj98pG.js
@@ -1,4 +1,4 @@
-import{_ as s,c as t,o as a,ag as e}from"./chunks/framework.VBE0TPts.js";const k=JSON.parse('{"title":"Bars","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/bars.md","filePath":"public/gamedevtree/docs/bars.md"}'),i={name:"public/gamedevtree/docs/bars.md"},n=e(`

Bars

Bars let you display information in a more direct way. It can be a progress bar, health bar, capacity gague, or anything else.

Bars are defined like other Big Features:

js
    bars: {
+import{_ as s,q as t,p as a,ag as e}from"./chunks/framework.DvHfxfnp.js";const k=JSON.parse('{"title":"Bars","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/bars.md","filePath":"public/gamedevtree/docs/bars.md"}'),i={name:"public/gamedevtree/docs/bars.md"},n=e(`

Bars

Bars let you display information in a more direct way. It can be a progress bar, health bar, capacity gague, or anything else.

Bars are defined like other Big Features:

js
    bars: {
         bigBar: {
             display() {return "Blah"},
             etc
diff --git a/assets/public_gamedevtree_docs_bars.md.1NZ3Fz1N.lean.js b/assets/public_gamedevtree_docs_bars.md.CBtj98pG.lean.js
similarity index 70%
rename from assets/public_gamedevtree_docs_bars.md.1NZ3Fz1N.lean.js
rename to assets/public_gamedevtree_docs_bars.md.CBtj98pG.lean.js
index b9014095..19823299 100644
--- a/assets/public_gamedevtree_docs_bars.md.1NZ3Fz1N.lean.js
+++ b/assets/public_gamedevtree_docs_bars.md.CBtj98pG.lean.js
@@ -1 +1 @@
-import{_ as s,c as t,o as a,ag as e}from"./chunks/framework.VBE0TPts.js";const k=JSON.parse('{"title":"Bars","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/bars.md","filePath":"public/gamedevtree/docs/bars.md"}'),i={name:"public/gamedevtree/docs/bars.md"},n=e("",6),r=[n];function l(o,p,h,d,c,u){return a(),t("div",null,r)}const b=s(i,[["render",l]]);export{k as __pageData,b as default};
+import{_ as s,q as t,p as a,ag as e}from"./chunks/framework.DvHfxfnp.js";const k=JSON.parse('{"title":"Bars","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/bars.md","filePath":"public/gamedevtree/docs/bars.md"}'),i={name:"public/gamedevtree/docs/bars.md"},n=e("",6),r=[n];function l(o,p,h,d,c,u){return a(),t("div",null,r)}const b=s(i,[["render",l]]);export{k as __pageData,b as default};
diff --git a/assets/public_gamedevtree_docs_basic-layer-breakdown.md.DG6Q9mdT.js b/assets/public_gamedevtree_docs_basic-layer-breakdown.md.Ykqytlzk.js
similarity index 98%
rename from assets/public_gamedevtree_docs_basic-layer-breakdown.md.DG6Q9mdT.js
rename to assets/public_gamedevtree_docs_basic-layer-breakdown.md.Ykqytlzk.js
index e516e539..7e40ed18 100644
--- a/assets/public_gamedevtree_docs_basic-layer-breakdown.md.DG6Q9mdT.js
+++ b/assets/public_gamedevtree_docs_basic-layer-breakdown.md.Ykqytlzk.js
@@ -1,4 +1,4 @@
-import{_ as s,c as i,o as a,ag as n}from"./chunks/framework.VBE0TPts.js";const g=JSON.parse('{"title":"Basic layer breakdown","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/basic-layer-breakdown.md","filePath":"public/gamedevtree/docs/basic-layer-breakdown.md"}'),e={name:"public/gamedevtree/docs/basic-layer-breakdown.md"},t=n(`

Basic layer breakdown

This is a very minimal layer with minimal features. Most things will require additional features.

js
    p: {
+import{_ as s,q as i,p as a,ag as n}from"./chunks/framework.DvHfxfnp.js";const g=JSON.parse('{"title":"Basic layer breakdown","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/basic-layer-breakdown.md","filePath":"public/gamedevtree/docs/basic-layer-breakdown.md"}'),e={name:"public/gamedevtree/docs/basic-layer-breakdown.md"},t=n(`

Basic layer breakdown

This is a very minimal layer with minimal features. Most things will require additional features.

js
    p: {
         startData() { return {                  // startData is a function that returns default data for a layer. 
             unlocked: false,                    // You can add more variables here to add them to your layer.
             points: new Decimal(0),             // "points" is the internal name for the main resource of the layer.
diff --git a/assets/public_gamedevtree_docs_basic-layer-breakdown.md.DG6Q9mdT.lean.js b/assets/public_gamedevtree_docs_basic-layer-breakdown.md.Ykqytlzk.lean.js
similarity index 74%
rename from assets/public_gamedevtree_docs_basic-layer-breakdown.md.DG6Q9mdT.lean.js
rename to assets/public_gamedevtree_docs_basic-layer-breakdown.md.Ykqytlzk.lean.js
index cef3b833..96bb4f1b 100644
--- a/assets/public_gamedevtree_docs_basic-layer-breakdown.md.DG6Q9mdT.lean.js
+++ b/assets/public_gamedevtree_docs_basic-layer-breakdown.md.Ykqytlzk.lean.js
@@ -1 +1 @@
-import{_ as s,c as i,o as a,ag as n}from"./chunks/framework.VBE0TPts.js";const g=JSON.parse('{"title":"Basic layer breakdown","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/basic-layer-breakdown.md","filePath":"public/gamedevtree/docs/basic-layer-breakdown.md"}'),e={name:"public/gamedevtree/docs/basic-layer-breakdown.md"},t=n("",3),h=[t];function l(k,p,r,E,d,o){return a(),i("div",null,h)}const c=s(e,[["render",l]]);export{g as __pageData,c as default};
+import{_ as s,q as i,p as a,ag as n}from"./chunks/framework.DvHfxfnp.js";const g=JSON.parse('{"title":"Basic layer breakdown","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/basic-layer-breakdown.md","filePath":"public/gamedevtree/docs/basic-layer-breakdown.md"}'),e={name:"public/gamedevtree/docs/basic-layer-breakdown.md"},t=n("",3),h=[t];function l(k,p,r,E,d,o){return a(),i("div",null,h)}const c=s(e,[["render",l]]);export{g as __pageData,c as default};
diff --git a/assets/public_gamedevtree_docs_buyables.md.BWSB6neR.js b/assets/public_gamedevtree_docs_buyables.md.C7aL_4eK.js
similarity index 98%
rename from assets/public_gamedevtree_docs_buyables.md.BWSB6neR.js
rename to assets/public_gamedevtree_docs_buyables.md.C7aL_4eK.js
index d045443a..46f4d6e4 100644
--- a/assets/public_gamedevtree_docs_buyables.md.BWSB6neR.js
+++ b/assets/public_gamedevtree_docs_buyables.md.C7aL_4eK.js
@@ -1,4 +1,4 @@
-import{_ as s,c as e,o as t,ag as a}from"./chunks/framework.VBE0TPts.js";const y=JSON.parse('{"title":"Buyables","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/buyables.md","filePath":"public/gamedevtree/docs/buyables.md"}'),i={name:"public/gamedevtree/docs/buyables.md"},n=a(`

Buyables

Buyables are usually things that can be bought multiple times with scaling costs. If you set a respec function, the player can reset the purchases to get their currency back.

The amount of a buyable owned is a Decimal. You can get or set the amount of a buyable with getBuyableAmt(layer, id) and setBuyableAmt(layer, id, amt). You can use buyableEffect(layer, id) to get the current effects of a buyable.

Buyables should be formatted like this:

js
    buyables: {
+import{_ as s,q as e,p as t,ag as a}from"./chunks/framework.DvHfxfnp.js";const y=JSON.parse('{"title":"Buyables","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/buyables.md","filePath":"public/gamedevtree/docs/buyables.md"}'),i={name:"public/gamedevtree/docs/buyables.md"},n=a(`

Buyables

Buyables are usually things that can be bought multiple times with scaling costs. If you set a respec function, the player can reset the purchases to get their currency back.

The amount of a buyable owned is a Decimal. You can get or set the amount of a buyable with getBuyableAmt(layer, id) and setBuyableAmt(layer, id, amt). You can use buyableEffect(layer, id) to get the current effects of a buyable.

Buyables should be formatted like this:

js
    buyables: {
         rows: # of rows
         cols: # of columns
         respec() {}, //**optional**, implement it to reset things and give back your currency.
diff --git a/assets/public_gamedevtree_docs_buyables.md.BWSB6neR.lean.js b/assets/public_gamedevtree_docs_buyables.md.C7aL_4eK.lean.js
similarity index 71%
rename from assets/public_gamedevtree_docs_buyables.md.BWSB6neR.lean.js
rename to assets/public_gamedevtree_docs_buyables.md.C7aL_4eK.lean.js
index a2a52f43..968d745f 100644
--- a/assets/public_gamedevtree_docs_buyables.md.BWSB6neR.lean.js
+++ b/assets/public_gamedevtree_docs_buyables.md.C7aL_4eK.lean.js
@@ -1 +1 @@
-import{_ as s,c as e,o as t,ag as a}from"./chunks/framework.VBE0TPts.js";const y=JSON.parse('{"title":"Buyables","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/buyables.md","filePath":"public/gamedevtree/docs/buyables.md"}'),i={name:"public/gamedevtree/docs/buyables.md"},n=a("",11),l=[n];function o(p,h,r,u,c,k){return t(),e("div",null,l)}const b=s(i,[["render",o]]);export{y as __pageData,b as default};
+import{_ as s,q as e,p as t,ag as a}from"./chunks/framework.DvHfxfnp.js";const y=JSON.parse('{"title":"Buyables","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/buyables.md","filePath":"public/gamedevtree/docs/buyables.md"}'),i={name:"public/gamedevtree/docs/buyables.md"},n=a("",11),l=[n];function o(p,h,r,u,c,k){return t(),e("div",null,l)}const b=s(i,[["render",o]]);export{y as __pageData,b as default};
diff --git a/assets/public_gamedevtree_docs_challenges.md.DJU5H6Rk.js b/assets/public_gamedevtree_docs_challenges.md.cvYq35wY.js
similarity index 98%
rename from assets/public_gamedevtree_docs_challenges.md.DJU5H6Rk.js
rename to assets/public_gamedevtree_docs_challenges.md.cvYq35wY.js
index 1fce96a6..7bdb4966 100644
--- a/assets/public_gamedevtree_docs_challenges.md.DJU5H6Rk.js
+++ b/assets/public_gamedevtree_docs_challenges.md.cvYq35wY.js
@@ -1,4 +1,4 @@
-import{_ as e,c as a,o as t,ag as s}from"./chunks/framework.VBE0TPts.js";const f=JSON.parse('{"title":"Challenges","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/challenges.md","filePath":"public/gamedevtree/docs/challenges.md"}'),i={name:"public/gamedevtree/docs/challenges.md"},n=s(`

Challenges

Useful functions for dealing with Challenges and implementing their effects:

  • inChallenge(layer, id): determine if the player is in a given challenge (or another challenge on the same layer that counts as this one)
  • hasChallenge(layer, id): determine if the player has completed the challenge
  • challengeCompletions(layer, id): determine how many times the player completed the challenge
  • challEffect(layer, id): Returns the current effects of the challenge, if any

Challenges are stored in the following format:

js
    challenges: {
+import{_ as e,q as a,p as t,ag as s}from"./chunks/framework.DvHfxfnp.js";const f=JSON.parse('{"title":"Challenges","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/challenges.md","filePath":"public/gamedevtree/docs/challenges.md"}'),i={name:"public/gamedevtree/docs/challenges.md"},n=s(`

Challenges

Useful functions for dealing with Challenges and implementing their effects:

  • inChallenge(layer, id): determine if the player is in a given challenge (or another challenge on the same layer that counts as this one)
  • hasChallenge(layer, id): determine if the player has completed the challenge
  • challengeCompletions(layer, id): determine how many times the player completed the challenge
  • challEffect(layer, id): Returns the current effects of the challenge, if any

Challenges are stored in the following format:

js
    challenges: {
         rows: # of rows
         cols: # of columns
         11: {
diff --git a/assets/public_gamedevtree_docs_challenges.md.DJU5H6Rk.lean.js b/assets/public_gamedevtree_docs_challenges.md.cvYq35wY.lean.js
similarity index 71%
rename from assets/public_gamedevtree_docs_challenges.md.DJU5H6Rk.lean.js
rename to assets/public_gamedevtree_docs_challenges.md.cvYq35wY.lean.js
index f075dfbd..614dae7a 100644
--- a/assets/public_gamedevtree_docs_challenges.md.DJU5H6Rk.lean.js
+++ b/assets/public_gamedevtree_docs_challenges.md.cvYq35wY.lean.js
@@ -1 +1 @@
-import{_ as e,c as a,o as t,ag as s}from"./chunks/framework.VBE0TPts.js";const f=JSON.parse('{"title":"Challenges","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/challenges.md","filePath":"public/gamedevtree/docs/challenges.md"}'),i={name:"public/gamedevtree/docs/challenges.md"},n=s("",9),l=[n];function o(h,r,c,p,g,u){return t(),a("div",null,l)}const y=e(i,[["render",o]]);export{f as __pageData,y as default};
+import{_ as e,q as a,p as t,ag as s}from"./chunks/framework.DvHfxfnp.js";const f=JSON.parse('{"title":"Challenges","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/challenges.md","filePath":"public/gamedevtree/docs/challenges.md"}'),i={name:"public/gamedevtree/docs/challenges.md"},n=s("",9),l=[n];function o(h,r,c,p,g,u){return t(),a("div",null,l)}const y=e(i,[["render",o]]);export{f as __pageData,y as default};
diff --git a/assets/public_gamedevtree_docs_clickables.md.DlF0g6fO.js b/assets/public_gamedevtree_docs_clickables.md.CwLsimiU.js
similarity index 97%
rename from assets/public_gamedevtree_docs_clickables.md.DlF0g6fO.js
rename to assets/public_gamedevtree_docs_clickables.md.CwLsimiU.js
index 83844198..daa757b4 100644
--- a/assets/public_gamedevtree_docs_clickables.md.DlF0g6fO.js
+++ b/assets/public_gamedevtree_docs_clickables.md.CwLsimiU.js
@@ -1,4 +1,4 @@
-import{_ as s,c as i,o as a,ag as e}from"./chunks/framework.VBE0TPts.js";const g=JSON.parse('{"title":"Clickables","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/clickables.md","filePath":"public/gamedevtree/docs/clickables.md"}'),t={name:"public/gamedevtree/docs/clickables.md"},l=e(`

Clickables

Clickables are any kind of thing that you can click for an effect. They're a more generalized version of Buyables.

DO NOT USE THESE TO MAKE THINGS THAT YOU CLICK REPEATEDLY FOR A BONUS BECAUSE THOSE ARE AWFUL.

There are several differences between the two. One is that a buyable's saved data is its amount as a Decimal, while Clickables store a "state" which can be a number or string, but not Decimal, array, or object). Buyables have a number of extra features which you can see on their page. Clickables also have a smaller default size.

You can get and set a clickable's state with getClickableState(layer, id) and setClickableState(layer, id, state). You can use clickableEffect(layer, id) to get the current effects of a clickable.

Clickables should be formatted like this:

js
    clickables: {
+import{_ as s,q as i,p as a,ag as e}from"./chunks/framework.DvHfxfnp.js";const g=JSON.parse('{"title":"Clickables","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/clickables.md","filePath":"public/gamedevtree/docs/clickables.md"}'),t={name:"public/gamedevtree/docs/clickables.md"},l=e(`

Clickables

Clickables are any kind of thing that you can click for an effect. They're a more generalized version of Buyables.

DO NOT USE THESE TO MAKE THINGS THAT YOU CLICK REPEATEDLY FOR A BONUS BECAUSE THOSE ARE AWFUL.

There are several differences between the two. One is that a buyable's saved data is its amount as a Decimal, while Clickables store a "state" which can be a number or string, but not Decimal, array, or object). Buyables have a number of extra features which you can see on their page. Clickables also have a smaller default size.

You can get and set a clickable's state with getClickableState(layer, id) and setClickableState(layer, id, state). You can use clickableEffect(layer, id) to get the current effects of a clickable.

Clickables should be formatted like this:

js
    clickables: {
         rows: # of rows
         cols: # of columns
         masterButtonPress() // **optional** If this is present, an additional button will appear above the clickables.
diff --git a/assets/public_gamedevtree_docs_clickables.md.DlF0g6fO.lean.js b/assets/public_gamedevtree_docs_clickables.md.CwLsimiU.lean.js
similarity index 71%
rename from assets/public_gamedevtree_docs_clickables.md.DlF0g6fO.lean.js
rename to assets/public_gamedevtree_docs_clickables.md.CwLsimiU.lean.js
index 6d1bc15e..88fb1b41 100644
--- a/assets/public_gamedevtree_docs_clickables.md.DlF0g6fO.lean.js
+++ b/assets/public_gamedevtree_docs_clickables.md.CwLsimiU.lean.js
@@ -1 +1 @@
-import{_ as s,c as i,o as a,ag as e}from"./chunks/framework.VBE0TPts.js";const g=JSON.parse('{"title":"Clickables","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/clickables.md","filePath":"public/gamedevtree/docs/clickables.md"}'),t={name:"public/gamedevtree/docs/clickables.md"},l=e("",9),n=[l];function h(p,o,r,c,k,d){return a(),i("div",null,n)}const E=s(t,[["render",h]]);export{g as __pageData,E as default};
+import{_ as s,q as i,p as a,ag as e}from"./chunks/framework.DvHfxfnp.js";const g=JSON.parse('{"title":"Clickables","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/clickables.md","filePath":"public/gamedevtree/docs/clickables.md"}'),t={name:"public/gamedevtree/docs/clickables.md"},l=e("",9),n=[l];function h(p,o,r,c,k,d){return a(),i("div",null,n)}const E=s(t,[["render",h]]);export{g as __pageData,E as default};
diff --git a/assets/public_gamedevtree_docs_custom-tab-layouts.md.oOQumDgW.js b/assets/public_gamedevtree_docs_custom-tab-layouts.md.DIYFlfWc.js
similarity index 98%
rename from assets/public_gamedevtree_docs_custom-tab-layouts.md.oOQumDgW.js
rename to assets/public_gamedevtree_docs_custom-tab-layouts.md.DIYFlfWc.js
index e722c370..8c0dc3fa 100644
--- a/assets/public_gamedevtree_docs_custom-tab-layouts.md.oOQumDgW.js
+++ b/assets/public_gamedevtree_docs_custom-tab-layouts.md.DIYFlfWc.js
@@ -1,4 +1,4 @@
-import{_ as s,c as i,o as a,ag as t}from"./chunks/framework.VBE0TPts.js";const E=JSON.parse('{"title":"Custom tab layouts","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/custom-tab-layouts.md","filePath":"public/gamedevtree/docs/custom-tab-layouts.md"}'),e={name:"public/gamedevtree/docs/custom-tab-layouts.md"},n=t(`

Custom tab layouts

Note: If you are using subtabs, tabFormat is used differently, but you still use the same format within each subtabs. See here for more on subtabs

Custom tab layouts can be used to do basically anything in a tab window, especially combined with the "style" layer feature. The tabFormat feature is an array of things, like this:

js
    tabFormat: ["main-display",
+import{_ as s,q as i,p as a,ag as t}from"./chunks/framework.DvHfxfnp.js";const E=JSON.parse('{"title":"Custom tab layouts","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/custom-tab-layouts.md","filePath":"public/gamedevtree/docs/custom-tab-layouts.md"}'),e={name:"public/gamedevtree/docs/custom-tab-layouts.md"},n=t(`

Custom tab layouts

Note: If you are using subtabs, tabFormat is used differently, but you still use the same format within each subtabs. See here for more on subtabs

Custom tab layouts can be used to do basically anything in a tab window, especially combined with the "style" layer feature. The tabFormat feature is an array of things, like this:

js
    tabFormat: ["main-display",
             ["prestige-button", function(){return "Melt your points into "}],
             "blank",
             ["display-text",
diff --git a/assets/public_gamedevtree_docs_custom-tab-layouts.md.oOQumDgW.lean.js b/assets/public_gamedevtree_docs_custom-tab-layouts.md.DIYFlfWc.lean.js
similarity index 73%
rename from assets/public_gamedevtree_docs_custom-tab-layouts.md.oOQumDgW.lean.js
rename to assets/public_gamedevtree_docs_custom-tab-layouts.md.DIYFlfWc.lean.js
index 400b4fcb..aad99098 100644
--- a/assets/public_gamedevtree_docs_custom-tab-layouts.md.oOQumDgW.lean.js
+++ b/assets/public_gamedevtree_docs_custom-tab-layouts.md.DIYFlfWc.lean.js
@@ -1 +1 @@
-import{_ as s,c as i,o as a,ag as t}from"./chunks/framework.VBE0TPts.js";const E=JSON.parse('{"title":"Custom tab layouts","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/custom-tab-layouts.md","filePath":"public/gamedevtree/docs/custom-tab-layouts.md"}'),e={name:"public/gamedevtree/docs/custom-tab-layouts.md"},n=t("",9),l=[n];function h(p,o,r,k,u,d){return a(),i("div",null,l)}const c=s(e,[["render",h]]);export{E as __pageData,c as default};
+import{_ as s,q as i,p as a,ag as t}from"./chunks/framework.DvHfxfnp.js";const E=JSON.parse('{"title":"Custom tab layouts","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/custom-tab-layouts.md","filePath":"public/gamedevtree/docs/custom-tab-layouts.md"}'),e={name:"public/gamedevtree/docs/custom-tab-layouts.md"},n=t("",9),l=[n];function h(p,o,r,k,u,d){return a(),i("div",null,l)}const c=s(e,[["render",h]]);export{E as __pageData,c as default};
diff --git a/assets/public_gamedevtree_docs_getting-started.md.CyNrXhyL.js b/assets/public_gamedevtree_docs_getting-started.md.CyNrXhyL.js
new file mode 100644
index 00000000..617252a5
--- /dev/null
+++ b/assets/public_gamedevtree_docs_getting-started.md.CyNrXhyL.js
@@ -0,0 +1 @@
+import{_ as e,q as t,p as o,ag as i}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"Getting started","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/getting-started.md","filePath":"public/gamedevtree/docs/getting-started.md"}'),a={name:"public/gamedevtree/docs/getting-started.md"},n=i('

Getting started

Welcome to The Modding Tree!

Using the Modding Tree, at its simplest level, just requires getting a copy of it onto your computer. However, if you do it the right way, it will help in many ways.

Don't let the word "Github" scare you away. It's actually much easier to use than most people think, especially because most people use it the hard way. The key is Github Desktop, which lets you do everything you need to, without even touching the command line.

The benefits of using Github:

  • It makes it much, much easier to update The Modding Tree.
  • You can share your work without any extra effort using githack, or with a bit more effort, set up a github.io site.
  • It lets you undo changes to your code, and to have multiple versions of it.
  • It lets you collaborate with other people, if you want to.

Getting set up with Github and The Modding Tree:

  1. Install Github Desktop and Visual Studio Code.

  2. Make a Github account. You can handle this on your own.

  3. Log in on your browser, and go back to The Modding Tree page. At the top right, there should be a button that says "fork". Click on it, and then on your username. You now have your own fork, or copy, of The Modding Tree.

  4. Open Github Desktop and log in. Ignore everything else and choose "clone a repository". A "repository" is basically a "Github project", like The Modding Tree. "Cloning" is downloading a copy of the repository to your computer.

  5. Look for The Modding Tree in the list of repositiories (it should be the only one) and click "clone".

  6. Select that you're using it for your own purposes, and click continue. It will download the files and handle everything.

Using your repository

  1. Click on "show in finder" to the right, and then open index.html. This will let you view and test your project!

  2. To edit your project, click "open in VSCode" in Github Desktop.

  3. Open mod.js in VSCode, and look at the top part where it says "modInfo". On the lines below that, change the mod's name to whatever you want, and change the id as well. (It can be any string value, and it's used to determine where the savefile is. Make it something that's probably unique, and don't change it again later.)

  4. Save game.js, and then reload index.html. The title on the tab, as well as on the info page, will now be the new ones!

  5. Go back to Github Desktop. It's time to save your changes into the git system by making a "commit".

  6. At the bottom right corner, add a summary of your changes, and then click "commit to master".

  7. Finally, at the top middle, click "push origin" to push your changes out onto the online repository.

  8. You can view your project on line, or share it with others, by going to https://raw.githack.com/[YOUR-GITHUB-USERNAME]/The-Modding-Tree/master/index.html

And now, you have successfully used Github! You can look at the documentation to see how The Modding Tree's system works and to make your mod a reality.

',11),r=[n];function s(h,l,u,d,p,c){return o(),t("div",null,r)}const y=e(a,[["render",s]]);export{m as __pageData,y as default}; diff --git a/assets/public_gamedevtree_docs_getting-started.md.CyNrXhyL.lean.js b/assets/public_gamedevtree_docs_getting-started.md.CyNrXhyL.lean.js new file mode 100644 index 00000000..59bd3605 --- /dev/null +++ b/assets/public_gamedevtree_docs_getting-started.md.CyNrXhyL.lean.js @@ -0,0 +1 @@ +import{_ as e,q as t,p as o,ag as i}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"Getting started","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/getting-started.md","filePath":"public/gamedevtree/docs/getting-started.md"}'),a={name:"public/gamedevtree/docs/getting-started.md"},n=i("",11),r=[n];function s(h,l,u,d,p,c){return o(),t("div",null,r)}const y=e(a,[["render",s]]);export{m as __pageData,y as default}; diff --git a/assets/public_gamedevtree_docs_getting-started.md.DZiPQZAv.js b/assets/public_gamedevtree_docs_getting-started.md.DZiPQZAv.js deleted file mode 100644 index 9ac93620..00000000 --- a/assets/public_gamedevtree_docs_getting-started.md.DZiPQZAv.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as e,c as t,o,ag as i}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"Getting started","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/getting-started.md","filePath":"public/gamedevtree/docs/getting-started.md"}'),a={name:"public/gamedevtree/docs/getting-started.md"},n=i('

Getting started

Welcome to The Modding Tree!

Using the Modding Tree, at its simplest level, just requires getting a copy of it onto your computer. However, if you do it the right way, it will help in many ways.

Don't let the word "Github" scare you away. It's actually much easier to use than most people think, especially because most people use it the hard way. The key is Github Desktop, which lets you do everything you need to, without even touching the command line.

The benefits of using Github:

  • It makes it much, much easier to update The Modding Tree.
  • You can share your work without any extra effort using githack, or with a bit more effort, set up a github.io site.
  • It lets you undo changes to your code, and to have multiple versions of it.
  • It lets you collaborate with other people, if you want to.

Getting set up with Github and The Modding Tree:

  1. Install Github Desktop and Visual Studio Code.

  2. Make a Github account. You can handle this on your own.

  3. Log in on your browser, and go back to The Modding Tree page. At the top right, there should be a button that says "fork". Click on it, and then on your username. You now have your own fork, or copy, of The Modding Tree.

  4. Open Github Desktop and log in. Ignore everything else and choose "clone a repository". A "repository" is basically a "Github project", like The Modding Tree. "Cloning" is downloading a copy of the repository to your computer.

  5. Look for The Modding Tree in the list of repositiories (it should be the only one) and click "clone".

  6. Select that you're using it for your own purposes, and click continue. It will download the files and handle everything.

Using your repository

  1. Click on "show in finder" to the right, and then open index.html. This will let you view and test your project!

  2. To edit your project, click "open in VSCode" in Github Desktop.

  3. Open mod.js in VSCode, and look at the top part where it says "modInfo". On the lines below that, change the mod's name to whatever you want, and change the id as well. (It can be any string value, and it's used to determine where the savefile is. Make it something that's probably unique, and don't change it again later.)

  4. Save game.js, and then reload index.html. The title on the tab, as well as on the info page, will now be the new ones!

  5. Go back to Github Desktop. It's time to save your changes into the git system by making a "commit".

  6. At the bottom right corner, add a summary of your changes, and then click "commit to master".

  7. Finally, at the top middle, click "push origin" to push your changes out onto the online repository.

  8. You can view your project on line, or share it with others, by going to https://raw.githack.com/[YOUR-GITHUB-USERNAME]/The-Modding-Tree/master/index.html

And now, you have successfully used Github! You can look at the documentation to see how The Modding Tree's system works and to make your mod a reality.

',11),r=[n];function s(h,l,u,d,p,c){return o(),t("div",null,r)}const y=e(a,[["render",s]]);export{m as __pageData,y as default}; diff --git a/assets/public_gamedevtree_docs_getting-started.md.DZiPQZAv.lean.js b/assets/public_gamedevtree_docs_getting-started.md.DZiPQZAv.lean.js deleted file mode 100644 index 488abf29..00000000 --- a/assets/public_gamedevtree_docs_getting-started.md.DZiPQZAv.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as e,c as t,o,ag as i}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"Getting started","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/getting-started.md","filePath":"public/gamedevtree/docs/getting-started.md"}'),a={name:"public/gamedevtree/docs/getting-started.md"},n=i("",11),r=[n];function s(h,l,u,d,p,c){return o(),t("div",null,r)}const y=e(a,[["render",s]]);export{m as __pageData,y as default}; diff --git a/assets/public_gamedevtree_docs_infoboxes.md.BtrpL17l.js b/assets/public_gamedevtree_docs_infoboxes.md.B4DD8BvC.js similarity index 96% rename from assets/public_gamedevtree_docs_infoboxes.md.BtrpL17l.js rename to assets/public_gamedevtree_docs_infoboxes.md.B4DD8BvC.js index c148f19a..1dff5ca5 100644 --- a/assets/public_gamedevtree_docs_infoboxes.md.BtrpL17l.js +++ b/assets/public_gamedevtree_docs_infoboxes.md.B4DD8BvC.js @@ -1,4 +1,4 @@ -import{_ as s,c as e,o as i,ag as a}from"./chunks/framework.VBE0TPts.js";const u=JSON.parse('{"title":"Infoboxes","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/infoboxes.md","filePath":"public/gamedevtree/docs/infoboxes.md"}'),t={name:"public/gamedevtree/docs/infoboxes.md"},n=a(`

Infoboxes

Infoboxes are good for displaying "lore", or story elements, as well as for explaining complicated things.

In the default tab layout, the first infobox will be displayed at the very top of the tab.

Infoboxes are defined like other Big Features:

js
    infoboxes: {
+import{_ as s,q as e,p as i,ag as a}from"./chunks/framework.DvHfxfnp.js";const u=JSON.parse('{"title":"Infoboxes","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/infoboxes.md","filePath":"public/gamedevtree/docs/infoboxes.md"}'),t={name:"public/gamedevtree/docs/infoboxes.md"},n=a(`

Infoboxes

Infoboxes are good for displaying "lore", or story elements, as well as for explaining complicated things.

In the default tab layout, the first infobox will be displayed at the very top of the tab.

Infoboxes are defined like other Big Features:

js
    infoboxes: {
         infobox: {
             display() {return "Blah"},
             etc
diff --git a/assets/public_gamedevtree_docs_infoboxes.md.BtrpL17l.lean.js b/assets/public_gamedevtree_docs_infoboxes.md.B4DD8BvC.lean.js
similarity index 71%
rename from assets/public_gamedevtree_docs_infoboxes.md.BtrpL17l.lean.js
rename to assets/public_gamedevtree_docs_infoboxes.md.B4DD8BvC.lean.js
index 1186b24a..8ad233e6 100644
--- a/assets/public_gamedevtree_docs_infoboxes.md.BtrpL17l.lean.js
+++ b/assets/public_gamedevtree_docs_infoboxes.md.B4DD8BvC.lean.js
@@ -1 +1 @@
-import{_ as s,c as e,o as i,ag as a}from"./chunks/framework.VBE0TPts.js";const u=JSON.parse('{"title":"Infoboxes","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/infoboxes.md","filePath":"public/gamedevtree/docs/infoboxes.md"}'),t={name:"public/gamedevtree/docs/infoboxes.md"},n=a("",7),o=[n];function l(p,r,h,d,c,b){return i(),e("div",null,o)}const g=s(t,[["render",l]]);export{u as __pageData,g as default};
+import{_ as s,q as e,p as i,ag as a}from"./chunks/framework.DvHfxfnp.js";const u=JSON.parse('{"title":"Infoboxes","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/infoboxes.md","filePath":"public/gamedevtree/docs/infoboxes.md"}'),t={name:"public/gamedevtree/docs/infoboxes.md"},n=a("",7),o=[n];function l(p,r,h,d,c,b){return i(),e("div",null,o)}const g=s(t,[["render",l]]);export{u as __pageData,g as default};
diff --git a/assets/public_gamedevtree_docs_layer-features.md.DAMp8TY6.js b/assets/public_gamedevtree_docs_layer-features.md.I54r8Buk.js
similarity index 99%
rename from assets/public_gamedevtree_docs_layer-features.md.DAMp8TY6.js
rename to assets/public_gamedevtree_docs_layer-features.md.I54r8Buk.js
index 96c4556c..c4c337f9 100644
--- a/assets/public_gamedevtree_docs_layer-features.md.DAMp8TY6.js
+++ b/assets/public_gamedevtree_docs_layer-features.md.I54r8Buk.js
@@ -1,4 +1,4 @@
-import{_ as e,c as t,o as a,ag as i}from"./chunks/framework.VBE0TPts.js";const g=JSON.parse('{"title":"Layer Features","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/layer-features.md","filePath":"public/gamedevtree/docs/layer-features.md"}'),s={name:"public/gamedevtree/docs/layer-features.md"},n=i(`

Layer Features

This is a more comprehensive list of established features to add to layers. You can add more freely, if you want to have other functions or values associated with your layer. These have special functionality, though.

You can make almost any value dynamic by using a function in its place, including all display strings and styling/color features.

Key:

  • No label: This is required and the game will crash if it isn't included.
  • sometimes required: This is may be required, depending on other things in the layer.
  • optional: You can leave this out if you don't intend to use that feature for the layer.

Layer Definition features

  • layer: Assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar to access the save value. It makes copying code to new layers easier. It is also assigned to all upgrades and buyables and such.

  • name: Optional, used in reset confirmations (and maybe other places). If absent, it just uses the layer's id.

  • startData(): A function to return the default save data for this layer. Add any variables you have to it. Any nonstandard Decimal variables need to be added to convertToDecimal as well. Standard values: Required: unlocked: a bool determining if this layer is unlocked or not points: a Decimal, the main currency for the layer Optional: total: A Decimal, tracks total amount of main prestige currency best: A Decimal, tracks highest amount of main prestige currency unlockOrder: used to keep track of relevant layers unlocked before this one.

  • color: A color associated with this layer, used in many places. (A string in hex format with a #)

  • row: The row of the layer, starting at 0. This affects where the node appears on the tree, and which resets affect the layer.

     Using "side" instead of a number will cause the layer to appear off to the side as a smaller node (useful for achievements
    +import{_ as e,q as t,p as a,ag as i}from"./chunks/framework.DvHfxfnp.js";const g=JSON.parse('{"title":"Layer Features","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/layer-features.md","filePath":"public/gamedevtree/docs/layer-features.md"}'),s={name:"public/gamedevtree/docs/layer-features.md"},n=i(`

    Layer Features

    This is a more comprehensive list of established features to add to layers. You can add more freely, if you want to have other functions or values associated with your layer. These have special functionality, though.

    You can make almost any value dynamic by using a function in its place, including all display strings and styling/color features.

    Key:

    • No label: This is required and the game will crash if it isn't included.
    • sometimes required: This is may be required, depending on other things in the layer.
    • optional: You can leave this out if you don't intend to use that feature for the layer.

    Layer Definition features

    • layer: Assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar to access the save value. It makes copying code to new layers easier. It is also assigned to all upgrades and buyables and such.

    • name: Optional, used in reset confirmations (and maybe other places). If absent, it just uses the layer's id.

    • startData(): A function to return the default save data for this layer. Add any variables you have to it. Any nonstandard Decimal variables need to be added to convertToDecimal as well. Standard values: Required: unlocked: a bool determining if this layer is unlocked or not points: a Decimal, the main currency for the layer Optional: total: A Decimal, tracks total amount of main prestige currency best: A Decimal, tracks highest amount of main prestige currency unlockOrder: used to keep track of relevant layers unlocked before this one.

    • color: A color associated with this layer, used in many places. (A string in hex format with a #)

    • row: The row of the layer, starting at 0. This affects where the node appears on the tree, and which resets affect the layer.

       Using "side" instead of a number will cause the layer to appear off to the side as a smaller node (useful for achievements
        and statistics). Side layers are not affected by resets unless you add a doReset to them.
       
    • resource: Name of the main currency you gain by resetting on this layer.

    • effect(): optional, A function that calculates and returns the current values of any bonuses inherent to the main currency. Can return a value or an object containing multiple values. You will also have to implement the effect where it is applied.

    • effectDescription: optional, A function that returns a description of this effect. If the text stays constant, it can just be a string.

    • layerShown(): A function returning a bool which determines if this layer's node should be visible on the tree. It can also return "ghost", which will hide the layer, but its node will still take up space in the tree.

    • hotkeys: optional, An array containing information on any hotkeys associated with this layer:

      js
      hotkeys: [
           {key: "p", // What the hotkey button is. Use uppercase if it's combined with shift, or "ctrl+x" if ctrl is.
      diff --git a/assets/public_gamedevtree_docs_layer-features.md.DAMp8TY6.lean.js b/assets/public_gamedevtree_docs_layer-features.md.I54r8Buk.lean.js
      similarity index 72%
      rename from assets/public_gamedevtree_docs_layer-features.md.DAMp8TY6.lean.js
      rename to assets/public_gamedevtree_docs_layer-features.md.I54r8Buk.lean.js
      index 02e9dcfc..ab66c509 100644
      --- a/assets/public_gamedevtree_docs_layer-features.md.DAMp8TY6.lean.js
      +++ b/assets/public_gamedevtree_docs_layer-features.md.I54r8Buk.lean.js
      @@ -1 +1 @@
      -import{_ as e,c as t,o as a,ag as i}from"./chunks/framework.VBE0TPts.js";const g=JSON.parse('{"title":"Layer Features","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/layer-features.md","filePath":"public/gamedevtree/docs/layer-features.md"}'),s={name:"public/gamedevtree/docs/layer-features.md"},n=i("",18),o=[n];function r(l,h,u,p,c,d){return a(),t("div",null,o)}const f=e(s,[["render",r]]);export{g as __pageData,f as default};
      +import{_ as e,q as t,p as a,ag as i}from"./chunks/framework.DvHfxfnp.js";const g=JSON.parse('{"title":"Layer Features","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/layer-features.md","filePath":"public/gamedevtree/docs/layer-features.md"}'),s={name:"public/gamedevtree/docs/layer-features.md"},n=i("",18),o=[n];function r(l,h,u,p,c,d){return a(),t("div",null,o)}const f=e(s,[["render",r]]);export{g as __pageData,f as default};
      diff --git a/assets/public_gamedevtree_docs_main-mod-info.md.DGfpmFPw.js b/assets/public_gamedevtree_docs_main-mod-info.md.SBsEn9C7.js
      similarity index 98%
      rename from assets/public_gamedevtree_docs_main-mod-info.md.DGfpmFPw.js
      rename to assets/public_gamedevtree_docs_main-mod-info.md.SBsEn9C7.js
      index 642a9d80..752046fb 100644
      --- a/assets/public_gamedevtree_docs_main-mod-info.md.DGfpmFPw.js
      +++ b/assets/public_gamedevtree_docs_main-mod-info.md.SBsEn9C7.js
      @@ -1,4 +1,4 @@
      -import{_ as i,c as e,o as t,ag as s}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"mod.js","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/main-mod-info.md","filePath":"public/gamedevtree/docs/main-mod-info.md"}'),a={name:"public/gamedevtree/docs/main-mod-info.md"},n=s(`

      mod.js

      All of the code and data that you're likely to edit is here in mod.js! Everything in mod.js will not be altered by updates, besides the addition of new things.

      Here's a breakdown of what's in it:

      • modInfo is where most of the basic configuration for the mod is. It contains:

        • name: The name of your mod. (a string)
        • id: The id for your mod, a unique string that is used to determine savefile location. Setting it is important!
        • author: The name of the author, displayed in the info tab.
        • pointsName: This changes what is displayed instead of "points" for the main currency. (It does not affect it in the code.)
        • discordName, discordLink: If you have a Discord server or other discussion place, you can add a link to it. "discordName" is the text on the link, and "discordLink" is the url of an invite. If you're using a Discord invite, please make sure it's set to never expire.
        • changelogLink: You can use this to set a link to a page where your changelog for the game is displayed.
        • offlineLimit: The maximum amount of offline time that the player can accumulate, in hours. Any extra time is lost. (a number) This is useful because most of these mods are fast-paced enough that too much offline time ruins the balance, such as the time in between updates. That is why I suggest developers disable offline time on their own savefile.
        • initialStartPoints: A Decimal for the amount of points a new player should start with.
      • VERSION is used to describe the current version of your mod. It contains: num: The mod's version number, displayed at the top right of the tree tab. name: The version's name, displayed alongside the number in the info tab.

      • doNotCallTheseFunctionsEveryTick is very important. TMT calls every function anywhere in "layers" every tick to store the result, unless specifically told not to. Functions that have are used to do an action need to be identified. "Official" functions (those in the documentation) are all fine, but if you make any new ones, add their names to this array.

      js
      // (The ones here are examples, all official functions are already taken care of)
      +import{_ as i,q as e,p as t,ag as s}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"mod.js","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/main-mod-info.md","filePath":"public/gamedevtree/docs/main-mod-info.md"}'),a={name:"public/gamedevtree/docs/main-mod-info.md"},n=s(`

      mod.js

      All of the code and data that you're likely to edit is here in mod.js! Everything in mod.js will not be altered by updates, besides the addition of new things.

      Here's a breakdown of what's in it:

      • modInfo is where most of the basic configuration for the mod is. It contains:

        • name: The name of your mod. (a string)
        • id: The id for your mod, a unique string that is used to determine savefile location. Setting it is important!
        • author: The name of the author, displayed in the info tab.
        • pointsName: This changes what is displayed instead of "points" for the main currency. (It does not affect it in the code.)
        • discordName, discordLink: If you have a Discord server or other discussion place, you can add a link to it. "discordName" is the text on the link, and "discordLink" is the url of an invite. If you're using a Discord invite, please make sure it's set to never expire.
        • changelogLink: You can use this to set a link to a page where your changelog for the game is displayed.
        • offlineLimit: The maximum amount of offline time that the player can accumulate, in hours. Any extra time is lost. (a number) This is useful because most of these mods are fast-paced enough that too much offline time ruins the balance, such as the time in between updates. That is why I suggest developers disable offline time on their own savefile.
        • initialStartPoints: A Decimal for the amount of points a new player should start with.
      • VERSION is used to describe the current version of your mod. It contains: num: The mod's version number, displayed at the top right of the tree tab. name: The version's name, displayed alongside the number in the info tab.

      • doNotCallTheseFunctionsEveryTick is very important. TMT calls every function anywhere in "layers" every tick to store the result, unless specifically told not to. Functions that have are used to do an action need to be identified. "Official" functions (those in the documentation) are all fine, but if you make any new ones, add their names to this array.

      js
      // (The ones here are examples, all official functions are already taken care of)
       var doNotCallTheseFunctionsEveryTick = ["doReset", "buy", "onPurchase", "blowUpEverything"]
      • getStartPoints(): A function to determine the amount of points the player starts with after a reset. (returns a Decimal value)

      • canGenPoints(): A function returning a boolean for if points should be generated. Use this if you want an upgrade to unlock generating points.

      • getPointGen(): A function that calculates your points per second. Anything that affects your point gain should go into the calculation here.

      • addedPlayerData(): A function that returns any non-layer-related data that you want to be added to the save data and "player" object.

      js
      function addedPlayerData() { return {
       	weather: "Yes",
       	happiness: new Decimal(72),
      diff --git a/assets/public_gamedevtree_docs_main-mod-info.md.DGfpmFPw.lean.js b/assets/public_gamedevtree_docs_main-mod-info.md.SBsEn9C7.lean.js
      similarity index 72%
      rename from assets/public_gamedevtree_docs_main-mod-info.md.DGfpmFPw.lean.js
      rename to assets/public_gamedevtree_docs_main-mod-info.md.SBsEn9C7.lean.js
      index 6a24cd67..8c2199a1 100644
      --- a/assets/public_gamedevtree_docs_main-mod-info.md.DGfpmFPw.lean.js
      +++ b/assets/public_gamedevtree_docs_main-mod-info.md.SBsEn9C7.lean.js
      @@ -1 +1 @@
      -import{_ as i,c as e,o as t,ag as s}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"mod.js","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/main-mod-info.md","filePath":"public/gamedevtree/docs/main-mod-info.md"}'),a={name:"public/gamedevtree/docs/main-mod-info.md"},n=s("",10),o=[n];function l(h,r,d,p,u,c){return t(),e("div",null,o)}const y=i(a,[["render",l]]);export{m as __pageData,y as default};
      +import{_ as i,q as e,p as t,ag as s}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"mod.js","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/main-mod-info.md","filePath":"public/gamedevtree/docs/main-mod-info.md"}'),a={name:"public/gamedevtree/docs/main-mod-info.md"},n=s("",10),o=[n];function l(h,r,d,p,u,c){return t(),e("div",null,o)}const y=i(a,[["render",l]]);export{m as __pageData,y as default};
      diff --git a/assets/public_gamedevtree_docs_milestones.md.C9u7zdbl.js b/assets/public_gamedevtree_docs_milestones.md.Idyk5tE3.js
      similarity index 96%
      rename from assets/public_gamedevtree_docs_milestones.md.C9u7zdbl.js
      rename to assets/public_gamedevtree_docs_milestones.md.Idyk5tE3.js
      index 0aa35852..ef28cb32 100644
      --- a/assets/public_gamedevtree_docs_milestones.md.C9u7zdbl.js
      +++ b/assets/public_gamedevtree_docs_milestones.md.Idyk5tE3.js
      @@ -1,4 +1,4 @@
      -import{_ as e,c as s,o as t,ag as i}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"Milestones","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/milestones.md","filePath":"public/gamedevtree/docs/milestones.md"}'),a={name:"public/gamedevtree/docs/milestones.md"},n=i(`

      Milestones

      Milestones are awarded to the player when they meet a certain goal, and give some benefit. Milestones should be formatted like this:

      js
          milestones: {
      +import{_ as e,q as s,p as t,ag as i}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"Milestones","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/milestones.md","filePath":"public/gamedevtree/docs/milestones.md"}'),a={name:"public/gamedevtree/docs/milestones.md"},n=i(`

      Milestones

      Milestones are awarded to the player when they meet a certain goal, and give some benefit. Milestones should be formatted like this:

      js
          milestones: {
               0: {
                   requirementDesc: "123 waffles",
               }
      diff --git a/assets/public_gamedevtree_docs_milestones.md.C9u7zdbl.lean.js b/assets/public_gamedevtree_docs_milestones.md.Idyk5tE3.lean.js
      similarity index 71%
      rename from assets/public_gamedevtree_docs_milestones.md.C9u7zdbl.lean.js
      rename to assets/public_gamedevtree_docs_milestones.md.Idyk5tE3.lean.js
      index d84efd75..1ea3270e 100644
      --- a/assets/public_gamedevtree_docs_milestones.md.C9u7zdbl.lean.js
      +++ b/assets/public_gamedevtree_docs_milestones.md.Idyk5tE3.lean.js
      @@ -1 +1 @@
      -import{_ as e,c as s,o as t,ag as i}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"Milestones","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/milestones.md","filePath":"public/gamedevtree/docs/milestones.md"}'),a={name:"public/gamedevtree/docs/milestones.md"},n=i("",6),o=[n];function l(r,h,p,d,c,u){return t(),s("div",null,o)}const k=e(a,[["render",l]]);export{m as __pageData,k as default};
      +import{_ as e,q as s,p as t,ag as i}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"Milestones","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/milestones.md","filePath":"public/gamedevtree/docs/milestones.md"}'),a={name:"public/gamedevtree/docs/milestones.md"},n=i("",6),o=[n];function l(r,h,p,d,c,u){return t(),s("div",null,o)}const k=e(a,[["render",l]]);export{m as __pageData,k as default};
      diff --git a/assets/public_gamedevtree_docs_subtabs-and-microtabs.md.BUkbEA-K.js b/assets/public_gamedevtree_docs_subtabs-and-microtabs.md.BhlicLTn.js
      similarity index 97%
      rename from assets/public_gamedevtree_docs_subtabs-and-microtabs.md.BUkbEA-K.js
      rename to assets/public_gamedevtree_docs_subtabs-and-microtabs.md.BhlicLTn.js
      index 00055fc6..4217f07c 100644
      --- a/assets/public_gamedevtree_docs_subtabs-and-microtabs.md.BUkbEA-K.js
      +++ b/assets/public_gamedevtree_docs_subtabs-and-microtabs.md.BhlicLTn.js
      @@ -1,4 +1,4 @@
      -import{_ as s,c as a,o as t,ag as i}from"./chunks/framework.VBE0TPts.js";const u=JSON.parse('{"title":"Subtabs and Microtabs","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/subtabs-and-microtabs.md","filePath":"public/gamedevtree/docs/subtabs-and-microtabs.md"}'),e={name:"public/gamedevtree/docs/subtabs-and-microtabs.md"},n=i(`

      Subtabs and Microtabs

      Subtabs are separate sections of a tab that you can view by selecting one at the top of the tab. Microtabs are smaller areas that function in much the same way.

      Subtabs are defined by using the tab format like this, where each element of tabFormat is given the name of that subtab:

      js
          tabFormat: {
      +import{_ as s,q as a,p as t,ag as i}from"./chunks/framework.DvHfxfnp.js";const u=JSON.parse('{"title":"Subtabs and Microtabs","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/subtabs-and-microtabs.md","filePath":"public/gamedevtree/docs/subtabs-and-microtabs.md"}'),e={name:"public/gamedevtree/docs/subtabs-and-microtabs.md"},n=i(`

      Subtabs and Microtabs

      Subtabs are separate sections of a tab that you can view by selecting one at the top of the tab. Microtabs are smaller areas that function in much the same way.

      Subtabs are defined by using the tab format like this, where each element of tabFormat is given the name of that subtab:

      js
          tabFormat: {
               "Main tab": {
                   *subtab features*
               },
      diff --git a/assets/public_gamedevtree_docs_subtabs-and-microtabs.md.BUkbEA-K.lean.js b/assets/public_gamedevtree_docs_subtabs-and-microtabs.md.BhlicLTn.lean.js
      similarity index 74%
      rename from assets/public_gamedevtree_docs_subtabs-and-microtabs.md.BUkbEA-K.lean.js
      rename to assets/public_gamedevtree_docs_subtabs-and-microtabs.md.BhlicLTn.lean.js
      index 1b964483..e0854da3 100644
      --- a/assets/public_gamedevtree_docs_subtabs-and-microtabs.md.BUkbEA-K.lean.js
      +++ b/assets/public_gamedevtree_docs_subtabs-and-microtabs.md.BhlicLTn.lean.js
      @@ -1 +1 @@
      -import{_ as s,c as a,o as t,ag as i}from"./chunks/framework.VBE0TPts.js";const u=JSON.parse('{"title":"Subtabs and Microtabs","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/subtabs-and-microtabs.md","filePath":"public/gamedevtree/docs/subtabs-and-microtabs.md"}'),e={name:"public/gamedevtree/docs/subtabs-and-microtabs.md"},n=i("",9),l=[n];function h(p,r,o,k,c,d){return t(),a("div",null,l)}const E=s(e,[["render",h]]);export{u as __pageData,E as default};
      +import{_ as s,q as a,p as t,ag as i}from"./chunks/framework.DvHfxfnp.js";const u=JSON.parse('{"title":"Subtabs and Microtabs","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/subtabs-and-microtabs.md","filePath":"public/gamedevtree/docs/subtabs-and-microtabs.md"}'),e={name:"public/gamedevtree/docs/subtabs-and-microtabs.md"},n=i("",9),l=[n];function h(p,r,o,k,c,d){return t(),a("div",null,l)}const E=s(e,[["render",h]]);export{u as __pageData,E as default};
      diff --git a/assets/public_gamedevtree_docs_updating-tmt.md.B1_CRXZy.js b/assets/public_gamedevtree_docs_updating-tmt.md.Clk0TMnI.js
      similarity index 94%
      rename from assets/public_gamedevtree_docs_updating-tmt.md.B1_CRXZy.js
      rename to assets/public_gamedevtree_docs_updating-tmt.md.Clk0TMnI.js
      index c43e088d..88aece87 100644
      --- a/assets/public_gamedevtree_docs_updating-tmt.md.B1_CRXZy.js
      +++ b/assets/public_gamedevtree_docs_updating-tmt.md.Clk0TMnI.js
      @@ -1 +1 @@
      -import{_ as e,c as t,o as a,ag as o}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"Updating The Modding Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/updating-tmt.md","filePath":"public/gamedevtree/docs/updating-tmt.md"}'),i={name:"public/gamedevtree/docs/updating-tmt.md"},n=o('

      Updating The Modding Tree

      This tutorial assumes that you have used the Getting Started Tutorial, and are using Github Desktop and VSCode for your mod.

      Here's what you have to do when there's a TMT update:

      1. Look at the changelog. It will warn you if the update will break anything or require any changes. Decide if you want to try to update.

      2. Open Github Desktop, and at the top middle, click "fetch origin". This will make Github Desktop get information about the update.

      3. Click where it says "current branch: master" at the top middle, and at the bottom of the thing that appears, click "choose a branch to merge into master.

      4. Select upstream/master. It will likely say there are conflicts, but you have tools to resolve them. Click "Merge upstream/master into master".

      5. A conflict happens when the things you're trying to merge have both made changes in the same place. Click "open in Visual Studio Code" next to the first file.

      6. Scroll down through the file, and look for the parts highlighted in red and green. One of these is your code, and the other is some code that will be modified by the update. Do your best to try to edit things to keep the updated changes, but keep your content.

      7. Continue to do this for all remaining challenges.

      8. Do any other changes required by the update, run the game, fix issues, etc.

      ',4),r=[n];function d(h,s,l,p,u,c){return a(),t("div",null,r)}const _=e(i,[["render",d]]);export{m as __pageData,_ as default}; +import{_ as e,q as t,p as a,ag as o}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"Updating The Modding Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/updating-tmt.md","filePath":"public/gamedevtree/docs/updating-tmt.md"}'),i={name:"public/gamedevtree/docs/updating-tmt.md"},n=o('

      Updating The Modding Tree

      This tutorial assumes that you have used the Getting Started Tutorial, and are using Github Desktop and VSCode for your mod.

      Here's what you have to do when there's a TMT update:

      1. Look at the changelog. It will warn you if the update will break anything or require any changes. Decide if you want to try to update.

      2. Open Github Desktop, and at the top middle, click "fetch origin". This will make Github Desktop get information about the update.

      3. Click where it says "current branch: master" at the top middle, and at the bottom of the thing that appears, click "choose a branch to merge into master.

      4. Select upstream/master. It will likely say there are conflicts, but you have tools to resolve them. Click "Merge upstream/master into master".

      5. A conflict happens when the things you're trying to merge have both made changes in the same place. Click "open in Visual Studio Code" next to the first file.

      6. Scroll down through the file, and look for the parts highlighted in red and green. One of these is your code, and the other is some code that will be modified by the update. Do your best to try to edit things to keep the updated changes, but keep your content.

      7. Continue to do this for all remaining challenges.

      8. Do any other changes required by the update, run the game, fix issues, etc.

      ',4),r=[n];function d(h,s,l,p,u,c){return a(),t("div",null,r)}const _=e(i,[["render",d]]);export{m as __pageData,_ as default}; diff --git a/assets/public_gamedevtree_docs_updating-tmt.md.B1_CRXZy.lean.js b/assets/public_gamedevtree_docs_updating-tmt.md.Clk0TMnI.lean.js similarity index 72% rename from assets/public_gamedevtree_docs_updating-tmt.md.B1_CRXZy.lean.js rename to assets/public_gamedevtree_docs_updating-tmt.md.Clk0TMnI.lean.js index 616fd50a..a933e8a1 100644 --- a/assets/public_gamedevtree_docs_updating-tmt.md.B1_CRXZy.lean.js +++ b/assets/public_gamedevtree_docs_updating-tmt.md.Clk0TMnI.lean.js @@ -1 +1 @@ -import{_ as e,c as t,o as a,ag as o}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"Updating The Modding Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/updating-tmt.md","filePath":"public/gamedevtree/docs/updating-tmt.md"}'),i={name:"public/gamedevtree/docs/updating-tmt.md"},n=o("",4),r=[n];function d(h,s,l,p,u,c){return a(),t("div",null,r)}const _=e(i,[["render",d]]);export{m as __pageData,_ as default}; +import{_ as e,q as t,p as a,ag as o}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"Updating The Modding Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/updating-tmt.md","filePath":"public/gamedevtree/docs/updating-tmt.md"}'),i={name:"public/gamedevtree/docs/updating-tmt.md"},n=o("",4),r=[n];function d(h,s,l,p,u,c){return a(),t("div",null,r)}const _=e(i,[["render",d]]);export{m as __pageData,_ as default}; diff --git a/assets/public_gamedevtree_docs_upgrades.md.DuL26i8s.js b/assets/public_gamedevtree_docs_upgrades.md.BspSzPzA.js similarity index 97% rename from assets/public_gamedevtree_docs_upgrades.md.DuL26i8s.js rename to assets/public_gamedevtree_docs_upgrades.md.BspSzPzA.js index b5bc8c6f..9ddd602c 100644 --- a/assets/public_gamedevtree_docs_upgrades.md.DuL26i8s.js +++ b/assets/public_gamedevtree_docs_upgrades.md.BspSzPzA.js @@ -1,4 +1,4 @@ -import{_ as e,c as s,o as t,ag as a}from"./chunks/framework.VBE0TPts.js";const f=JSON.parse('{"title":"Upgrades","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/upgrades.md","filePath":"public/gamedevtree/docs/upgrades.md"}'),i={name:"public/gamedevtree/docs/upgrades.md"},n=a(`

      Upgrades

      Useful functions for dealing with Upgrades and implementing their effects:

      • hasUpgrade(layer, id): determine if the player has the upgrade
      • upgradeEffect(layer, id): Returns the current effects of the upgrade, if any
      • buyUpgrade(layer, id): Buys an upgrade directly (if affordable)

      Hint: Basic point gain is calculated in mod.js's "getPointGen".

      Upgrades are stored in the following format:

      js
          upgrades: {
      +import{_ as e,q as s,p as t,ag as a}from"./chunks/framework.DvHfxfnp.js";const f=JSON.parse('{"title":"Upgrades","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/upgrades.md","filePath":"public/gamedevtree/docs/upgrades.md"}'),i={name:"public/gamedevtree/docs/upgrades.md"},n=a(`

      Upgrades

      Useful functions for dealing with Upgrades and implementing their effects:

      • hasUpgrade(layer, id): determine if the player has the upgrade
      • upgradeEffect(layer, id): Returns the current effects of the upgrade, if any
      • buyUpgrade(layer, id): Buys an upgrade directly (if affordable)

      Hint: Basic point gain is calculated in mod.js's "getPointGen".

      Upgrades are stored in the following format:

      js
          upgrades: {
               rows: # of rows
               cols: # of columns
               11: {
      diff --git a/assets/public_gamedevtree_docs_upgrades.md.DuL26i8s.lean.js b/assets/public_gamedevtree_docs_upgrades.md.BspSzPzA.lean.js
      similarity index 71%
      rename from assets/public_gamedevtree_docs_upgrades.md.DuL26i8s.lean.js
      rename to assets/public_gamedevtree_docs_upgrades.md.BspSzPzA.lean.js
      index d72d091e..f7a7f441 100644
      --- a/assets/public_gamedevtree_docs_upgrades.md.DuL26i8s.lean.js
      +++ b/assets/public_gamedevtree_docs_upgrades.md.BspSzPzA.lean.js
      @@ -1 +1 @@
      -import{_ as e,c as s,o as t,ag as a}from"./chunks/framework.VBE0TPts.js";const f=JSON.parse('{"title":"Upgrades","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/upgrades.md","filePath":"public/gamedevtree/docs/upgrades.md"}'),i={name:"public/gamedevtree/docs/upgrades.md"},n=a("",10),r=[n];function l(o,p,h,d,u,c){return t(),s("div",null,r)}const y=e(i,[["render",l]]);export{f as __pageData,y as default};
      +import{_ as e,q as s,p as t,ag as a}from"./chunks/framework.DvHfxfnp.js";const f=JSON.parse('{"title":"Upgrades","description":"","frontmatter":{},"headers":[],"relativePath":"public/gamedevtree/docs/upgrades.md","filePath":"public/gamedevtree/docs/upgrades.md"}'),i={name:"public/gamedevtree/docs/upgrades.md"},n=a("",10),r=[n];function l(o,p,h,d,u,c){return t(),s("div",null,r)}const y=e(i,[["render",l]]);export{f as __pageData,y as default};
      diff --git a/assets/public_kronos_Old Things_2.0-format-changes.md.DAyzd7AX.js b/assets/public_kronos_Old Things_2.0-format-changes.md.BM0FXptY.js
      similarity index 90%
      rename from assets/public_kronos_Old Things_2.0-format-changes.md.DAyzd7AX.js
      rename to assets/public_kronos_Old Things_2.0-format-changes.md.BM0FXptY.js
      index b15e135e..2d4b8764 100644
      --- a/assets/public_kronos_Old Things_2.0-format-changes.md.DAyzd7AX.js	
      +++ b/assets/public_kronos_Old Things_2.0-format-changes.md.BM0FXptY.js	
      @@ -1 +1 @@
      -import{_ as e,c as a,o as t,ag as o}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"2.0 format changes","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/Old Things/2.0-format-changes.md","filePath":"public/kronos/Old Things/2.0-format-changes.md"}'),n={name:"public/kronos/Old Things/2.0-format-changes.md"},i=o('

      2.0 format changes

      • Temp format is changed from temp.something[layer] to temp[layer].something, for consistency
      • Challenges are now saved as an object with the amount of completions in each spot. (This will break saves.)
      • effectDisplay in Challenges and Upgrades no longer takes an argument, and neither does effect for Buyables
      • Buyable cost can take an argument for amount of buyables, but it needs to function if no argument is supplied (it should do the cost for the next purchase).
      • Generation of Points now happens in the main game loop (not in a layer update function), enabled by canGenPoints in game.js.
      • Changed fullLayerReset to layerDataReset, which takes an array of names of values to keep

      In addition, many names were changed, mostly expanding abbreviations:

      All instances of:

      • chall -> challenge
      • unl -> unlocked
      • upg -> upgrade (besides CSS)
      • amt -> amount
      • desc -> description
      • resCeil -> roundUpCost
      • order -> unlockOrder
      • incr_order -> increaseUnlockOrder

      Challenges:

      • desc -> challengeDescription
      • reward -> rewardDescription
      • effect -> rewardEffect
      • effectDisplay -> rewardDisplay
      • active -> challengeActive
      ',7),l=[i];function s(r,c,d,g,h,f){return t(),a("div",null,l)}const u=e(n,[["render",s]]);export{m as __pageData,u as default}; +import{_ as e,q as a,p as t,ag as o}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"2.0 format changes","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/Old Things/2.0-format-changes.md","filePath":"public/kronos/Old Things/2.0-format-changes.md"}'),n={name:"public/kronos/Old Things/2.0-format-changes.md"},i=o('

      2.0 format changes

      • Temp format is changed from temp.something[layer] to temp[layer].something, for consistency
      • Challenges are now saved as an object with the amount of completions in each spot. (This will break saves.)
      • effectDisplay in Challenges and Upgrades no longer takes an argument, and neither does effect for Buyables
      • Buyable cost can take an argument for amount of buyables, but it needs to function if no argument is supplied (it should do the cost for the next purchase).
      • Generation of Points now happens in the main game loop (not in a layer update function), enabled by canGenPoints in game.js.
      • Changed fullLayerReset to layerDataReset, which takes an array of names of values to keep

      In addition, many names were changed, mostly expanding abbreviations:

      All instances of:

      • chall -> challenge
      • unl -> unlocked
      • upg -> upgrade (besides CSS)
      • amt -> amount
      • desc -> description
      • resCeil -> roundUpCost
      • order -> unlockOrder
      • incr_order -> increaseUnlockOrder

      Challenges:

      • desc -> challengeDescription
      • reward -> rewardDescription
      • effect -> rewardEffect
      • effectDisplay -> rewardDisplay
      • active -> challengeActive
      ',7),l=[i];function s(r,c,d,g,h,p){return t(),a("div",null,l)}const u=e(n,[["render",s]]);export{m as __pageData,u as default}; diff --git a/assets/public_kronos_Old Things_2.0-format-changes.md.DAyzd7AX.lean.js b/assets/public_kronos_Old Things_2.0-format-changes.md.BM0FXptY.lean.js similarity index 60% rename from assets/public_kronos_Old Things_2.0-format-changes.md.DAyzd7AX.lean.js rename to assets/public_kronos_Old Things_2.0-format-changes.md.BM0FXptY.lean.js index 9316a80e..7d702ff7 100644 --- a/assets/public_kronos_Old Things_2.0-format-changes.md.DAyzd7AX.lean.js +++ b/assets/public_kronos_Old Things_2.0-format-changes.md.BM0FXptY.lean.js @@ -1 +1 @@ -import{_ as e,c as a,o as t,ag as o}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"2.0 format changes","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/Old Things/2.0-format-changes.md","filePath":"public/kronos/Old Things/2.0-format-changes.md"}'),n={name:"public/kronos/Old Things/2.0-format-changes.md"},i=o("",7),l=[i];function s(r,c,d,g,h,f){return t(),a("div",null,l)}const u=e(n,[["render",s]]);export{m as __pageData,u as default}; +import{_ as e,q as a,p as t,ag as o}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"2.0 format changes","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/Old Things/2.0-format-changes.md","filePath":"public/kronos/Old Things/2.0-format-changes.md"}'),n={name:"public/kronos/Old Things/2.0-format-changes.md"},i=o("",7),l=[i];function s(r,c,d,g,h,p){return t(),a("div",null,l)}const u=e(n,[["render",s]]);export{m as __pageData,u as default}; diff --git a/assets/public_kronos_README.md.DR8w07T9.js b/assets/public_kronos_README.md.zcQPLTsl.js similarity index 85% rename from assets/public_kronos_README.md.DR8w07T9.js rename to assets/public_kronos_README.md.zcQPLTsl.js index a7ec34b1..393e2f78 100644 --- a/assets/public_kronos_README.md.DR8w07T9.js +++ b/assets/public_kronos_README.md.zcQPLTsl.js @@ -1 +1 @@ -import{_ as e,c as o,o as t,ag as r}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"Kronos","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/README.md","filePath":"public/kronos/README.md"}'),a={name:"public/kronos/README.md"},s=r('

      Kronos

      Play here.

      Updating the website:

      • git submodule update --remote
      • git add -A
      • git commit -m "Updated kronos"
      • git push
      ',4),i=[s];function n(c,d,l,_,p,u){return t(),o("div",null,i)}const f=e(a,[["render",n]]);export{m as __pageData,f as default}; +import{_ as e,q as o,p as t,ag as r}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"Kronos","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/README.md","filePath":"public/kronos/README.md"}'),a={name:"public/kronos/README.md"},s=r('

      Kronos

      Play here.

      Updating the website:

      • git submodule update --remote
      • git add -A
      • git commit -m "Updated kronos"
      • git push
      ',4),i=[s];function n(c,d,l,_,p,u){return t(),o("div",null,i)}const f=e(a,[["render",n]]);export{m as __pageData,f as default}; diff --git a/assets/public_kronos_README.md.DR8w07T9.lean.js b/assets/public_kronos_README.md.zcQPLTsl.lean.js similarity index 68% rename from assets/public_kronos_README.md.DR8w07T9.lean.js rename to assets/public_kronos_README.md.zcQPLTsl.lean.js index 44b78fbb..70f433cb 100644 --- a/assets/public_kronos_README.md.DR8w07T9.lean.js +++ b/assets/public_kronos_README.md.zcQPLTsl.lean.js @@ -1 +1 @@ -import{_ as e,c as o,o as t,ag as r}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"Kronos","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/README.md","filePath":"public/kronos/README.md"}'),a={name:"public/kronos/README.md"},s=r("",4),i=[s];function n(c,d,l,_,p,u){return t(),o("div",null,i)}const f=e(a,[["render",n]]);export{m as __pageData,f as default}; +import{_ as e,q as o,p as t,ag as r}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"Kronos","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/README.md","filePath":"public/kronos/README.md"}'),a={name:"public/kronos/README.md"},s=r("",4),i=[s];function n(c,d,l,_,p,u){return t(),o("div",null,i)}const f=e(a,[["render",n]]);export{m as __pageData,f as default}; diff --git a/assets/public_kronos_changelog.md._RxA7rHJ.js b/assets/public_kronos_changelog.md.BB6U1JML.js similarity index 99% rename from assets/public_kronos_changelog.md._RxA7rHJ.js rename to assets/public_kronos_changelog.md.BB6U1JML.js index b7913716..a0711e35 100644 --- a/assets/public_kronos_changelog.md._RxA7rHJ.js +++ b/assets/public_kronos_changelog.md.BB6U1JML.js @@ -1 +1 @@ -import{_ as e,c as i,o as a,ag as l}from"./chunks/framework.VBE0TPts.js";const b=JSON.parse('{"title":"The Modding Tree changelog:","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/changelog.md","filePath":"public/kronos/changelog.md"}'),t={name:"public/kronos/changelog.md"},o=l('

      The Modding Tree changelog:

      v2.5.9.2 - 5/19/21

      • Fixed many issues with things not updating.

      v2.5.9.1 - 5/18/21

      • Made text inputs never give NaNs.

      v2.5.9 - 5/18/21

      • Fixed issue when using text inputs for Numbers.
      • Added particle color feature.
      • Particle speed and dir are updated as it moves.
      • Added setSpeed and setDir for particles.
      • Added more trig functions.

      v2.5.8 - 5/17/21

      • Added makeShinies, which creates a stationary particle in a random spot.
      • Bars will visually update more quickly.
      • Fixed a major particle-related issue.
      • Fixed autoUpgrade.
      • Fixed a minor visual issue with tree nodes.

      v2.5.7 - 5/15/21

      • Added a particle system! Not only can it be used for visual effects, but particles can interact with the mouse. They could be used to create golden cookies or collectables, for example.
      • Added marked feature to buyables, clickables, and challenges. By default, stars multi-completion challenges when maxed.
      • Added 'deactivated' feature to layers, which disables many features.
      • Improved number formatting slightly.

      v2.5.6 - 5/14/21

      • You can now use non-numeric ids for upgrades, buyables, etc.
      • Fixed an exploit that let you buy an extra buyable.
      • Moved basic getter/setter functions to easyAccess.js.

      v2.5.5.2 - 5/12/21

      • Fixed a major issue with buyables.
      • Fixed a variety of tabFormat-related issues.
      • Fixed commas appearing in decimal places (thanks to pg132!)

      v2.5.5.1 - 5/12/21

      • Fixed clickables.

      v2.5.5 - 5/12/21

      • Added grids! They are a grid of buttons which behave the same, but have their own data. Good for inventory grids, map tiles, and more!
      • Added "marked" feature to add a mark to a node. Can be an image instead of a star. (Originally by Jacorb)
      • Added "layer-proxy" component that lets you use components from another layer.
      • Added the ability to display non-whole numbers in main-display.

      v2.5.4 - 5/10/21

      • Added a setting to always use single-tab mode.
      • Added directMult, which multiplies prestige gain after exponents and softcaps. It actually multiplies gain for static layers.
      • Added onEnter and onExit for challenges.
      • Improved displaying numbers between 0.0001 and 0.1.
      • Added documentation on how gainMult/Exp work for static layers.
      • Fixed a visual issue on mobile, thanks to thepaperpilot.
      • Improved documentation in general.

      v2.5.3 - 5/8/21

      • Improved performance of tab formats and bars.
      • Respec confirmation settings are now kept on resets.
      • Improved compatibility with older browsers.
      • Fixed missing pixel on vertical bars.

      v2.5.2.1 - 5/7/21

      • Fixed microtabs making layers highlight incorrectly.

      v2.5.2 - 5/7/21

      • Added glowColor for subtabs.
      • Improved the display for extremely small numbers.
      • Fixed issues in the buyable docs.

      v2.5.1 - 5/7/21

      • Fixed dynamic things in tabFormat not updating.

      v2.5: Dreams Really Do Come True - 5/7/21

      • Optimizations, hopefully a significant amount.
      • Added OOM/s point gen display at high values (thanks to Ducdat!)
      • Only one tab will display if the window is not wide enough (also thanks to Ducdat!)
      • Holding down a buyable's button now buys it continuously.
      • New milestone setting will also show the most recently unlocked milestone. (Also renamed all settings to be clearer)
      • Added an onHold feature for clickables.
      • Layer nodes will be highlighted even if the player is on the same tab.
      • Added customizable node glowColor.
      • Added buyable purchaseLimit.
      • Amount is automatically supplied to buyable cost and effect functions.
      • Locked (not yet visible) milestones no longer take up space. Also fixed hidden milestones taking a tiny bit of space.
      • Re-centered respec buttons.
      • Force-displayed tooltips are not hidden by resets.
      • Added formatting support for very small numbers. Disabled in most places by default because rounding errors might cause issues. Access it with formatSmall, or enable it globally by adding "allowSmall: true" to modInfo.

      v2.4.1 - 4/29/21

      • A number of minor fixes, many thanks to thepaperpilot.
      • The respec confirmation checkbox is now part of the respec-button component. (This also fixes the checkbox appearing when there is no respec button)
      • Added a few undocumented changes to the 2.4 changelog (the two at the bottom)

      v2.4: Rationalized Edition - 4/29/21

      • Completely reworked tooltips. Shift-click a node to force its tooltip to stay displayed. (And hopefully finally fixed flickering!)

      • Added text-input and slider components.

      • Added the ability to toggle respec confirmations.

      • Added custom respec confirmation messages.

      • The red layer highlight will not appear before a layer is unlocked.

      • Added unlocking hotkeys.

      • You no longer need to supply 'rows' and 'cols' for any Big Features.

      • Node symbols can use HTML.

      • Added documentation for the respec button.

      • Added prestigeNotify to subtabs, and prestigeNotify in subtabs also highlights the layer node.

      • The version number no longer contains special characters or irrational numbers.

      • Added ctrlDown and shiftDown variables.

      • Tooltips now use HTML (this means you need to replace any newlines with
        )

      v2.π.1 - 4/7/21

      • Fixed formatting for some larger numbers.
      • Upgrades will expand if there is too much text to display.
      • Fixed styling challenges.
      • No longer attempts to display a base currency when there is none.

      v2.π: Incrementally Updated - 2/5/21

      • Performance improvements.
      • Fixed tooltips overlapping with the top display.
      • Clicking a popup dismisses it immediately.
      • Added support for bulk challenge completions.
      • "Best" is updated automatically.
      • Fixed keeping Decimal values on reset.
      • Code reorganization and style improvements by fudo.

      v2.3.5 - 12/21/20

      • Added resetTime, which tracks the time since a layer prestiged or was reset.
      • A layer node will be highlighted red if one of its subtabs is highlighted red.
      • Fixed issues with keeping challenges, buyables, and clickables on reset.
      • Improved the unlocking of custom layers.
      • Other minor fixes.

      v2.3.4 - 12/16/20

      • Added a node image feature.
      • Resource display now always shows the amount of the currency the layer's gain is based on.
      • Added spacing between tree nodes.
      • Another attempt to fix tooltip flickering.

      v2.3.3 - 12/13/20

      • Fixed the first node in a row always taking up space.
      • layerShown is now optional.
      • All prestige types can now use features for custom prestige types.

      v2.3.2 - 12/13/20

      • Fixed achievement/milestone popups.

      v2.3.1 - 12/12/20

      • Another attempt to fix flickering tooltips.
      • The "this" keyword should work everywhere except tabFormat arrays (although I may have missed some things).
      • Fixed tree branches not updating when scrolling on the right-side tab.
      • Fixed a spacing issue when a node's symbol is ""
      • Removed some old, unneeded files.

      v2.3: Cooler and Newer Edition - 12/10/20

      • Added achievement/milestone popups (thank you to Jacorb for this contribution!)
      • The changelog tab is back, and can be set in mod.js.
      • Layer nodes and respec buttons will not be clicked by pressing "enter".
      • Possible fix for flickering tooltips and strange transitions.
      • The victory screen text is configurable.
      • Added image and textStyle features to achievements.
      • Added an argument to use specific rows in an "upgrades" component.
      • Fixed the comma appearing in the main display when there was no effectDescription
      • Added the ability to easily make a tab that is a collection of layers in subtabs.
      • Improved spacing for embedding layers with subtabs into subtabs.

      v2.2.8 - 12/03/20

      • Double-clicking a layer node brings you to the main subtab for that layer.
      • Attempted to fix challenges visually updating a different way.
      • Added a softcap function for use in formulas.
      • Added displayRow feature, which lets layers be shown somewhere separate from where they are in the reset order (e.g. side layers)
      • Fixed autoupgrade issue.

      v2.2.7 - 11/30/20

      • Added autoUpgrade feature.
      • resource-display now shows resource gain per second if passiveGain is active.
      • Fixed formatting issues on some large numbers.
      • Better support for using classed objects in player and in layers/tmp.
      • Made hard resetting more effective.
      • Removed Herobrine from getStartClickables.

      v2.2.6 - 11/30/20

      • Added goalDescription for challenges and made the new "canComplete" system the standard.
      • Another attempt to fix challenges not visually updating.
      • Fixed side layers not appearing.
      • Fixed getStartClickables again.

      v2.2.5 - 11/29/20

      • Added features for overriding the displays and costs/goals of upgrades and challenges to make them fully custom.
      • best, total, and unlocked are always automatically added to layerData (but best and total will only display if you add them yourself).
      • Fixed getStartClickables.

      v2.2.4 - 11/28/20

      • Added softcap and softcapPower features (for Normal layers)
      • Offline time limit and default max tick length were fixed (previously the limits were 1000x too large)
      • Added fixOldSaves.
      • You can use HTML in main-display.
      • Fixed a number of minor oddities.

      v2.2.3 - 11/28/20

      • Layers will be highlighted if you can finish a challenge.
      • The "can complete challenge" color now overrides the "already completed" color.
      • Button nodes now work as side "layers".
      • Setting a tooltip to "" hides it entirely.

      v2.2.2 - 11/22/20

      • Fixed right half of the screen being unclickable in some circumstances.
      • Fixed tree branches being offset.
      • Fix to lastSafeTab.

      v2.2.1 - 11/7/20

      • Added a small highlight to layers you can meaningfully prestige on.
      • Added passiveGeneration and autoPrestige features to standardize prestige automation. (The old ways still work, but the new ones work better with other things)
      • Improved milestones visually a bit.
      • "best" and "total" are now only displayed if present in startData.
      • Fixed issues with things not updating visually. (Thank you to to Jacorb!)
      • Side layers and button nodes can now be highlighted.
      • Updated docs on the new tree-related features.

      v2.2: Uprooted - 11/7/20

      • You can now embed a layer inside of a subtab or microtab!
      • Added support for hiding or reformatting the tree tab
      • Added non-layer button nodes
      • Added shouldNotify to subtab/microtab buttons. (You can make them highlighted)
      • Added commas to large exponents.
      • Upgrades now only show "currently" if they have an effectDisplay (so not for constant effects).
      • Achievements are part of the default tab format.
      • NaN is now handled more intelligently.
      • Renamed files, and moved less relevant ones to another folder.
      • The "hide completed challenges" setting now only hides challenges at max completions.
      • Thank you to thepaperpilot for fixing errors in docs and improving the infobox appearance!
      • Many other minor fixes.

      v2.1.4 - 10/25/20

      • Added an infobox component. Thank you to thepaperpilot for this contribution!
      • Layer type is now optional, and defaults to "none".
      • Improved the look of bars and tab buttons.
      • Improved spacing between layer nodes (also thanks to thepaperpilot!)
      • Fixed the "blank" component breaking if only specifying the height.
      • Fixed some numbers not displaying with enough digits.
      • Made a few more things able to be functions.
      • A few other minor fixes.

      v2.1.3.1 - 10/21/20

      • Fixed the update function.

      v2.1.3 - 10/21/20

      • gainMult and gainExp are now optional.
      • Layer unlocking is now kept on reset.
      • Game should start up faster.
      • Layer updates now have a determined order and starts with earlier-rowed layers.
      • Automation now has a determined order and starts with later-rowed layers.
      • Fixed issues with resetting clickables and challenges.
      • Commas should no longer appear in the decimal places of a number.
      • Fixed potential issue in displaying the tree.

      v2.1.2 - 10/19/20

      • Added buyUpgrade function (buyUpg still works though)
      • Added author name to modInfo.
      • Fix to crash caused when the name of a subtab or microtab is changed.
      • Fixes to outdated information in docs.
      • Improvements to Discord links.
      • Thank you to thepaperpilot for contributing to this update!

      v2.1.1 - 10/17/20

      • Added resource-display component, which displays the base currency for the prestige layer, as well as the best and/or total of this layer's prestige currency.
      • Fixed the value for the base currency not updating in resource-display.

      v2.1: We should have thought of this sooner! - 10/17/20

      • Moved most of the code users will want to edit to mod.js, added documentation for it.
        • Specifically, modInfo, VERSION, canGenPoints, getPointGen, and maxTickLength
      • Added getStartPoints()
      • Added the ability to store non-layer-related data
      • Added the ability to display more things at the top of the tree tab below points.
      • Made the endgame condition customizable
      • Added "sell one" and "sell all" buttons for buyables.
      • Moved the old "game" to demo.js, and replaced it with a minimal game that won't cause issues when edited.
      • Fixed issues with version number
      • Fixed number formatting issue making things like "10e9" appear.

      v2.0.5 - 10/16/20

      • Made more features (including prestige parameters) able to be dynamic.
      • Layer nodes can be hidden but still take up space with "ghost" visibility
      • Added clickableEffect for real.
      • Fixed some visual issues with bars.
      • A few other minor tweaks and improvements.

      v2.0.4 - 10/16/20

      • Fixed HTML on buttons interfering with clicking on them.

      v2.0.3 - 10/16/20

      • Fixed hotkeys not displaying in info.
      • Fixed the game supressing all external hotkeys.
      • You can use more things as currencies for upgrade costs and challenge goals using currencyLocation.
      • Added maxTickLength, which can be used to prevent offline time or tab-switching from breaking time-limit based mechanics.
      • Made buyable respec buttons and clickable "master" buttons their own components, and gave them a hide/show feature.
      • Added a general "tooltip" feature for achievements.

      v2.0.2 - 10/15/20

      • Branches are now dynamic (they can be functions).
      • Fixed a crash related to offline time.
      • Fixed links being too wide.

      v2.0.1 - 10/15/20

      • Fixed side layers appearing multiple times.

      v2.0: The Pinnacle of Achievement Mountain - 10/15/20

      • Added progress bars, which are highly customizable and can be horizontal or vertical!
      • Added "side layers", displayed smaller and off to the side, and don't get reset by default. They can be used for global achievements and statistics. Speaking of which...
      • Added achievements!
      • Added clickables, a more generalized variant of buyables.
      • Almost every value in layer data can be either a function or a constant value!
      • Added support for multiple completions of challenges.
      • Added "none" prestige type, which removes the need for any other prestige-related features.
      • The points display and other gui elements stay at the top of the screen when the tree scrolls.
      • Added getter/setter functions for the amounts and effects of most Big Features
      • Moved modInfo to game.js, added a spot in modInfo for a Discord link, changelog link. Also added a separate mod version from the TMT version in VERSION.
      • Tree structure is based on layer data, no index.html editing is needed.
      • Tmp does not need to be manually updated.
      • You don't have to have the same amount of upgrades in every row (and challs and buyables)
      • "unlocked" is optional for all Big Components (defaults to true).
      • All displays will update correctly.
      • Changelog is no longer in index.html at all.
      • Generation of Points now happens in the main game loop
      • Changed the reset functions to make keeping things easier
      • Renamed many things to increase readability (see the list in the link below)
      • Improved documentation based on feedback

      v1.3.5:

      • Completely automated convertToDecimal, now you never have to worry about it again.
      • Branches can be defined without a color id. But they can also use hex values for color ids!
      • Created a tutorial for getting started with TMT and Github.
      • Page title is now automatically taken from mod name.

      v1.3.4 - 10/8/20

      • Added "midsection" feature to add things to a tab's layout while still keeping the standard layout.
      • Fix for being able to buy more buyables than you should.

      v1.3.3 - 10/7/20

      • Fix for the "order of operations" issue in temp.

      v1.3.1 - 10/7/20

      • Added custom CSS and tooltips for Layer Nodes.
      • Added custom CSS for upgrades, buyables, milestones, and challenges, both individually and layer-wide.
      • You can now use HTML in most display text!
      • You can now make milestones unlockable and not display immediately.
      • Fixed importing saves, and issue with upgrades not appearing, and probably more.
      • Optional "name" layer feature, used in confirmation messages.

      v1.3: Tabception... ception! - 10/7/20

      • Added subtabs! And also a Micro-tab component to let you make smaller subtab-esque areas anywhere.
      • Added a "custom" prestige formula type, and a number of features to support it.
      • Added points/sec display (can be disabled).
      • Added h-line, v-line and image-display components, plus components for individual upgrades, challenges, and milestones.
      • Added upgEffect, buyableEffect, and challEffect functions.
      • Added "hide completed challenges" setting.
      • Moved old changelogs to a separate place.
      • Fixed hasMilestone and incr_order.
      • Static layers now show the currency amount needed for the next one if you can buy max.

      v1.2.4 - 10/4/20

      • Layers are now highlighted if you can buy an upgrade, and a new feature, shouldNotify, lets you make it highlight other ways.
      • Fixed bugs with hasUpg, hasChall, hasMilestone, and inChallenge.
      • Changed the sample code to use the above functions for convenience.

      v1.2.3 - 10/3/20

      • Added a row component, which displays a list of objects in a row.
      • Added a column component, which displays a list of objects in a column (useful within a row).
      • Changed blanks to have a customizable width and height.

      v1.2: This Changes Everything! - 10/3/20

      • Many layer features can now be static values or functions. (This made some formats change, which will break old things)
      • You can now use the "this" keyword, to make code easier to transfer when making new layers.
      • Also added "this.layer", which is the current layer's name, and works on existing subfeatures (e.g. individual upgrades) as well! Subfeatures also have "this.id".
      • Fixed a big save issue. If you use a unique mod id, your save will never conflict with other mods.
      • Added a configurable offline time limit in modinfo at the top of index.html. (default 1 hour)
      • Added a few minor features, and updated the docs with new information.

      v1.1.1 - 9/30/20

      • You can define hotkeys directly from layer config.

      v1.1: Enhanced Edition - 9/30/20

      • Added "Buyables", which can function like Space Buildings or Enhancers.
      • Custom CSS can now be used on any component! Make the third argument an object with CSS parameters.
      • Lots of minor good things.

      v1.0 - 9/27/20

      • First release.
      ',115),n=[o];function r(s,d,h,u,c,m){return a(),i("div",null,n)}const f=e(t,[["render",r]]);export{b as __pageData,f as default}; +import{_ as e,q as i,p as a,ag as l}from"./chunks/framework.DvHfxfnp.js";const b=JSON.parse('{"title":"The Modding Tree changelog:","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/changelog.md","filePath":"public/kronos/changelog.md"}'),t={name:"public/kronos/changelog.md"},o=l('

      The Modding Tree changelog:

      v2.5.9.2 - 5/19/21

      • Fixed many issues with things not updating.

      v2.5.9.1 - 5/18/21

      • Made text inputs never give NaNs.

      v2.5.9 - 5/18/21

      • Fixed issue when using text inputs for Numbers.
      • Added particle color feature.
      • Particle speed and dir are updated as it moves.
      • Added setSpeed and setDir for particles.
      • Added more trig functions.

      v2.5.8 - 5/17/21

      • Added makeShinies, which creates a stationary particle in a random spot.
      • Bars will visually update more quickly.
      • Fixed a major particle-related issue.
      • Fixed autoUpgrade.
      • Fixed a minor visual issue with tree nodes.

      v2.5.7 - 5/15/21

      • Added a particle system! Not only can it be used for visual effects, but particles can interact with the mouse. They could be used to create golden cookies or collectables, for example.
      • Added marked feature to buyables, clickables, and challenges. By default, stars multi-completion challenges when maxed.
      • Added 'deactivated' feature to layers, which disables many features.
      • Improved number formatting slightly.

      v2.5.6 - 5/14/21

      • You can now use non-numeric ids for upgrades, buyables, etc.
      • Fixed an exploit that let you buy an extra buyable.
      • Moved basic getter/setter functions to easyAccess.js.

      v2.5.5.2 - 5/12/21

      • Fixed a major issue with buyables.
      • Fixed a variety of tabFormat-related issues.
      • Fixed commas appearing in decimal places (thanks to pg132!)

      v2.5.5.1 - 5/12/21

      • Fixed clickables.

      v2.5.5 - 5/12/21

      • Added grids! They are a grid of buttons which behave the same, but have their own data. Good for inventory grids, map tiles, and more!
      • Added "marked" feature to add a mark to a node. Can be an image instead of a star. (Originally by Jacorb)
      • Added "layer-proxy" component that lets you use components from another layer.
      • Added the ability to display non-whole numbers in main-display.

      v2.5.4 - 5/10/21

      • Added a setting to always use single-tab mode.
      • Added directMult, which multiplies prestige gain after exponents and softcaps. It actually multiplies gain for static layers.
      • Added onEnter and onExit for challenges.
      • Improved displaying numbers between 0.0001 and 0.1.
      • Added documentation on how gainMult/Exp work for static layers.
      • Fixed a visual issue on mobile, thanks to thepaperpilot.
      • Improved documentation in general.

      v2.5.3 - 5/8/21

      • Improved performance of tab formats and bars.
      • Respec confirmation settings are now kept on resets.
      • Improved compatibility with older browsers.
      • Fixed missing pixel on vertical bars.

      v2.5.2.1 - 5/7/21

      • Fixed microtabs making layers highlight incorrectly.

      v2.5.2 - 5/7/21

      • Added glowColor for subtabs.
      • Improved the display for extremely small numbers.
      • Fixed issues in the buyable docs.

      v2.5.1 - 5/7/21

      • Fixed dynamic things in tabFormat not updating.

      v2.5: Dreams Really Do Come True - 5/7/21

      • Optimizations, hopefully a significant amount.
      • Added OOM/s point gen display at high values (thanks to Ducdat!)
      • Only one tab will display if the window is not wide enough (also thanks to Ducdat!)
      • Holding down a buyable's button now buys it continuously.
      • New milestone setting will also show the most recently unlocked milestone. (Also renamed all settings to be clearer)
      • Added an onHold feature for clickables.
      • Layer nodes will be highlighted even if the player is on the same tab.
      • Added customizable node glowColor.
      • Added buyable purchaseLimit.
      • Amount is automatically supplied to buyable cost and effect functions.
      • Locked (not yet visible) milestones no longer take up space. Also fixed hidden milestones taking a tiny bit of space.
      • Re-centered respec buttons.
      • Force-displayed tooltips are not hidden by resets.
      • Added formatting support for very small numbers. Disabled in most places by default because rounding errors might cause issues. Access it with formatSmall, or enable it globally by adding "allowSmall: true" to modInfo.

      v2.4.1 - 4/29/21

      • A number of minor fixes, many thanks to thepaperpilot.
      • The respec confirmation checkbox is now part of the respec-button component. (This also fixes the checkbox appearing when there is no respec button)
      • Added a few undocumented changes to the 2.4 changelog (the two at the bottom)

      v2.4: Rationalized Edition - 4/29/21

      • Completely reworked tooltips. Shift-click a node to force its tooltip to stay displayed. (And hopefully finally fixed flickering!)

      • Added text-input and slider components.

      • Added the ability to toggle respec confirmations.

      • Added custom respec confirmation messages.

      • The red layer highlight will not appear before a layer is unlocked.

      • Added unlocking hotkeys.

      • You no longer need to supply 'rows' and 'cols' for any Big Features.

      • Node symbols can use HTML.

      • Added documentation for the respec button.

      • Added prestigeNotify to subtabs, and prestigeNotify in subtabs also highlights the layer node.

      • The version number no longer contains special characters or irrational numbers.

      • Added ctrlDown and shiftDown variables.

      • Tooltips now use HTML (this means you need to replace any newlines with
        )

      v2.π.1 - 4/7/21

      • Fixed formatting for some larger numbers.
      • Upgrades will expand if there is too much text to display.
      • Fixed styling challenges.
      • No longer attempts to display a base currency when there is none.

      v2.π: Incrementally Updated - 2/5/21

      • Performance improvements.
      • Fixed tooltips overlapping with the top display.
      • Clicking a popup dismisses it immediately.
      • Added support for bulk challenge completions.
      • "Best" is updated automatically.
      • Fixed keeping Decimal values on reset.
      • Code reorganization and style improvements by fudo.

      v2.3.5 - 12/21/20

      • Added resetTime, which tracks the time since a layer prestiged or was reset.
      • A layer node will be highlighted red if one of its subtabs is highlighted red.
      • Fixed issues with keeping challenges, buyables, and clickables on reset.
      • Improved the unlocking of custom layers.
      • Other minor fixes.

      v2.3.4 - 12/16/20

      • Added a node image feature.
      • Resource display now always shows the amount of the currency the layer's gain is based on.
      • Added spacing between tree nodes.
      • Another attempt to fix tooltip flickering.

      v2.3.3 - 12/13/20

      • Fixed the first node in a row always taking up space.
      • layerShown is now optional.
      • All prestige types can now use features for custom prestige types.

      v2.3.2 - 12/13/20

      • Fixed achievement/milestone popups.

      v2.3.1 - 12/12/20

      • Another attempt to fix flickering tooltips.
      • The "this" keyword should work everywhere except tabFormat arrays (although I may have missed some things).
      • Fixed tree branches not updating when scrolling on the right-side tab.
      • Fixed a spacing issue when a node's symbol is ""
      • Removed some old, unneeded files.

      v2.3: Cooler and Newer Edition - 12/10/20

      • Added achievement/milestone popups (thank you to Jacorb for this contribution!)
      • The changelog tab is back, and can be set in mod.js.
      • Layer nodes and respec buttons will not be clicked by pressing "enter".
      • Possible fix for flickering tooltips and strange transitions.
      • The victory screen text is configurable.
      • Added image and textStyle features to achievements.
      • Added an argument to use specific rows in an "upgrades" component.
      • Fixed the comma appearing in the main display when there was no effectDescription
      • Added the ability to easily make a tab that is a collection of layers in subtabs.
      • Improved spacing for embedding layers with subtabs into subtabs.

      v2.2.8 - 12/03/20

      • Double-clicking a layer node brings you to the main subtab for that layer.
      • Attempted to fix challenges visually updating a different way.
      • Added a softcap function for use in formulas.
      • Added displayRow feature, which lets layers be shown somewhere separate from where they are in the reset order (e.g. side layers)
      • Fixed autoupgrade issue.

      v2.2.7 - 11/30/20

      • Added autoUpgrade feature.
      • resource-display now shows resource gain per second if passiveGain is active.
      • Fixed formatting issues on some large numbers.
      • Better support for using classed objects in player and in layers/tmp.
      • Made hard resetting more effective.
      • Removed Herobrine from getStartClickables.

      v2.2.6 - 11/30/20

      • Added goalDescription for challenges and made the new "canComplete" system the standard.
      • Another attempt to fix challenges not visually updating.
      • Fixed side layers not appearing.
      • Fixed getStartClickables again.

      v2.2.5 - 11/29/20

      • Added features for overriding the displays and costs/goals of upgrades and challenges to make them fully custom.
      • best, total, and unlocked are always automatically added to layerData (but best and total will only display if you add them yourself).
      • Fixed getStartClickables.

      v2.2.4 - 11/28/20

      • Added softcap and softcapPower features (for Normal layers)
      • Offline time limit and default max tick length were fixed (previously the limits were 1000x too large)
      • Added fixOldSaves.
      • You can use HTML in main-display.
      • Fixed a number of minor oddities.

      v2.2.3 - 11/28/20

      • Layers will be highlighted if you can finish a challenge.
      • The "can complete challenge" color now overrides the "already completed" color.
      • Button nodes now work as side "layers".
      • Setting a tooltip to "" hides it entirely.

      v2.2.2 - 11/22/20

      • Fixed right half of the screen being unclickable in some circumstances.
      • Fixed tree branches being offset.
      • Fix to lastSafeTab.

      v2.2.1 - 11/7/20

      • Added a small highlight to layers you can meaningfully prestige on.
      • Added passiveGeneration and autoPrestige features to standardize prestige automation. (The old ways still work, but the new ones work better with other things)
      • Improved milestones visually a bit.
      • "best" and "total" are now only displayed if present in startData.
      • Fixed issues with things not updating visually. (Thank you to to Jacorb!)
      • Side layers and button nodes can now be highlighted.
      • Updated docs on the new tree-related features.

      v2.2: Uprooted - 11/7/20

      • You can now embed a layer inside of a subtab or microtab!
      • Added support for hiding or reformatting the tree tab
      • Added non-layer button nodes
      • Added shouldNotify to subtab/microtab buttons. (You can make them highlighted)
      • Added commas to large exponents.
      • Upgrades now only show "currently" if they have an effectDisplay (so not for constant effects).
      • Achievements are part of the default tab format.
      • NaN is now handled more intelligently.
      • Renamed files, and moved less relevant ones to another folder.
      • The "hide completed challenges" setting now only hides challenges at max completions.
      • Thank you to thepaperpilot for fixing errors in docs and improving the infobox appearance!
      • Many other minor fixes.

      v2.1.4 - 10/25/20

      • Added an infobox component. Thank you to thepaperpilot for this contribution!
      • Layer type is now optional, and defaults to "none".
      • Improved the look of bars and tab buttons.
      • Improved spacing between layer nodes (also thanks to thepaperpilot!)
      • Fixed the "blank" component breaking if only specifying the height.
      • Fixed some numbers not displaying with enough digits.
      • Made a few more things able to be functions.
      • A few other minor fixes.

      v2.1.3.1 - 10/21/20

      • Fixed the update function.

      v2.1.3 - 10/21/20

      • gainMult and gainExp are now optional.
      • Layer unlocking is now kept on reset.
      • Game should start up faster.
      • Layer updates now have a determined order and starts with earlier-rowed layers.
      • Automation now has a determined order and starts with later-rowed layers.
      • Fixed issues with resetting clickables and challenges.
      • Commas should no longer appear in the decimal places of a number.
      • Fixed potential issue in displaying the tree.

      v2.1.2 - 10/19/20

      • Added buyUpgrade function (buyUpg still works though)
      • Added author name to modInfo.
      • Fix to crash caused when the name of a subtab or microtab is changed.
      • Fixes to outdated information in docs.
      • Improvements to Discord links.
      • Thank you to thepaperpilot for contributing to this update!

      v2.1.1 - 10/17/20

      • Added resource-display component, which displays the base currency for the prestige layer, as well as the best and/or total of this layer's prestige currency.
      • Fixed the value for the base currency not updating in resource-display.

      v2.1: We should have thought of this sooner! - 10/17/20

      • Moved most of the code users will want to edit to mod.js, added documentation for it.
        • Specifically, modInfo, VERSION, canGenPoints, getPointGen, and maxTickLength
      • Added getStartPoints()
      • Added the ability to store non-layer-related data
      • Added the ability to display more things at the top of the tree tab below points.
      • Made the endgame condition customizable
      • Added "sell one" and "sell all" buttons for buyables.
      • Moved the old "game" to demo.js, and replaced it with a minimal game that won't cause issues when edited.
      • Fixed issues with version number
      • Fixed number formatting issue making things like "10e9" appear.

      v2.0.5 - 10/16/20

      • Made more features (including prestige parameters) able to be dynamic.
      • Layer nodes can be hidden but still take up space with "ghost" visibility
      • Added clickableEffect for real.
      • Fixed some visual issues with bars.
      • A few other minor tweaks and improvements.

      v2.0.4 - 10/16/20

      • Fixed HTML on buttons interfering with clicking on them.

      v2.0.3 - 10/16/20

      • Fixed hotkeys not displaying in info.
      • Fixed the game supressing all external hotkeys.
      • You can use more things as currencies for upgrade costs and challenge goals using currencyLocation.
      • Added maxTickLength, which can be used to prevent offline time or tab-switching from breaking time-limit based mechanics.
      • Made buyable respec buttons and clickable "master" buttons their own components, and gave them a hide/show feature.
      • Added a general "tooltip" feature for achievements.

      v2.0.2 - 10/15/20

      • Branches are now dynamic (they can be functions).
      • Fixed a crash related to offline time.
      • Fixed links being too wide.

      v2.0.1 - 10/15/20

      • Fixed side layers appearing multiple times.

      v2.0: The Pinnacle of Achievement Mountain - 10/15/20

      • Added progress bars, which are highly customizable and can be horizontal or vertical!
      • Added "side layers", displayed smaller and off to the side, and don't get reset by default. They can be used for global achievements and statistics. Speaking of which...
      • Added achievements!
      • Added clickables, a more generalized variant of buyables.
      • Almost every value in layer data can be either a function or a constant value!
      • Added support for multiple completions of challenges.
      • Added "none" prestige type, which removes the need for any other prestige-related features.
      • The points display and other gui elements stay at the top of the screen when the tree scrolls.
      • Added getter/setter functions for the amounts and effects of most Big Features
      • Moved modInfo to game.js, added a spot in modInfo for a Discord link, changelog link. Also added a separate mod version from the TMT version in VERSION.
      • Tree structure is based on layer data, no index.html editing is needed.
      • Tmp does not need to be manually updated.
      • You don't have to have the same amount of upgrades in every row (and challs and buyables)
      • "unlocked" is optional for all Big Components (defaults to true).
      • All displays will update correctly.
      • Changelog is no longer in index.html at all.
      • Generation of Points now happens in the main game loop
      • Changed the reset functions to make keeping things easier
      • Renamed many things to increase readability (see the list in the link below)
      • Improved documentation based on feedback

      v1.3.5:

      • Completely automated convertToDecimal, now you never have to worry about it again.
      • Branches can be defined without a color id. But they can also use hex values for color ids!
      • Created a tutorial for getting started with TMT and Github.
      • Page title is now automatically taken from mod name.

      v1.3.4 - 10/8/20

      • Added "midsection" feature to add things to a tab's layout while still keeping the standard layout.
      • Fix for being able to buy more buyables than you should.

      v1.3.3 - 10/7/20

      • Fix for the "order of operations" issue in temp.

      v1.3.1 - 10/7/20

      • Added custom CSS and tooltips for Layer Nodes.
      • Added custom CSS for upgrades, buyables, milestones, and challenges, both individually and layer-wide.
      • You can now use HTML in most display text!
      • You can now make milestones unlockable and not display immediately.
      • Fixed importing saves, and issue with upgrades not appearing, and probably more.
      • Optional "name" layer feature, used in confirmation messages.

      v1.3: Tabception... ception! - 10/7/20

      • Added subtabs! And also a Micro-tab component to let you make smaller subtab-esque areas anywhere.
      • Added a "custom" prestige formula type, and a number of features to support it.
      • Added points/sec display (can be disabled).
      • Added h-line, v-line and image-display components, plus components for individual upgrades, challenges, and milestones.
      • Added upgEffect, buyableEffect, and challEffect functions.
      • Added "hide completed challenges" setting.
      • Moved old changelogs to a separate place.
      • Fixed hasMilestone and incr_order.
      • Static layers now show the currency amount needed for the next one if you can buy max.

      v1.2.4 - 10/4/20

      • Layers are now highlighted if you can buy an upgrade, and a new feature, shouldNotify, lets you make it highlight other ways.
      • Fixed bugs with hasUpg, hasChall, hasMilestone, and inChallenge.
      • Changed the sample code to use the above functions for convenience.

      v1.2.3 - 10/3/20

      • Added a row component, which displays a list of objects in a row.
      • Added a column component, which displays a list of objects in a column (useful within a row).
      • Changed blanks to have a customizable width and height.

      v1.2: This Changes Everything! - 10/3/20

      • Many layer features can now be static values or functions. (This made some formats change, which will break old things)
      • You can now use the "this" keyword, to make code easier to transfer when making new layers.
      • Also added "this.layer", which is the current layer's name, and works on existing subfeatures (e.g. individual upgrades) as well! Subfeatures also have "this.id".
      • Fixed a big save issue. If you use a unique mod id, your save will never conflict with other mods.
      • Added a configurable offline time limit in modinfo at the top of index.html. (default 1 hour)
      • Added a few minor features, and updated the docs with new information.

      v1.1.1 - 9/30/20

      • You can define hotkeys directly from layer config.

      v1.1: Enhanced Edition - 9/30/20

      • Added "Buyables", which can function like Space Buildings or Enhancers.
      • Custom CSS can now be used on any component! Make the third argument an object with CSS parameters.
      • Lots of minor good things.

      v1.0 - 9/27/20

      • First release.
      ',115),n=[o];function r(s,d,h,u,c,m){return a(),i("div",null,n)}const f=e(t,[["render",r]]);export{b as __pageData,f as default}; diff --git a/assets/public_kronos_changelog.md._RxA7rHJ.lean.js b/assets/public_kronos_changelog.md.BB6U1JML.lean.js similarity index 70% rename from assets/public_kronos_changelog.md._RxA7rHJ.lean.js rename to assets/public_kronos_changelog.md.BB6U1JML.lean.js index c41cbf3b..48571db4 100644 --- a/assets/public_kronos_changelog.md._RxA7rHJ.lean.js +++ b/assets/public_kronos_changelog.md.BB6U1JML.lean.js @@ -1 +1 @@ -import{_ as e,c as i,o as a,ag as l}from"./chunks/framework.VBE0TPts.js";const b=JSON.parse('{"title":"The Modding Tree changelog:","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/changelog.md","filePath":"public/kronos/changelog.md"}'),t={name:"public/kronos/changelog.md"},o=l("",115),n=[o];function r(s,d,h,u,c,m){return a(),i("div",null,n)}const f=e(t,[["render",r]]);export{b as __pageData,f as default}; +import{_ as e,q as i,p as a,ag as l}from"./chunks/framework.DvHfxfnp.js";const b=JSON.parse('{"title":"The Modding Tree changelog:","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/changelog.md","filePath":"public/kronos/changelog.md"}'),t={name:"public/kronos/changelog.md"},o=l("",115),n=[o];function r(s,d,h,u,c,m){return a(),i("div",null,n)}const f=e(t,[["render",r]]);export{b as __pageData,f as default}; diff --git a/assets/public_kronos_docs_!general-info.md.Dr4UpP6q.js b/assets/public_kronos_docs_!general-info.md.jKiOCSlr.js similarity index 98% rename from assets/public_kronos_docs_!general-info.md.Dr4UpP6q.js rename to assets/public_kronos_docs_!general-info.md.jKiOCSlr.js index fda1a25d..25c6f60f 100644 --- a/assets/public_kronos_docs_!general-info.md.Dr4UpP6q.js +++ b/assets/public_kronos_docs_!general-info.md.jKiOCSlr.js @@ -1 +1 @@ -import{_ as e,c as a,o as t,ag as o}from"./chunks/framework.VBE0TPts.js";const b=JSON.parse('{"title":"The-Modding-Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/!general-info.md","filePath":"public/kronos/docs/!general-info.md"}'),n={name:"public/kronos/docs/!general-info.md"},r=o('

      The-Modding-Tree

      Making a game in The Modding Tree mostly involves defining parameters or functions on objects. If you aren't following the getting started guide, you should start by setting up your basic mod info in mod.js. It's important to set a mod id to ensure saving works properly.

      Beyond that, the main way to add content is through creating layers, often in layers.js. You can add new layers by calling addLayer(layername, layerdata). There is an example of a basic layer in layers.js showing the recommended method. It is just an example and can be freely deleted. You can also use it as a reference or a base for your own layers.

      Most of the time, you won't need to dive deep into the code to create things, but you still can if you really want to, for example to add new Vue components in components.js.

      The Modding Tree uses break_eternity.js to store large values. This means that many numbers are Decimal objects, and must be treated differently. For example, you have to use new Decimal(x) to create a Decimal value instead of a plain number, and perform operations on them by calling functions. e.g, instead of x = x + y, use x = x.add(y). Keep in mind this also applies to comparison operators, which should be replaced with calling the .gt, .gte, .lt, .lte, .eq, and .neq functions. See the break_eternity.js docs for more details on working with Decimal values.

      Almost all values can be either a constant value, or a dynamic value. Dynamic values are defined by putting a function that returns what the value should be at any given time.

      All display text can use basic HTML elements (But you can't use most Vue features there).

      While reading this documentation, the following key will be used when describing features:

      • No label: This is required and the game may crash if it isn't included.
      • sometimes required: This is may be required, depending on other things in the layer.
      • optional: You can leave this out if you don't intend to use that feature for the layer.
      • assigned automagically: This value will be set automatically and override any value you set.
      • deprecated: This feature is not recommended to be used, because newer features are able to achieve the same thing in a better, easier way.

      Table of Contents

      General

      • Getting Started: Getting your own copy of the code set up with Github Desktop.
      • Main mod info: How to set up general things for your mod in mod.js.
      • Basic layer breakdown: Breaking down the components of a layer with minimal features.
      • Layer features: Explanations of all of the different properties that you can give a layer.
      • Custom Tab Layouts: An optional way to give your tabs a different layout. You can even create entirely new components to use.
      • Custom game layouts: You can get rid of the tree tab, add buttons and other things to the tree, or even customize the tab's layout like a layer tab.
      • Updating TMT: Using Github Desktop to update your mod's version of TMT.

      Common components

      • Upgrades: How to create upgrades for a layer.
      • Milestones: How to create milestones for a layer.
      • Buyables: Create rebuyable upgrades for your layer (with the option to make them respec-able). Can be used to make Enhancers or Space Buildings, for example.
      • Clickables: A more generalized variant of buyables, for any kind of thing that is sometimes clickable. Between these and Buyables, you can do just about anything.
      • Achievements: How to create achievements for a layer (or for the whole game).

      Other components and features

      • Challenges: How to create challenges for a layer.
      • Bars: Display some information as a progress bar, gauge, or similar. They are highly customizable, and can be horizontal and vertical as well.
      • Subtabs and Microtabs: Create subtabs for your tabs, as well as "microtab" components that you can put inside the tabs. You can even use them to embed a layer inside another layer!
      • [Grids][grids.md]: Create a group buttons that behave the same, but have their own data. Good for map tiles, an inventory grid, and more!
      • Infoboxes: Boxes containing text that can be shown or hidden.
      • Trees: Make your own trees. You can make non-layer button nodes too!
      • Particle system: Can be used to create particles for visual effects, but also interactable things like golden cookies or collectables.
      ',16),i=[r];function s(l,d,c,h,u,m){return t(),a("div",null,i)}const g=e(n,[["render",s]]);export{b as __pageData,g as default}; +import{_ as e,q as a,p as t,ag as o}from"./chunks/framework.DvHfxfnp.js";const b=JSON.parse('{"title":"The-Modding-Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/!general-info.md","filePath":"public/kronos/docs/!general-info.md"}'),n={name:"public/kronos/docs/!general-info.md"},r=o('

      The-Modding-Tree

      Making a game in The Modding Tree mostly involves defining parameters or functions on objects. If you aren't following the getting started guide, you should start by setting up your basic mod info in mod.js. It's important to set a mod id to ensure saving works properly.

      Beyond that, the main way to add content is through creating layers, often in layers.js. You can add new layers by calling addLayer(layername, layerdata). There is an example of a basic layer in layers.js showing the recommended method. It is just an example and can be freely deleted. You can also use it as a reference or a base for your own layers.

      Most of the time, you won't need to dive deep into the code to create things, but you still can if you really want to, for example to add new Vue components in components.js.

      The Modding Tree uses break_eternity.js to store large values. This means that many numbers are Decimal objects, and must be treated differently. For example, you have to use new Decimal(x) to create a Decimal value instead of a plain number, and perform operations on them by calling functions. e.g, instead of x = x + y, use x = x.add(y). Keep in mind this also applies to comparison operators, which should be replaced with calling the .gt, .gte, .lt, .lte, .eq, and .neq functions. See the break_eternity.js docs for more details on working with Decimal values.

      Almost all values can be either a constant value, or a dynamic value. Dynamic values are defined by putting a function that returns what the value should be at any given time.

      All display text can use basic HTML elements (But you can't use most Vue features there).

      While reading this documentation, the following key will be used when describing features:

      • No label: This is required and the game may crash if it isn't included.
      • sometimes required: This is may be required, depending on other things in the layer.
      • optional: You can leave this out if you don't intend to use that feature for the layer.
      • assigned automagically: This value will be set automatically and override any value you set.
      • deprecated: This feature is not recommended to be used, because newer features are able to achieve the same thing in a better, easier way.

      Table of Contents

      General

      • Getting Started: Getting your own copy of the code set up with Github Desktop.
      • Main mod info: How to set up general things for your mod in mod.js.
      • Basic layer breakdown: Breaking down the components of a layer with minimal features.
      • Layer features: Explanations of all of the different properties that you can give a layer.
      • Custom Tab Layouts: An optional way to give your tabs a different layout. You can even create entirely new components to use.
      • Custom game layouts: You can get rid of the tree tab, add buttons and other things to the tree, or even customize the tab's layout like a layer tab.
      • Updating TMT: Using Github Desktop to update your mod's version of TMT.

      Common components

      • Upgrades: How to create upgrades for a layer.
      • Milestones: How to create milestones for a layer.
      • Buyables: Create rebuyable upgrades for your layer (with the option to make them respec-able). Can be used to make Enhancers or Space Buildings, for example.
      • Clickables: A more generalized variant of buyables, for any kind of thing that is sometimes clickable. Between these and Buyables, you can do just about anything.
      • Achievements: How to create achievements for a layer (or for the whole game).

      Other components and features

      • Challenges: How to create challenges for a layer.
      • Bars: Display some information as a progress bar, gauge, or similar. They are highly customizable, and can be horizontal and vertical as well.
      • Subtabs and Microtabs: Create subtabs for your tabs, as well as "microtab" components that you can put inside the tabs. You can even use them to embed a layer inside another layer!
      • [Grids][grids.md]: Create a group buttons that behave the same, but have their own data. Good for map tiles, an inventory grid, and more!
      • Infoboxes: Boxes containing text that can be shown or hidden.
      • Trees: Make your own trees. You can make non-layer button nodes too!
      • Particle system: Can be used to create particles for visual effects, but also interactable things like golden cookies or collectables.
      ',16),i=[r];function s(l,d,c,h,u,m){return t(),a("div",null,i)}const g=e(n,[["render",s]]);export{b as __pageData,g as default}; diff --git a/assets/public_kronos_docs_!general-info.md.Dr4UpP6q.lean.js b/assets/public_kronos_docs_!general-info.md.jKiOCSlr.lean.js similarity index 71% rename from assets/public_kronos_docs_!general-info.md.Dr4UpP6q.lean.js rename to assets/public_kronos_docs_!general-info.md.jKiOCSlr.lean.js index 68ac79fe..3f83791e 100644 --- a/assets/public_kronos_docs_!general-info.md.Dr4UpP6q.lean.js +++ b/assets/public_kronos_docs_!general-info.md.jKiOCSlr.lean.js @@ -1 +1 @@ -import{_ as e,c as a,o as t,ag as o}from"./chunks/framework.VBE0TPts.js";const b=JSON.parse('{"title":"The-Modding-Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/!general-info.md","filePath":"public/kronos/docs/!general-info.md"}'),n={name:"public/kronos/docs/!general-info.md"},r=o("",16),i=[r];function s(l,d,c,h,u,m){return t(),a("div",null,i)}const g=e(n,[["render",s]]);export{b as __pageData,g as default}; +import{_ as e,q as a,p as t,ag as o}from"./chunks/framework.DvHfxfnp.js";const b=JSON.parse('{"title":"The-Modding-Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/!general-info.md","filePath":"public/kronos/docs/!general-info.md"}'),n={name:"public/kronos/docs/!general-info.md"},r=o("",16),i=[r];function s(l,d,c,h,u,m){return t(),a("div",null,i)}const g=e(n,[["render",s]]);export{b as __pageData,g as default}; diff --git a/assets/public_kronos_docs_achievements.md.BQdSRHBr.js b/assets/public_kronos_docs_achievements.md.CWA5xmwG.js similarity index 97% rename from assets/public_kronos_docs_achievements.md.BQdSRHBr.js rename to assets/public_kronos_docs_achievements.md.CWA5xmwG.js index ea0e1144..de23d18f 100644 --- a/assets/public_kronos_docs_achievements.md.BQdSRHBr.js +++ b/assets/public_kronos_docs_achievements.md.CWA5xmwG.js @@ -1,4 +1,4 @@ -import{_ as e,c as t,o as a,ag as i}from"./chunks/framework.VBE0TPts.js";const g=JSON.parse('{"title":"Achievements","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/achievements.md","filePath":"public/kronos/docs/achievements.md"}'),s={name:"public/kronos/docs/achievements.md"},n=i(`

      Achievements

      Achievements are awarded to the player when they meet a certain goal, and optionally give some benefit.

      You can make global achievements by putting them in a side layer by making its row equal to "side" instead of a number.

      Useful functions for dealing with achievements and implementing their effects:

      • hasAchievement(layer, id): determine if the player has the Achievement.
      • achievementEffect(layer, id): Returns the current effects of the achievement, if any.

      Achievements should be formatted like this:

      js
      achievements: {
      +import{_ as e,q as t,p as a,ag as i}from"./chunks/framework.DvHfxfnp.js";const g=JSON.parse('{"title":"Achievements","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/achievements.md","filePath":"public/kronos/docs/achievements.md"}'),s={name:"public/kronos/docs/achievements.md"},n=i(`

      Achievements

      Achievements are awarded to the player when they meet a certain goal, and optionally give some benefit.

      You can make global achievements by putting them in a side layer by making its row equal to "side" instead of a number.

      Useful functions for dealing with achievements and implementing their effects:

      • hasAchievement(layer, id): determine if the player has the Achievement.
      • achievementEffect(layer, id): Returns the current effects of the achievement, if any.

      Achievements should be formatted like this:

      js
      achievements: {
           11: {
               name: "Blah",
               more features
      diff --git a/assets/public_kronos_docs_achievements.md.BQdSRHBr.lean.js b/assets/public_kronos_docs_achievements.md.CWA5xmwG.lean.js
      similarity index 71%
      rename from assets/public_kronos_docs_achievements.md.BQdSRHBr.lean.js
      rename to assets/public_kronos_docs_achievements.md.CWA5xmwG.lean.js
      index 5eae7d8c..22fc0b05 100644
      --- a/assets/public_kronos_docs_achievements.md.BQdSRHBr.lean.js
      +++ b/assets/public_kronos_docs_achievements.md.CWA5xmwG.lean.js
      @@ -1 +1 @@
      -import{_ as e,c as t,o as a,ag as i}from"./chunks/framework.VBE0TPts.js";const g=JSON.parse('{"title":"Achievements","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/achievements.md","filePath":"public/kronos/docs/achievements.md"}'),s={name:"public/kronos/docs/achievements.md"},n=i("",11),o=[n];function l(h,r,p,c,d,u){return a(),t("div",null,o)}const v=e(s,[["render",l]]);export{g as __pageData,v as default};
      +import{_ as e,q as t,p as a,ag as i}from"./chunks/framework.DvHfxfnp.js";const g=JSON.parse('{"title":"Achievements","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/achievements.md","filePath":"public/kronos/docs/achievements.md"}'),s={name:"public/kronos/docs/achievements.md"},n=i("",11),o=[n];function l(h,r,p,c,d,u){return a(),t("div",null,o)}const v=e(s,[["render",l]]);export{g as __pageData,v as default};
      diff --git a/assets/public_kronos_docs_bars.md.DLIjHzcw.js b/assets/public_kronos_docs_bars.md.DU3nCdnU.js
      similarity index 95%
      rename from assets/public_kronos_docs_bars.md.DLIjHzcw.js
      rename to assets/public_kronos_docs_bars.md.DU3nCdnU.js
      index 4989ed4a..891277c5 100644
      --- a/assets/public_kronos_docs_bars.md.DLIjHzcw.js
      +++ b/assets/public_kronos_docs_bars.md.DU3nCdnU.js
      @@ -1,4 +1,4 @@
      -import{_ as s,c as i,o as a,ag as t}from"./chunks/framework.VBE0TPts.js";const u=JSON.parse('{"title":"Bars","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/bars.md","filePath":"public/kronos/docs/bars.md"}'),e={name:"public/kronos/docs/bars.md"},n=t(`

      Bars

      Bars let you display information in a more direct way. It can be a progress bar, health bar, capacity gauge, or anything else.

      Bars are defined like other Big Features:

      js
      bars: {
      +import{_ as s,q as i,p as a,ag as t}from"./chunks/framework.DvHfxfnp.js";const u=JSON.parse('{"title":"Bars","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/bars.md","filePath":"public/kronos/docs/bars.md"}'),e={name:"public/kronos/docs/bars.md"},n=t(`

      Bars

      Bars let you display information in a more direct way. It can be a progress bar, health bar, capacity gauge, or anything else.

      Bars are defined like other Big Features:

      js
      bars: {
           bigBar: {
               direction: RIGHT,
               width: 200,
      @@ -7,4 +7,4 @@ import{_ as s,c as i,o as a,ag as t}from"./chunks/framework.VBE0TPts.js";const u
               etc
           },
           etc
      -}

      Features:

      • direction: UP, DOWN, LEFT, or RIGHT (not strings). Determines the direction that the bar is filled as it progresses. RIGHT means from left to right.

      • width, height: The size in pixels of the bar, but as numbers (no "px" at the end).

      • progress(): A function that returns the portion of the bar that is filled, from "empty" at 0 to "full" at 1, updating automatically. (Nothing bad happens if the value goes out of these bounds, and it can be a number or Decimal)

      • display(): optional. A function that returns text to be displayed on top of the bar, can use HTML.

      • unlocked(): optional. A function returning a bool to determine if the bar is visible or not. Default is unlocked.

      • baseStyle, fillStyle, borderStyle, textStyle: Optional, Apply CSS to the unfilled portion, filled portion, border, and display text on the bar, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

      • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

      • id: assigned automagically. It's the "key" which the bar was stored under, for convenient access. The bar in the example's id is "bigBar".

      `,6),l=[n];function r(o,p,h,d,k,c){return a(),i("div",null,l)}const E=s(e,[["render",r]]);export{u as __pageData,E as default}; +}

      Features:

      • direction: UP, DOWN, LEFT, or RIGHT (not strings). Determines the direction that the bar is filled as it progresses. RIGHT means from left to right.

      • width, height: The size in pixels of the bar, but as numbers (no "px" at the end).

      • progress(): A function that returns the portion of the bar that is filled, from "empty" at 0 to "full" at 1, updating automatically. (Nothing bad happens if the value goes out of these bounds, and it can be a number or Decimal)

      • display(): optional. A function that returns text to be displayed on top of the bar, can use HTML.

      • unlocked(): optional. A function returning a bool to determine if the bar is visible or not. Default is unlocked.

      • baseStyle, fillStyle, borderStyle, textStyle: Optional, Apply CSS to the unfilled portion, filled portion, border, and display text on the bar, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

      • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

      • id: assigned automagically. It's the "key" which the bar was stored under, for convenient access. The bar in the example's id is "bigBar".

      `,6),l=[n];function r(p,o,h,d,k,c){return a(),i("div",null,l)}const E=s(e,[["render",r]]);export{u as __pageData,E as default}; diff --git a/assets/public_kronos_docs_bars.md.DLIjHzcw.lean.js b/assets/public_kronos_docs_bars.md.DU3nCdnU.lean.js similarity index 53% rename from assets/public_kronos_docs_bars.md.DLIjHzcw.lean.js rename to assets/public_kronos_docs_bars.md.DU3nCdnU.lean.js index bfcf58be..6d7550f1 100644 --- a/assets/public_kronos_docs_bars.md.DLIjHzcw.lean.js +++ b/assets/public_kronos_docs_bars.md.DU3nCdnU.lean.js @@ -1 +1 @@ -import{_ as s,c as i,o as a,ag as t}from"./chunks/framework.VBE0TPts.js";const u=JSON.parse('{"title":"Bars","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/bars.md","filePath":"public/kronos/docs/bars.md"}'),e={name:"public/kronos/docs/bars.md"},n=t("",6),l=[n];function r(o,p,h,d,k,c){return a(),i("div",null,l)}const E=s(e,[["render",r]]);export{u as __pageData,E as default}; +import{_ as s,q as i,p as a,ag as t}from"./chunks/framework.DvHfxfnp.js";const u=JSON.parse('{"title":"Bars","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/bars.md","filePath":"public/kronos/docs/bars.md"}'),e={name:"public/kronos/docs/bars.md"},n=t("",6),l=[n];function r(p,o,h,d,k,c){return a(),i("div",null,l)}const E=s(e,[["render",r]]);export{u as __pageData,E as default}; diff --git a/assets/public_kronos_docs_basic-layer-breakdown.md.DHJLymK0.js b/assets/public_kronos_docs_basic-layer-breakdown.md.BZhX1dEF.js similarity index 98% rename from assets/public_kronos_docs_basic-layer-breakdown.md.DHJLymK0.js rename to assets/public_kronos_docs_basic-layer-breakdown.md.BZhX1dEF.js index a2397d23..1d71af5c 100644 --- a/assets/public_kronos_docs_basic-layer-breakdown.md.DHJLymK0.js +++ b/assets/public_kronos_docs_basic-layer-breakdown.md.BZhX1dEF.js @@ -1,4 +1,4 @@ -import{_ as s,c as i,o as a,ag as n}from"./chunks/framework.VBE0TPts.js";const g=JSON.parse('{"title":"Basic layer breakdown","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/basic-layer-breakdown.md","filePath":"public/kronos/docs/basic-layer-breakdown.md"}'),e={name:"public/kronos/docs/basic-layer-breakdown.md"},t=n(`

      Basic layer breakdown

      This is a very minimal layer with minimal features. Most things will require additional features.

      js
      addLayer("p", {
      +import{_ as s,q as i,p as a,ag as n}from"./chunks/framework.DvHfxfnp.js";const g=JSON.parse('{"title":"Basic layer breakdown","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/basic-layer-breakdown.md","filePath":"public/kronos/docs/basic-layer-breakdown.md"}'),e={name:"public/kronos/docs/basic-layer-breakdown.md"},t=n(`

      Basic layer breakdown

      This is a very minimal layer with minimal features. Most things will require additional features.

      js
      addLayer("p", {
           startData() { return {                  // startData is a function that returns default data for a layer. 
               unlocked: true,                     // You can add more variables here to add them to your layer.
               points: new Decimal(0),             // "points" is the internal name for the main resource of the layer.
      diff --git a/assets/public_kronos_docs_basic-layer-breakdown.md.DHJLymK0.lean.js b/assets/public_kronos_docs_basic-layer-breakdown.md.BZhX1dEF.lean.js
      similarity index 73%
      rename from assets/public_kronos_docs_basic-layer-breakdown.md.DHJLymK0.lean.js
      rename to assets/public_kronos_docs_basic-layer-breakdown.md.BZhX1dEF.lean.js
      index 1ccd36b4..d04ecd27 100644
      --- a/assets/public_kronos_docs_basic-layer-breakdown.md.DHJLymK0.lean.js
      +++ b/assets/public_kronos_docs_basic-layer-breakdown.md.BZhX1dEF.lean.js
      @@ -1 +1 @@
      -import{_ as s,c as i,o as a,ag as n}from"./chunks/framework.VBE0TPts.js";const g=JSON.parse('{"title":"Basic layer breakdown","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/basic-layer-breakdown.md","filePath":"public/kronos/docs/basic-layer-breakdown.md"}'),e={name:"public/kronos/docs/basic-layer-breakdown.md"},t=n("",3),h=[t];function l(p,k,r,E,d,o){return a(),i("div",null,h)}const c=s(e,[["render",l]]);export{g as __pageData,c as default};
      +import{_ as s,q as i,p as a,ag as n}from"./chunks/framework.DvHfxfnp.js";const g=JSON.parse('{"title":"Basic layer breakdown","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/basic-layer-breakdown.md","filePath":"public/kronos/docs/basic-layer-breakdown.md"}'),e={name:"public/kronos/docs/basic-layer-breakdown.md"},t=n("",3),h=[t];function l(p,k,r,E,d,o){return a(),i("div",null,h)}const c=s(e,[["render",l]]);export{g as __pageData,c as default};
      diff --git a/assets/public_kronos_docs_buyables.md.CZOwuPEI.js b/assets/public_kronos_docs_buyables.md.0zoux8fQ.js
      similarity index 98%
      rename from assets/public_kronos_docs_buyables.md.CZOwuPEI.js
      rename to assets/public_kronos_docs_buyables.md.0zoux8fQ.js
      index dc0bd7c3..1dea3868 100644
      --- a/assets/public_kronos_docs_buyables.md.CZOwuPEI.js
      +++ b/assets/public_kronos_docs_buyables.md.0zoux8fQ.js
      @@ -1,4 +1,4 @@
      -import{_ as s,c as i,o as a,ag as t}from"./chunks/framework.VBE0TPts.js";const c=JSON.parse('{"title":"Buyables","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/buyables.md","filePath":"public/kronos/docs/buyables.md"}'),e={name:"public/kronos/docs/buyables.md"},n=t(`

      Buyables

      Buyables are usually things that can be bought multiple times with scaling costs. They come with optional buttons that can be used for respeccing or selling buyables, among other things.

      The amount of a buyable owned is a Decimal.

      Useful functions for dealing with buyables and implementing their effects:

      • getBuyableAmount(layer, id): get the amount of the buyable the player has
      • setBuyableAmount(layer, id, amount): set the amount of the buyable the player has
      • buyableEffect(layer, id): Returns the current effects of the buyable, if any.

      Buyables should be formatted like this:

      js
      buyables: {
      +import{_ as s,q as i,p as a,ag as t}from"./chunks/framework.DvHfxfnp.js";const c=JSON.parse('{"title":"Buyables","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/buyables.md","filePath":"public/kronos/docs/buyables.md"}'),e={name:"public/kronos/docs/buyables.md"},n=t(`

      Buyables

      Buyables are usually things that can be bought multiple times with scaling costs. They come with optional buttons that can be used for respeccing or selling buyables, among other things.

      The amount of a buyable owned is a Decimal.

      Useful functions for dealing with buyables and implementing their effects:

      • getBuyableAmount(layer, id): get the amount of the buyable the player has
      • setBuyableAmount(layer, id, amount): set the amount of the buyable the player has
      • buyableEffect(layer, id): Returns the current effects of the buyable, if any.

      Buyables should be formatted like this:

      js
      buyables: {
           11: {
               cost(x) { return new Decimal(1).mul(x) },
               display() { return "Blah" },
      diff --git a/assets/public_kronos_docs_buyables.md.CZOwuPEI.lean.js b/assets/public_kronos_docs_buyables.md.0zoux8fQ.lean.js
      similarity index 70%
      rename from assets/public_kronos_docs_buyables.md.CZOwuPEI.lean.js
      rename to assets/public_kronos_docs_buyables.md.0zoux8fQ.lean.js
      index bbc4f71e..d9005ef2 100644
      --- a/assets/public_kronos_docs_buyables.md.CZOwuPEI.lean.js
      +++ b/assets/public_kronos_docs_buyables.md.0zoux8fQ.lean.js
      @@ -1 +1 @@
      -import{_ as s,c as i,o as a,ag as t}from"./chunks/framework.VBE0TPts.js";const c=JSON.parse('{"title":"Buyables","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/buyables.md","filePath":"public/kronos/docs/buyables.md"}'),e={name:"public/kronos/docs/buyables.md"},n=t("",14),l=[n];function h(p,o,r,k,u,d){return a(),i("div",null,l)}const g=s(e,[["render",h]]);export{c as __pageData,g as default};
      +import{_ as s,q as i,p as a,ag as t}from"./chunks/framework.DvHfxfnp.js";const c=JSON.parse('{"title":"Buyables","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/buyables.md","filePath":"public/kronos/docs/buyables.md"}'),e={name:"public/kronos/docs/buyables.md"},n=t("",14),l=[n];function h(p,o,r,k,u,d){return a(),i("div",null,l)}const g=s(e,[["render",h]]);export{c as __pageData,g as default};
      diff --git a/assets/public_kronos_docs_challenges.md.C8-cN764.js b/assets/public_kronos_docs_challenges.md.DvQ_P73q.js
      similarity index 98%
      rename from assets/public_kronos_docs_challenges.md.C8-cN764.js
      rename to assets/public_kronos_docs_challenges.md.DvQ_P73q.js
      index 4b98017a..76d68146 100644
      --- a/assets/public_kronos_docs_challenges.md.C8-cN764.js
      +++ b/assets/public_kronos_docs_challenges.md.DvQ_P73q.js
      @@ -1,4 +1,4 @@
      -import{_ as e,c as t,o as i,ag as a}from"./chunks/framework.VBE0TPts.js";const f=JSON.parse('{"title":"Challenges","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/challenges.md","filePath":"public/kronos/docs/challenges.md"}'),s={name:"public/kronos/docs/challenges.md"},n=a(`

      Challenges

      Challenges can have fully customizable win conditions. Useful functions for dealing with Challenges and implementing their effects:

      • inChallenge(layer, id): determine if the player is in a given challenge (or another challenge on the same layer that counts as this one).
      • hasChallenge(layer, id): determine if the player has completed the challenge.
      • challengeCompletions(layer, id): determine how many times the player completed the challenge.
      • maxedChallenge(layer, id): determines if the player has reached the maximum completions.
      • challengeEffect(layer, id): Returns the current effects of the challenge, if any.

      Challenges are stored in the following format:

      js
      challenges: {
      +import{_ as e,q as t,p as i,ag as a}from"./chunks/framework.DvHfxfnp.js";const f=JSON.parse('{"title":"Challenges","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/challenges.md","filePath":"public/kronos/docs/challenges.md"}'),s={name:"public/kronos/docs/challenges.md"},n=a(`

      Challenges

      Challenges can have fully customizable win conditions. Useful functions for dealing with Challenges and implementing their effects:

      • inChallenge(layer, id): determine if the player is in a given challenge (or another challenge on the same layer that counts as this one).
      • hasChallenge(layer, id): determine if the player has completed the challenge.
      • challengeCompletions(layer, id): determine how many times the player completed the challenge.
      • maxedChallenge(layer, id): determines if the player has reached the maximum completions.
      • challengeEffect(layer, id): Returns the current effects of the challenge, if any.

      Challenges are stored in the following format:

      js
      challenges: {
           11: {
               name: "Ouch",
               challengeDescription: "description of ouchie",
      diff --git a/assets/public_kronos_docs_challenges.md.C8-cN764.lean.js b/assets/public_kronos_docs_challenges.md.DvQ_P73q.lean.js
      similarity index 70%
      rename from assets/public_kronos_docs_challenges.md.C8-cN764.lean.js
      rename to assets/public_kronos_docs_challenges.md.DvQ_P73q.lean.js
      index 9cad5f57..fe415f48 100644
      --- a/assets/public_kronos_docs_challenges.md.C8-cN764.lean.js
      +++ b/assets/public_kronos_docs_challenges.md.DvQ_P73q.lean.js
      @@ -1 +1 @@
      -import{_ as e,c as t,o as i,ag as a}from"./chunks/framework.VBE0TPts.js";const f=JSON.parse('{"title":"Challenges","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/challenges.md","filePath":"public/kronos/docs/challenges.md"}'),s={name:"public/kronos/docs/challenges.md"},n=a("",10),l=[n];function o(h,r,p,c,g,u){return i(),t("div",null,l)}const y=e(s,[["render",o]]);export{f as __pageData,y as default};
      +import{_ as e,q as t,p as i,ag as a}from"./chunks/framework.DvHfxfnp.js";const f=JSON.parse('{"title":"Challenges","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/challenges.md","filePath":"public/kronos/docs/challenges.md"}'),s={name:"public/kronos/docs/challenges.md"},n=a("",10),l=[n];function o(h,r,p,c,g,u){return i(),t("div",null,l)}const y=e(s,[["render",o]]);export{f as __pageData,y as default};
      diff --git a/assets/public_kronos_docs_clickables.md.Dpdgv1J5.js b/assets/public_kronos_docs_clickables.md.C1ENZgWW.js
      similarity index 97%
      rename from assets/public_kronos_docs_clickables.md.Dpdgv1J5.js
      rename to assets/public_kronos_docs_clickables.md.C1ENZgWW.js
      index 80dbd374..4ea5c4df 100644
      --- a/assets/public_kronos_docs_clickables.md.Dpdgv1J5.js
      +++ b/assets/public_kronos_docs_clickables.md.C1ENZgWW.js
      @@ -1,4 +1,4 @@
      -import{_ as e,c as t,o as a,ag as s}from"./chunks/framework.VBE0TPts.js";const b=JSON.parse('{"title":"Clickables","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/clickables.md","filePath":"public/kronos/docs/clickables.md"}'),i={name:"public/kronos/docs/clickables.md"},l=s(`

      Clickables

      Clickables are any kind of thing that you can click for an effect. They're a more generalized version of Buyables.

      DO NOT USE THESE TO MAKE THINGS THAT YOU CLICK REPEATEDLY FOR A BONUS BECAUSE THOSE ARE AWFUL.

      There are several differences between the two. One is that a buyable's saved data is its amount as a Decimal, while Clickables store a "state" which can be a number or string, but not Decimal, array, or object). Buyables have a number of extra features which you can see on their page. Clickables also have a smaller default size.

      Useful functions for dealing with clickables and implementing their effects:

      • getClickableState(layer, id): get the state of the clickable the player has
      • setClickableState(layer, id, state): set the state of the clickable the player has
      • clickableEffect(layer, id): Returns the current effects of the clickable, if any.

      Clickables should be formatted like this:

      js
      clickables: {
      +import{_ as e,q as t,p as a,ag as s}from"./chunks/framework.DvHfxfnp.js";const b=JSON.parse('{"title":"Clickables","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/clickables.md","filePath":"public/kronos/docs/clickables.md"}'),i={name:"public/kronos/docs/clickables.md"},l=s(`

      Clickables

      Clickables are any kind of thing that you can click for an effect. They're a more generalized version of Buyables.

      DO NOT USE THESE TO MAKE THINGS THAT YOU CLICK REPEATEDLY FOR A BONUS BECAUSE THOSE ARE AWFUL.

      There are several differences between the two. One is that a buyable's saved data is its amount as a Decimal, while Clickables store a "state" which can be a number or string, but not Decimal, array, or object). Buyables have a number of extra features which you can see on their page. Clickables also have a smaller default size.

      Useful functions for dealing with clickables and implementing their effects:

      • getClickableState(layer, id): get the state of the clickable the player has
      • setClickableState(layer, id, state): set the state of the clickable the player has
      • clickableEffect(layer, id): Returns the current effects of the clickable, if any.

      Clickables should be formatted like this:

      js
      clickables: {
           11: {
               display() {return "Blah"},
               etc
      diff --git a/assets/public_kronos_docs_clickables.md.Dpdgv1J5.lean.js b/assets/public_kronos_docs_clickables.md.C1ENZgWW.lean.js
      similarity index 70%
      rename from assets/public_kronos_docs_clickables.md.Dpdgv1J5.lean.js
      rename to assets/public_kronos_docs_clickables.md.C1ENZgWW.lean.js
      index b3edccd9..701f8da8 100644
      --- a/assets/public_kronos_docs_clickables.md.Dpdgv1J5.lean.js
      +++ b/assets/public_kronos_docs_clickables.md.C1ENZgWW.lean.js
      @@ -1 +1 @@
      -import{_ as e,c as t,o as a,ag as s}from"./chunks/framework.VBE0TPts.js";const b=JSON.parse('{"title":"Clickables","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/clickables.md","filePath":"public/kronos/docs/clickables.md"}'),i={name:"public/kronos/docs/clickables.md"},l=s("",12),n=[l];function o(c,r,p,h,u,d){return a(),t("div",null,n)}const g=e(i,[["render",o]]);export{b as __pageData,g as default};
      +import{_ as e,q as t,p as a,ag as s}from"./chunks/framework.DvHfxfnp.js";const b=JSON.parse('{"title":"Clickables","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/clickables.md","filePath":"public/kronos/docs/clickables.md"}'),i={name:"public/kronos/docs/clickables.md"},l=s("",12),n=[l];function o(c,r,p,h,u,d){return a(),t("div",null,n)}const g=e(i,[["render",o]]);export{b as __pageData,g as default};
      diff --git a/assets/public_kronos_docs_custom-tab-layouts.md.B34ACqtp.js b/assets/public_kronos_docs_custom-tab-layouts.md.D4DCXZo7.js
      similarity index 98%
      rename from assets/public_kronos_docs_custom-tab-layouts.md.B34ACqtp.js
      rename to assets/public_kronos_docs_custom-tab-layouts.md.D4DCXZo7.js
      index babc1b06..5e34b588 100644
      --- a/assets/public_kronos_docs_custom-tab-layouts.md.B34ACqtp.js
      +++ b/assets/public_kronos_docs_custom-tab-layouts.md.D4DCXZo7.js
      @@ -1,4 +1,4 @@
      -import{_ as s,c as a,o as i,ag as t}from"./chunks/framework.VBE0TPts.js";const c=JSON.parse('{"title":"Custom tab layouts","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/custom-tab-layouts.md","filePath":"public/kronos/docs/custom-tab-layouts.md"}'),e={name:"public/kronos/docs/custom-tab-layouts.md"},n=t(`

      Custom tab layouts

      Note: If you are using subtabs, tabFormat is used differently, but the same format is used for defining their layouts. See here for more on subtabs.

      Custom tab layouts can be used to do basically anything in a tab window, especially combined with the "style" layer feature. The tabFormat feature is an array of things, like this:

      js
      tabFormat: [
      +import{_ as s,q as a,p as i,ag as t}from"./chunks/framework.DvHfxfnp.js";const c=JSON.parse('{"title":"Custom tab layouts","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/custom-tab-layouts.md","filePath":"public/kronos/docs/custom-tab-layouts.md"}'),e={name:"public/kronos/docs/custom-tab-layouts.md"},n=t(`

      Custom tab layouts

      Note: If you are using subtabs, tabFormat is used differently, but the same format is used for defining their layouts. See here for more on subtabs.

      Custom tab layouts can be used to do basically anything in a tab window, especially combined with the "style" layer feature. The tabFormat feature is an array of things, like this:

      js
      tabFormat: [
           "main-display",
           ["prestige-button", function() { return "Melt your points into " }],
           "blank",
      diff --git a/assets/public_kronos_docs_custom-tab-layouts.md.B34ACqtp.lean.js b/assets/public_kronos_docs_custom-tab-layouts.md.D4DCXZo7.lean.js
      similarity index 72%
      rename from assets/public_kronos_docs_custom-tab-layouts.md.B34ACqtp.lean.js
      rename to assets/public_kronos_docs_custom-tab-layouts.md.D4DCXZo7.lean.js
      index c1296654..9d7b91d2 100644
      --- a/assets/public_kronos_docs_custom-tab-layouts.md.B34ACqtp.lean.js
      +++ b/assets/public_kronos_docs_custom-tab-layouts.md.D4DCXZo7.lean.js
      @@ -1 +1 @@
      -import{_ as s,c as a,o as i,ag as t}from"./chunks/framework.VBE0TPts.js";const c=JSON.parse('{"title":"Custom tab layouts","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/custom-tab-layouts.md","filePath":"public/kronos/docs/custom-tab-layouts.md"}'),e={name:"public/kronos/docs/custom-tab-layouts.md"},n=t("",9),l=[n];function o(h,p,r,u,k,d){return i(),a("div",null,l)}const g=s(e,[["render",o]]);export{c as __pageData,g as default};
      +import{_ as s,q as a,p as i,ag as t}from"./chunks/framework.DvHfxfnp.js";const c=JSON.parse('{"title":"Custom tab layouts","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/custom-tab-layouts.md","filePath":"public/kronos/docs/custom-tab-layouts.md"}'),e={name:"public/kronos/docs/custom-tab-layouts.md"},n=t("",9),l=[n];function o(h,p,r,u,k,d){return i(),a("div",null,l)}const g=s(e,[["render",o]]);export{c as __pageData,g as default};
      diff --git a/assets/public_kronos_docs_getting-started.md.N-haPVCK.js b/assets/public_kronos_docs_getting-started.md.N-haPVCK.js
      new file mode 100644
      index 00000000..12aad77f
      --- /dev/null
      +++ b/assets/public_kronos_docs_getting-started.md.N-haPVCK.js
      @@ -0,0 +1 @@
      +import{_ as e,q as t,p as o,ag as i}from"./chunks/framework.DvHfxfnp.js";const y=JSON.parse('{"title":"Getting started","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/getting-started.md","filePath":"public/kronos/docs/getting-started.md"}'),a={name:"public/kronos/docs/getting-started.md"},n=i('

      Getting started

      Welcome to The Modding Tree!

      Using the Modding Tree, at its simplest level, just requires getting a copy of it onto your computer. However, if you do it the right way, it will help in many ways.

      Don't let the word "Github" scare you away. It's actually much easier to use than most people think, especially because most people use it the hard way. The key is Github Desktop, which lets you do everything you need to, without even touching the command line.

      The benefits of using Github:

      • It makes it much, much easier to update The Modding Tree.
      • You can share your work without any extra effort using githack, or with a bit more effort, set up a github.io site.
      • It lets you undo changes to your code, and to have multiple versions of it.
      • It lets you collaborate with other people, if you want to.

      Getting set up with Github Desktop, Visual Studio Code, and The Modding Tree:

      1. Install Github Desktop and Visual Studio Code.

      2. Make a Github account. You can handle this on your own.

      3. Log in on your browser, and go back to The Modding Tree page. At the top right, there should be a button that says "fork". Click on it, and then on your username. You now have your own fork, or copy, of The Modding Tree.

      4. Open Github Desktop and log in. Ignore everything else and choose "clone a repository". A "repository" is basically a "Github project", like The Modding Tree. "Cloning" is downloading a copy of the repository to your computer.

      5. Look for The Modding Tree in the list of repositiories (it should be the only one) and click "clone".

      6. Select that you're using it for your own purposes, and click continue. It will download the files and handle everything.

      Using your repository

      1. Click on "show in explorer/finder" to the right, and then open the index.html file in the folder. The page should open up on your browser. This will let you view and test your project locally!

      2. To edit your project, click "open in VSCode" in Github Desktop.

      3. Open mod.js in VSCode, and look at the top part where it has a "modInfo" object. Fill in your mod's name to whatever you want, and change the id as well. (It can be any string value, and it's used to determine where the savefile is. Make it something that's probably unique, and don't change it again later or else it'll effectively wipe existing saves)

      4. Save mod.js, and then reload index.html in your browser. The title on the tab, as well as on the info page, will now be updated! You can reload the page every time you change the code to test it quickly and easily.

      5. Go back to Github Desktop. It's time to save your changes into the git system by making a "commit". This basically saves your work and creates a snapshot of what your code looks like at this moment, allowing you to look back at it later.

      6. At the bottom right corner, add a summary of your changes, and then click "commit to master".

      7. Finally, at the top middle, click "push origin" to push your changes out onto the online repository.

      8. You can view your project on line, or share it with others, by going to https://raw.githack.com/[YOUR-GITHUB-USERNAME]/The-Modding-Tree/master/index.html

      And now, you have successfully used Github! You can look at the documentation to see how The Modding Tree's system works and to make your mod a reality.

      ',11),r=[n];function s(l,h,u,d,p,c){return o(),t("div",null,r)}const m=e(a,[["render",s]]);export{y as __pageData,m as default}; diff --git a/assets/public_kronos_docs_getting-started.md.N-haPVCK.lean.js b/assets/public_kronos_docs_getting-started.md.N-haPVCK.lean.js new file mode 100644 index 00000000..633eb14a --- /dev/null +++ b/assets/public_kronos_docs_getting-started.md.N-haPVCK.lean.js @@ -0,0 +1 @@ +import{_ as e,q as t,p as o,ag as i}from"./chunks/framework.DvHfxfnp.js";const y=JSON.parse('{"title":"Getting started","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/getting-started.md","filePath":"public/kronos/docs/getting-started.md"}'),a={name:"public/kronos/docs/getting-started.md"},n=i("",11),r=[n];function s(l,h,u,d,p,c){return o(),t("div",null,r)}const m=e(a,[["render",s]]);export{y as __pageData,m as default}; diff --git a/assets/public_kronos_docs_getting-started.md.qT4YQHFa.js b/assets/public_kronos_docs_getting-started.md.qT4YQHFa.js deleted file mode 100644 index 39039e3d..00000000 --- a/assets/public_kronos_docs_getting-started.md.qT4YQHFa.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as e,c as t,o,ag as i}from"./chunks/framework.VBE0TPts.js";const y=JSON.parse('{"title":"Getting started","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/getting-started.md","filePath":"public/kronos/docs/getting-started.md"}'),a={name:"public/kronos/docs/getting-started.md"},n=i('

      Getting started

      Welcome to The Modding Tree!

      Using the Modding Tree, at its simplest level, just requires getting a copy of it onto your computer. However, if you do it the right way, it will help in many ways.

      Don't let the word "Github" scare you away. It's actually much easier to use than most people think, especially because most people use it the hard way. The key is Github Desktop, which lets you do everything you need to, without even touching the command line.

      The benefits of using Github:

      • It makes it much, much easier to update The Modding Tree.
      • You can share your work without any extra effort using githack, or with a bit more effort, set up a github.io site.
      • It lets you undo changes to your code, and to have multiple versions of it.
      • It lets you collaborate with other people, if you want to.

      Getting set up with Github Desktop, Visual Studio Code, and The Modding Tree:

      1. Install Github Desktop and Visual Studio Code.

      2. Make a Github account. You can handle this on your own.

      3. Log in on your browser, and go back to The Modding Tree page. At the top right, there should be a button that says "fork". Click on it, and then on your username. You now have your own fork, or copy, of The Modding Tree.

      4. Open Github Desktop and log in. Ignore everything else and choose "clone a repository". A "repository" is basically a "Github project", like The Modding Tree. "Cloning" is downloading a copy of the repository to your computer.

      5. Look for The Modding Tree in the list of repositiories (it should be the only one) and click "clone".

      6. Select that you're using it for your own purposes, and click continue. It will download the files and handle everything.

      Using your repository

      1. Click on "show in explorer/finder" to the right, and then open the index.html file in the folder. The page should open up on your browser. This will let you view and test your project locally!

      2. To edit your project, click "open in VSCode" in Github Desktop.

      3. Open mod.js in VSCode, and look at the top part where it has a "modInfo" object. Fill in your mod's name to whatever you want, and change the id as well. (It can be any string value, and it's used to determine where the savefile is. Make it something that's probably unique, and don't change it again later or else it'll effectively wipe existing saves)

      4. Save mod.js, and then reload index.html in your browser. The title on the tab, as well as on the info page, will now be updated! You can reload the page every time you change the code to test it quickly and easily.

      5. Go back to Github Desktop. It's time to save your changes into the git system by making a "commit". This basically saves your work and creates a snapshot of what your code looks like at this moment, allowing you to look back at it later.

      6. At the bottom right corner, add a summary of your changes, and then click "commit to master".

      7. Finally, at the top middle, click "push origin" to push your changes out onto the online repository.

      8. You can view your project on line, or share it with others, by going to https://raw.githack.com/[YOUR-GITHUB-USERNAME]/The-Modding-Tree/master/index.html

      And now, you have successfully used Github! You can look at the documentation to see how The Modding Tree's system works and to make your mod a reality.

      ',11),r=[n];function s(l,h,u,d,p,c){return o(),t("div",null,r)}const m=e(a,[["render",s]]);export{y as __pageData,m as default}; diff --git a/assets/public_kronos_docs_getting-started.md.qT4YQHFa.lean.js b/assets/public_kronos_docs_getting-started.md.qT4YQHFa.lean.js deleted file mode 100644 index a31cf86c..00000000 --- a/assets/public_kronos_docs_getting-started.md.qT4YQHFa.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as e,c as t,o,ag as i}from"./chunks/framework.VBE0TPts.js";const y=JSON.parse('{"title":"Getting started","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/getting-started.md","filePath":"public/kronos/docs/getting-started.md"}'),a={name:"public/kronos/docs/getting-started.md"},n=i("",11),r=[n];function s(l,h,u,d,p,c){return o(),t("div",null,r)}const m=e(a,[["render",s]]);export{y as __pageData,m as default}; diff --git a/assets/public_kronos_docs_grids.md.dbyCMqJD.js b/assets/public_kronos_docs_grids.md.DGDenQsi.js similarity index 98% rename from assets/public_kronos_docs_grids.md.dbyCMqJD.js rename to assets/public_kronos_docs_grids.md.DGDenQsi.js index 8a5387b9..80a76521 100644 --- a/assets/public_kronos_docs_grids.md.dbyCMqJD.js +++ b/assets/public_kronos_docs_grids.md.DGDenQsi.js @@ -1,4 +1,4 @@ -import{_ as s,c as i,o as a,ag as t}from"./chunks/framework.VBE0TPts.js";const u=JSON.parse('{"title":"Grids","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/grids.md","filePath":"public/kronos/docs/grids.md"}'),e={name:"public/kronos/docs/grids.md"},n=t(`

      Grids

      Grids are an easier way of making a group of similar clickables. They all have the same behavior, but are different based on their data.

      NOTE: Gridables are similar to clickables in some respects, but are fundamentally different from normal TMT components in quite a few ways. Be sure to keep these in mind:

      • Gridable ids use base 100 instead of base 10, so you can have more than 10 tiles in a row. This means that a grid might look like this: 101 102 201 202
      • Individual gridables are not defined individually. All properties go directly into the "grid" object. Functions are called with arguments for the id of the gridables and its associated data, so you can give them the appropriate appearance and properties based on that.
      • If you need two unrelated grids in a layer, you'll need to use a layer proxy component.

      Useful functions for dealing with grids:

      • getGridData(layer, id): get the data for the chosen gridable
      • setGridData(layer, id, state): set the data for the chosen gridable
      • gridEffect(layer, id): get the effect for the chosen gridable

      The grid should be formatted like this:

      js
      grid: {
      +import{_ as s,q as i,p as a,ag as t}from"./chunks/framework.DvHfxfnp.js";const u=JSON.parse('{"title":"Grids","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/grids.md","filePath":"public/kronos/docs/grids.md"}'),e={name:"public/kronos/docs/grids.md"},n=t(`

      Grids

      Grids are an easier way of making a group of similar clickables. They all have the same behavior, but are different based on their data.

      NOTE: Gridables are similar to clickables in some respects, but are fundamentally different from normal TMT components in quite a few ways. Be sure to keep these in mind:

      • Gridable ids use base 100 instead of base 10, so you can have more than 10 tiles in a row. This means that a grid might look like this: 101 102 201 202
      • Individual gridables are not defined individually. All properties go directly into the "grid" object. Functions are called with arguments for the id of the gridables and its associated data, so you can give them the appropriate appearance and properties based on that.
      • If you need two unrelated grids in a layer, you'll need to use a layer proxy component.

      Useful functions for dealing with grids:

      • getGridData(layer, id): get the data for the chosen gridable
      • setGridData(layer, id, state): set the data for the chosen gridable
      • gridEffect(layer, id): get the effect for the chosen gridable

      The grid should be formatted like this:

      js
      grid: {
           rows: 4, // If these are dynamic make sure to have a max value as well!
           cols: 5,
           getStartData(id) {
      diff --git a/assets/public_kronos_docs_grids.md.dbyCMqJD.lean.js b/assets/public_kronos_docs_grids.md.DGDenQsi.lean.js
      similarity index 69%
      rename from assets/public_kronos_docs_grids.md.dbyCMqJD.lean.js
      rename to assets/public_kronos_docs_grids.md.DGDenQsi.lean.js
      index 869db564..fc90ce5f 100644
      --- a/assets/public_kronos_docs_grids.md.dbyCMqJD.lean.js
      +++ b/assets/public_kronos_docs_grids.md.DGDenQsi.lean.js
      @@ -1 +1 @@
      -import{_ as s,c as i,o as a,ag as t}from"./chunks/framework.VBE0TPts.js";const u=JSON.parse('{"title":"Grids","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/grids.md","filePath":"public/kronos/docs/grids.md"}'),e={name:"public/kronos/docs/grids.md"},n=t("",10),l=[n];function r(h,p,o,d,k,g){return a(),i("div",null,l)}const y=s(e,[["render",r]]);export{u as __pageData,y as default};
      +import{_ as s,q as i,p as a,ag as t}from"./chunks/framework.DvHfxfnp.js";const u=JSON.parse('{"title":"Grids","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/grids.md","filePath":"public/kronos/docs/grids.md"}'),e={name:"public/kronos/docs/grids.md"},n=t("",10),l=[n];function r(h,p,o,d,k,g){return a(),i("div",null,l)}const y=s(e,[["render",r]]);export{u as __pageData,y as default};
      diff --git a/assets/public_kronos_docs_infoboxes.md.Bc-XXHMa.js b/assets/public_kronos_docs_infoboxes.md.BXXHzXvY.js
      similarity index 96%
      rename from assets/public_kronos_docs_infoboxes.md.Bc-XXHMa.js
      rename to assets/public_kronos_docs_infoboxes.md.BXXHzXvY.js
      index 06278fb6..e55970cb 100644
      --- a/assets/public_kronos_docs_infoboxes.md.Bc-XXHMa.js
      +++ b/assets/public_kronos_docs_infoboxes.md.BXXHzXvY.js
      @@ -1,4 +1,4 @@
      -import{_ as s,c as i,o as e,ag as a}from"./chunks/framework.VBE0TPts.js";const u=JSON.parse('{"title":"Infoboxes","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/infoboxes.md","filePath":"public/kronos/docs/infoboxes.md"}'),t={name:"public/kronos/docs/infoboxes.md"},n=a(`

      Infoboxes

      Infoboxes are good for displaying "lore", or story elements, as well as for explaining complicated things.

      In the default tab layout, the first infobox will be displayed at the very top of the tab.

      Infoboxes are defined like other Big Features:

      js
      infoboxes: {
      +import{_ as s,q as i,p as e,ag as a}from"./chunks/framework.DvHfxfnp.js";const u=JSON.parse('{"title":"Infoboxes","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/infoboxes.md","filePath":"public/kronos/docs/infoboxes.md"}'),t={name:"public/kronos/docs/infoboxes.md"},n=a(`

      Infoboxes

      Infoboxes are good for displaying "lore", or story elements, as well as for explaining complicated things.

      In the default tab layout, the first infobox will be displayed at the very top of the tab.

      Infoboxes are defined like other Big Features:

      js
      infoboxes: {
           lore: {
               title: "foo",
               body() { return "bar" },
      diff --git a/assets/public_kronos_docs_infoboxes.md.Bc-XXHMa.lean.js b/assets/public_kronos_docs_infoboxes.md.BXXHzXvY.lean.js
      similarity index 70%
      rename from assets/public_kronos_docs_infoboxes.md.Bc-XXHMa.lean.js
      rename to assets/public_kronos_docs_infoboxes.md.BXXHzXvY.lean.js
      index a269a0c7..71d3ba41 100644
      --- a/assets/public_kronos_docs_infoboxes.md.Bc-XXHMa.lean.js
      +++ b/assets/public_kronos_docs_infoboxes.md.BXXHzXvY.lean.js
      @@ -1 +1 @@
      -import{_ as s,c as i,o as e,ag as a}from"./chunks/framework.VBE0TPts.js";const u=JSON.parse('{"title":"Infoboxes","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/infoboxes.md","filePath":"public/kronos/docs/infoboxes.md"}'),t={name:"public/kronos/docs/infoboxes.md"},n=a("",7),o=[n];function l(p,h,r,d,c,k){return e(),i("div",null,o)}const y=s(t,[["render",l]]);export{u as __pageData,y as default};
      +import{_ as s,q as i,p as e,ag as a}from"./chunks/framework.DvHfxfnp.js";const u=JSON.parse('{"title":"Infoboxes","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/infoboxes.md","filePath":"public/kronos/docs/infoboxes.md"}'),t={name:"public/kronos/docs/infoboxes.md"},n=a("",7),o=[n];function l(p,h,r,d,c,k){return e(),i("div",null,o)}const y=s(t,[["render",l]]);export{u as __pageData,y as default};
      diff --git a/assets/public_kronos_docs_layer-features.md.DJjusT4t.js b/assets/public_kronos_docs_layer-features.md.C1uOzCZ-.js
      similarity index 99%
      rename from assets/public_kronos_docs_layer-features.md.DJjusT4t.js
      rename to assets/public_kronos_docs_layer-features.md.C1uOzCZ-.js
      index e35eeede..f2e17fb1 100644
      --- a/assets/public_kronos_docs_layer-features.md.DJjusT4t.js
      +++ b/assets/public_kronos_docs_layer-features.md.C1uOzCZ-.js
      @@ -1,4 +1,4 @@
      -import{_ as e,c as t,o as a,ag as s}from"./chunks/framework.VBE0TPts.js";const y=JSON.parse('{"title":"Layer Features","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/layer-features.md","filePath":"public/kronos/docs/layer-features.md"}'),i={name:"public/kronos/docs/layer-features.md"},o=s(`

      Layer Features

      This is a more comprehensive list of established features to add to layers. You can add more freely, if you want to have other functions or values associated with your layer. These have special functionality, though.

      You can make almost any value dynamic by using a function in its place, including all display strings and styling/color features.

      Layer Definition features

      • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar to access the saved value. It makes copying code to new layers easier. It is also assigned to all upgrades and buyables and such.

      • name: optional. used in reset confirmations (and the default infobox title). If absent, it just uses the layer's id.

      • startData(): A function to return the default save data for this layer. Add any variables you have to it. Make sure to use Decimal values rather than normal numbers.

        Standard values: - Required: - unlocked: a bool determining if this layer is unlocked or not - points: a Decimal, the main currency for the layer - Optional: - total: A Decimal, tracks total amount of main prestige currency. Always tracked, but only shown if you add it here. - best: A Decimal, tracks highest amount of main prestige currency. Always tracked, but only shown if you add it here. - unlockOrder: used to keep track of relevant layers unlocked before this one. - resetTime: A number, time since this layer was last prestiged (or reset by another layer)

      • color: A color associated with this layer, used in many places. (A string in hex format with a #)

      • row: The row of the layer, starting at 0. This affects where the node appears on the standard tree, and which resets affect the layer.

        Using "side" instead of a number will cause the layer to appear off to the side as a smaller node (useful for achievements and statistics). Side layers are not affected by resets unless you add a doReset to them.

      • displayRow: OVERRIDE Changes where the layer node appears without changing where it is in the reset order.

      • resource: Name of the main currency you gain by resetting on this layer.

      • effect(): optional. A function that calculates and returns the current values of any bonuses inherent to the main currency. Can return a value or an object containing multiple values. You will also have to implement the effect where it is applied.

      • effectDescription: optional. A function that returns a description of this effect. If the text stays constant, it can just be a string.

      • layerShown(): optional, A function returning a bool which determines if this layer's node should be visible on the tree. It can also return "ghost", which will hide the layer, but its node will still take up space in the tree. Defaults to true.

      • hotkeys: optional. An array containing information on any hotkeys associated with this layer:

        js
        hotkeys: [
        +import{_ as e,q as t,p as a,ag as s}from"./chunks/framework.DvHfxfnp.js";const y=JSON.parse('{"title":"Layer Features","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/layer-features.md","filePath":"public/kronos/docs/layer-features.md"}'),i={name:"public/kronos/docs/layer-features.md"},o=s(`

        Layer Features

        This is a more comprehensive list of established features to add to layers. You can add more freely, if you want to have other functions or values associated with your layer. These have special functionality, though.

        You can make almost any value dynamic by using a function in its place, including all display strings and styling/color features.

        Layer Definition features

        • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar to access the saved value. It makes copying code to new layers easier. It is also assigned to all upgrades and buyables and such.

        • name: optional. used in reset confirmations (and the default infobox title). If absent, it just uses the layer's id.

        • startData(): A function to return the default save data for this layer. Add any variables you have to it. Make sure to use Decimal values rather than normal numbers.

          Standard values: - Required: - unlocked: a bool determining if this layer is unlocked or not - points: a Decimal, the main currency for the layer - Optional: - total: A Decimal, tracks total amount of main prestige currency. Always tracked, but only shown if you add it here. - best: A Decimal, tracks highest amount of main prestige currency. Always tracked, but only shown if you add it here. - unlockOrder: used to keep track of relevant layers unlocked before this one. - resetTime: A number, time since this layer was last prestiged (or reset by another layer)

        • color: A color associated with this layer, used in many places. (A string in hex format with a #)

        • row: The row of the layer, starting at 0. This affects where the node appears on the standard tree, and which resets affect the layer.

          Using "side" instead of a number will cause the layer to appear off to the side as a smaller node (useful for achievements and statistics). Side layers are not affected by resets unless you add a doReset to them.

        • displayRow: OVERRIDE Changes where the layer node appears without changing where it is in the reset order.

        • resource: Name of the main currency you gain by resetting on this layer.

        • effect(): optional. A function that calculates and returns the current values of any bonuses inherent to the main currency. Can return a value or an object containing multiple values. You will also have to implement the effect where it is applied.

        • effectDescription: optional. A function that returns a description of this effect. If the text stays constant, it can just be a string.

        • layerShown(): optional, A function returning a bool which determines if this layer's node should be visible on the tree. It can also return "ghost", which will hide the layer, but its node will still take up space in the tree. Defaults to true.

        • hotkeys: optional. An array containing information on any hotkeys associated with this layer:

          js
          hotkeys: [
               {
                   key: "p", // What the hotkey button is. Use uppercase if it's combined with shift, or "ctrl+x" for holding down ctrl.
                   description: "p: reset your points for prestige points", // The description of the hotkey that is displayed in the game's How To Play tab
          diff --git a/assets/public_kronos_docs_layer-features.md.DJjusT4t.lean.js b/assets/public_kronos_docs_layer-features.md.C1uOzCZ-.lean.js
          similarity index 71%
          rename from assets/public_kronos_docs_layer-features.md.DJjusT4t.lean.js
          rename to assets/public_kronos_docs_layer-features.md.C1uOzCZ-.lean.js
          index a9341cf9..34719e78 100644
          --- a/assets/public_kronos_docs_layer-features.md.DJjusT4t.lean.js
          +++ b/assets/public_kronos_docs_layer-features.md.C1uOzCZ-.lean.js
          @@ -1 +1 @@
          -import{_ as e,c as t,o as a,ag as s}from"./chunks/framework.VBE0TPts.js";const y=JSON.parse('{"title":"Layer Features","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/layer-features.md","filePath":"public/kronos/docs/layer-features.md"}'),i={name:"public/kronos/docs/layer-features.md"},o=s("",20),r=[o];function n(l,h,p,u,d,c){return a(),t("div",null,r)}const f=e(i,[["render",n]]);export{y as __pageData,f as default};
          +import{_ as e,q as t,p as a,ag as s}from"./chunks/framework.DvHfxfnp.js";const y=JSON.parse('{"title":"Layer Features","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/layer-features.md","filePath":"public/kronos/docs/layer-features.md"}'),i={name:"public/kronos/docs/layer-features.md"},o=s("",20),r=[o];function n(l,h,p,u,d,c){return a(),t("div",null,r)}const f=e(i,[["render",n]]);export{y as __pageData,f as default};
          diff --git a/assets/public_kronos_docs_main-mod-info.md.DYKIKxsS.js b/assets/public_kronos_docs_main-mod-info.md.TWb3xDwG.js
          similarity index 98%
          rename from assets/public_kronos_docs_main-mod-info.md.DYKIKxsS.js
          rename to assets/public_kronos_docs_main-mod-info.md.TWb3xDwG.js
          index eca8f950..6eea3e05 100644
          --- a/assets/public_kronos_docs_main-mod-info.md.DYKIKxsS.js
          +++ b/assets/public_kronos_docs_main-mod-info.md.TWb3xDwG.js
          @@ -1,4 +1,4 @@
          -import{_ as i,c as e,o as t,ag as s}from"./chunks/framework.VBE0TPts.js";const f=JSON.parse('{"title":"mod.js","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/main-mod-info.md","filePath":"public/kronos/docs/main-mod-info.md"}'),a={name:"public/kronos/docs/main-mod-info.md"},n=s(`

          mod.js

          Most of the non-layer code and data that you're likely to edit is here in mod.js. Everything in mod.js will not be altered by updates, besides the addition of new things.

          Here's a breakdown of what's in it:

          • modInfo is where most of the basic configuration for the mod is. It contains:

            • name: The name of your mod. (a string)

            • id: The id for your mod, a unique string that is used to determine savefile location. Be sure to set it when you start making a mod, and don't change it later because it will erase all saves.

            • author: The name of the author, displayed in the info tab.

            • pointsName: This changes what is displayed instead of "points" for the main currency. (It does not affect it in the code.)

            • discordName, discordLink: If you have a Discord server or other discussion place, you can add a link to it.

              "discordName" is the text on the link, and "discordLink" is the url of an invite. If you're using a Discord invite, please make sure it's set to never expire.

            • offlineLimit: The maximum amount of offline time that the player can accumulate, in hours. Any extra time is lost. (a number)

              This is useful because most of these mods are fast-paced enough that too much offline time ruins the balance, such as the time in between updates. That is why I suggest developers disable offline time on their own savefile.

            • initialStartPoints: A Decimal for the amount of points a new player should start with.

          • VERSION is used to describe the current version of your mod. It contains:

            • num: The mod's version number, displayed at the top right of the tree tab.
            • name: The version's name, displayed alongside the number in the info tab.
          • changelog is the HTML displayed in the changelog tab. If this gets particularly long, it might be good to put in a separate file (be sure to add the file to index.html)

          • doNotCallTheseFunctionsEveryTick is very important, if you are adding non-standard functions. TMT calls every function anywhere in "layers" every tick to store the result, unless specifically told not to. Functions that have are used to do an action need to be identified. "Official" functions (those in the documentation) are all fine, but if you make any new ones, add their names to this array.

          js
          // (The ones here are examples, all official functions are already taken care of)
          +import{_ as i,q as e,p as t,ag as s}from"./chunks/framework.DvHfxfnp.js";const f=JSON.parse('{"title":"mod.js","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/main-mod-info.md","filePath":"public/kronos/docs/main-mod-info.md"}'),a={name:"public/kronos/docs/main-mod-info.md"},n=s(`

          mod.js

          Most of the non-layer code and data that you're likely to edit is here in mod.js. Everything in mod.js will not be altered by updates, besides the addition of new things.

          Here's a breakdown of what's in it:

          • modInfo is where most of the basic configuration for the mod is. It contains:

            • name: The name of your mod. (a string)

            • id: The id for your mod, a unique string that is used to determine savefile location. Be sure to set it when you start making a mod, and don't change it later because it will erase all saves.

            • author: The name of the author, displayed in the info tab.

            • pointsName: This changes what is displayed instead of "points" for the main currency. (It does not affect it in the code.)

            • discordName, discordLink: If you have a Discord server or other discussion place, you can add a link to it.

              "discordName" is the text on the link, and "discordLink" is the url of an invite. If you're using a Discord invite, please make sure it's set to never expire.

            • offlineLimit: The maximum amount of offline time that the player can accumulate, in hours. Any extra time is lost. (a number)

              This is useful because most of these mods are fast-paced enough that too much offline time ruins the balance, such as the time in between updates. That is why I suggest developers disable offline time on their own savefile.

            • initialStartPoints: A Decimal for the amount of points a new player should start with.

          • VERSION is used to describe the current version of your mod. It contains:

            • num: The mod's version number, displayed at the top right of the tree tab.
            • name: The version's name, displayed alongside the number in the info tab.
          • changelog is the HTML displayed in the changelog tab. If this gets particularly long, it might be good to put in a separate file (be sure to add the file to index.html)

          • doNotCallTheseFunctionsEveryTick is very important, if you are adding non-standard functions. TMT calls every function anywhere in "layers" every tick to store the result, unless specifically told not to. Functions that have are used to do an action need to be identified. "Official" functions (those in the documentation) are all fine, but if you make any new ones, add their names to this array.

          js
          // (The ones here are examples, all official functions are already taken care of)
           var doNotCallTheseFunctionsEveryTick = ["doReset", "buy", "onPurchase", "blowUpEverything"]
          • getStartPoints(): A function to determine the amount of points the player starts with after a reset. (returns a Decimal value)

          • canGenPoints(): A function returning a boolean for if points should be generated. Use this if you want an upgrade to unlock generating points.

          • getPointGen(): A function that calculates your points per second. Anything that affects your point gain should go into the calculation here.

          • addedPlayerData(): A function that returns any non-layer-related data that you want to be added to the save data and "player" object.

          js
          function addedPlayerData() { return {
           	weather: "Yes",
           	happiness: new Decimal(72),
          diff --git a/assets/public_kronos_docs_main-mod-info.md.DYKIKxsS.lean.js b/assets/public_kronos_docs_main-mod-info.md.TWb3xDwG.lean.js
          similarity index 71%
          rename from assets/public_kronos_docs_main-mod-info.md.DYKIKxsS.lean.js
          rename to assets/public_kronos_docs_main-mod-info.md.TWb3xDwG.lean.js
          index 8fd633ab..49b511a5 100644
          --- a/assets/public_kronos_docs_main-mod-info.md.DYKIKxsS.lean.js
          +++ b/assets/public_kronos_docs_main-mod-info.md.TWb3xDwG.lean.js
          @@ -1 +1 @@
          -import{_ as i,c as e,o as t,ag as s}from"./chunks/framework.VBE0TPts.js";const f=JSON.parse('{"title":"mod.js","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/main-mod-info.md","filePath":"public/kronos/docs/main-mod-info.md"}'),a={name:"public/kronos/docs/main-mod-info.md"},n=s("",10),o=[n];function l(h,r,p,d,u,c){return t(),e("div",null,o)}const y=i(a,[["render",l]]);export{f as __pageData,y as default};
          +import{_ as i,q as e,p as t,ag as s}from"./chunks/framework.DvHfxfnp.js";const f=JSON.parse('{"title":"mod.js","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/main-mod-info.md","filePath":"public/kronos/docs/main-mod-info.md"}'),a={name:"public/kronos/docs/main-mod-info.md"},n=s("",10),o=[n];function l(h,r,p,d,u,c){return t(),e("div",null,o)}const y=i(a,[["render",l]]);export{f as __pageData,y as default};
          diff --git a/assets/public_kronos_docs_milestones.md.Ce7tGr8C.js b/assets/public_kronos_docs_milestones.md.BqiEbWx4.js
          similarity index 97%
          rename from assets/public_kronos_docs_milestones.md.Ce7tGr8C.js
          rename to assets/public_kronos_docs_milestones.md.BqiEbWx4.js
          index 0cf4e44e..907a46f8 100644
          --- a/assets/public_kronos_docs_milestones.md.Ce7tGr8C.js
          +++ b/assets/public_kronos_docs_milestones.md.BqiEbWx4.js
          @@ -1,4 +1,4 @@
          -import{_ as e,c as s,o as i,ag as t}from"./chunks/framework.VBE0TPts.js";const u=JSON.parse('{"title":"Milestones","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/milestones.md","filePath":"public/kronos/docs/milestones.md"}'),a={name:"public/kronos/docs/milestones.md"},n=t(`

          Milestones

          Milestones are awarded to the player when they meet a certain goal, and give some benefit. Milestones should be formatted like this:

          js
          milestones: {
          +import{_ as e,q as s,p as i,ag as t}from"./chunks/framework.DvHfxfnp.js";const u=JSON.parse('{"title":"Milestones","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/milestones.md","filePath":"public/kronos/docs/milestones.md"}'),a={name:"public/kronos/docs/milestones.md"},n=t(`

          Milestones

          Milestones are awarded to the player when they meet a certain goal, and give some benefit. Milestones should be formatted like this:

          js
          milestones: {
               0: {
                   requirementDescription: "123 waffles",
                   effectDescription: "blah",
          diff --git a/assets/public_kronos_docs_milestones.md.Ce7tGr8C.lean.js b/assets/public_kronos_docs_milestones.md.BqiEbWx4.lean.js
          similarity index 70%
          rename from assets/public_kronos_docs_milestones.md.Ce7tGr8C.lean.js
          rename to assets/public_kronos_docs_milestones.md.BqiEbWx4.lean.js
          index 4487eb20..27040965 100644
          --- a/assets/public_kronos_docs_milestones.md.Ce7tGr8C.lean.js
          +++ b/assets/public_kronos_docs_milestones.md.BqiEbWx4.lean.js
          @@ -1 +1 @@
          -import{_ as e,c as s,o as i,ag as t}from"./chunks/framework.VBE0TPts.js";const u=JSON.parse('{"title":"Milestones","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/milestones.md","filePath":"public/kronos/docs/milestones.md"}'),a={name:"public/kronos/docs/milestones.md"},n=t("",7),o=[n];function l(h,r,p,d,c,g){return i(),s("div",null,o)}const m=e(a,[["render",l]]);export{u as __pageData,m as default};
          +import{_ as e,q as s,p as i,ag as t}from"./chunks/framework.DvHfxfnp.js";const u=JSON.parse('{"title":"Milestones","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/milestones.md","filePath":"public/kronos/docs/milestones.md"}'),a={name:"public/kronos/docs/milestones.md"},n=t("",7),o=[n];function l(h,r,p,d,c,g){return i(),s("div",null,o)}const m=e(a,[["render",l]]);export{u as __pageData,m as default};
          diff --git a/assets/public_kronos_docs_particles.md.CgdBAXsD.js b/assets/public_kronos_docs_particles.md.a4-BPTpH.js
          similarity index 98%
          rename from assets/public_kronos_docs_particles.md.CgdBAXsD.js
          rename to assets/public_kronos_docs_particles.md.a4-BPTpH.js
          index e1d032c9..4584589c 100644
          --- a/assets/public_kronos_docs_particles.md.CgdBAXsD.js
          +++ b/assets/public_kronos_docs_particles.md.a4-BPTpH.js
          @@ -1,4 +1,4 @@
          -import{_ as e,c as i,o as s,ag as a}from"./chunks/framework.VBE0TPts.js";const g=JSON.parse('{"title":"Particles","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/particles.md","filePath":"public/kronos/docs/particles.md"}'),t={name:"public/kronos/docs/particles.md"},l=a(`

          Particles

          Particles are free-floating elements that can move and have many different behaviors. They can also interact with the mouse.

          To make particles, use makeParticles(particle, amount). particle is a particle-defining object, with features as explained below. There is also makeShinies, which uses different defaults and creates stationary particles at a random location. There are also a few other useful things listed at the end.

          js
          
          +import{_ as e,q as i,p as s,ag as a}from"./chunks/framework.DvHfxfnp.js";const g=JSON.parse('{"title":"Particles","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/particles.md","filePath":"public/kronos/docs/particles.md"}'),t={name:"public/kronos/docs/particles.md"},l=a(`

          Particles

          Particles are free-floating elements that can move and have many different behaviors. They can also interact with the mouse.

          To make particles, use makeParticles(particle, amount). particle is a particle-defining object, with features as explained below. There is also makeShinies, which uses different defaults and creates stationary particles at a random location. There are also a few other useful things listed at the end.

          js
          
           const myParticle {
               image:"options_wheel.png",
               spread: 20,
          diff --git a/assets/public_kronos_docs_particles.md.CgdBAXsD.lean.js b/assets/public_kronos_docs_particles.md.a4-BPTpH.lean.js
          similarity index 70%
          rename from assets/public_kronos_docs_particles.md.CgdBAXsD.lean.js
          rename to assets/public_kronos_docs_particles.md.a4-BPTpH.lean.js
          index bd3b1acc..9c79faf0 100644
          --- a/assets/public_kronos_docs_particles.md.CgdBAXsD.lean.js
          +++ b/assets/public_kronos_docs_particles.md.a4-BPTpH.lean.js
          @@ -1 +1 @@
          -import{_ as e,c as i,o as s,ag as a}from"./chunks/framework.VBE0TPts.js";const g=JSON.parse('{"title":"Particles","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/particles.md","filePath":"public/kronos/docs/particles.md"}'),t={name:"public/kronos/docs/particles.md"},l=a("",11),n=[l];function h(p,r,o,d,c,k){return s(),i("div",null,n)}const f=e(t,[["render",h]]);export{g as __pageData,f as default};
          +import{_ as e,q as i,p as s,ag as a}from"./chunks/framework.DvHfxfnp.js";const g=JSON.parse('{"title":"Particles","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/particles.md","filePath":"public/kronos/docs/particles.md"}'),t={name:"public/kronos/docs/particles.md"},l=a("",11),n=[l];function h(p,r,o,d,c,k){return s(),i("div",null,n)}const f=e(t,[["render",h]]);export{g as __pageData,f as default};
          diff --git a/assets/public_kronos_docs_subtabs-and-microtabs.md.BSv4TpNt.js b/assets/public_kronos_docs_subtabs-and-microtabs.md.B3i34UtK.js
          similarity index 98%
          rename from assets/public_kronos_docs_subtabs-and-microtabs.md.BSv4TpNt.js
          rename to assets/public_kronos_docs_subtabs-and-microtabs.md.B3i34UtK.js
          index 3f960cf8..e934a487 100644
          --- a/assets/public_kronos_docs_subtabs-and-microtabs.md.BSv4TpNt.js
          +++ b/assets/public_kronos_docs_subtabs-and-microtabs.md.B3i34UtK.js
          @@ -1,4 +1,4 @@
          -import{_ as s,c as a,o as t,ag as i}from"./chunks/framework.VBE0TPts.js";const u=JSON.parse('{"title":"Subtabs and Microtabs","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/subtabs-and-microtabs.md","filePath":"public/kronos/docs/subtabs-and-microtabs.md"}'),n={name:"public/kronos/docs/subtabs-and-microtabs.md"},e=i(`

          Subtabs and Microtabs

          Subtabs are separate sections of a tab that you can view by selecting one at the top of the tab. Microtabs are smaller areas that function in much the same way. You can also embed layers inside of subtabs/microtabs.

          Subtabs are defined by using the tab format like this, where each element of tabFormat is given the name of that subtab:

          js
          tabFormat: {
          +import{_ as s,q as a,p as t,ag as i}from"./chunks/framework.DvHfxfnp.js";const u=JSON.parse('{"title":"Subtabs and Microtabs","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/subtabs-and-microtabs.md","filePath":"public/kronos/docs/subtabs-and-microtabs.md"}'),n={name:"public/kronos/docs/subtabs-and-microtabs.md"},e=i(`

          Subtabs and Microtabs

          Subtabs are separate sections of a tab that you can view by selecting one at the top of the tab. Microtabs are smaller areas that function in much the same way. You can also embed layers inside of subtabs/microtabs.

          Subtabs are defined by using the tab format like this, where each element of tabFormat is given the name of that subtab:

          js
          tabFormat: {
               "Main tab": {
                   content: [tab format things],
                   *subtab features*
          diff --git a/assets/public_kronos_docs_subtabs-and-microtabs.md.BSv4TpNt.lean.js b/assets/public_kronos_docs_subtabs-and-microtabs.md.B3i34UtK.lean.js
          similarity index 73%
          rename from assets/public_kronos_docs_subtabs-and-microtabs.md.BSv4TpNt.lean.js
          rename to assets/public_kronos_docs_subtabs-and-microtabs.md.B3i34UtK.lean.js
          index 7e7e6d32..c8da07b0 100644
          --- a/assets/public_kronos_docs_subtabs-and-microtabs.md.BSv4TpNt.lean.js
          +++ b/assets/public_kronos_docs_subtabs-and-microtabs.md.B3i34UtK.lean.js
          @@ -1 +1 @@
          -import{_ as s,c as a,o as t,ag as i}from"./chunks/framework.VBE0TPts.js";const u=JSON.parse('{"title":"Subtabs and Microtabs","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/subtabs-and-microtabs.md","filePath":"public/kronos/docs/subtabs-and-microtabs.md"}'),n={name:"public/kronos/docs/subtabs-and-microtabs.md"},e=i("",9),l=[e];function h(o,p,r,k,d,b){return t(),a("div",null,l)}const E=s(n,[["render",h]]);export{u as __pageData,E as default};
          +import{_ as s,q as a,p as t,ag as i}from"./chunks/framework.DvHfxfnp.js";const u=JSON.parse('{"title":"Subtabs and Microtabs","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/subtabs-and-microtabs.md","filePath":"public/kronos/docs/subtabs-and-microtabs.md"}'),n={name:"public/kronos/docs/subtabs-and-microtabs.md"},e=i("",9),l=[e];function h(o,p,r,k,d,b){return t(),a("div",null,l)}const E=s(n,[["render",h]]);export{u as __pageData,E as default};
          diff --git a/assets/public_kronos_docs_trees-and-tree-customization.md.C6vJ-bgs.js b/assets/public_kronos_docs_trees-and-tree-customization.md.bHBppIK5.js
          similarity index 97%
          rename from assets/public_kronos_docs_trees-and-tree-customization.md.C6vJ-bgs.js
          rename to assets/public_kronos_docs_trees-and-tree-customization.md.bHBppIK5.js
          index 44079973..0615e680 100644
          --- a/assets/public_kronos_docs_trees-and-tree-customization.md.C6vJ-bgs.js
          +++ b/assets/public_kronos_docs_trees-and-tree-customization.md.bHBppIK5.js
          @@ -1,3 +1,3 @@
          -import{_ as e,c as t,o as a,ag as i}from"./chunks/framework.VBE0TPts.js";const y=JSON.parse('{"title":"Trees and tree customization","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/trees-and-tree-customization.md","filePath":"public/kronos/docs/trees-and-tree-customization.md"}'),s={name:"public/kronos/docs/trees-and-tree-customization.md"},o=i(`

          Trees and tree customization

          If you want to have something beyond the standard tree on the left tab, you can do that in tree.js. You can change the layout of the tree, including making non-layer nodes, change it into something other than a tree, or hide the left tab altogether. This also introduces the "tree" component, which can be used in your layers as well.

          layoutInfo

          The most important part is layoutInfo, containing:

          • startTab: The id of the default tab to show on the left at the start.
          • showTree: True if the tree tab should be shown at the start of the game. (The other tab will fill the whole page)
          • treeLayout: If present, overrides the tree layout and places nodes as you describe instead (explained in the next section).

          Additionally, if you want the main layout to not be a tree, you can edit the "tree-tab" layer at the bottom of tree.js to modify it just like a normal layer's tab. You can even switch between left tabs, using showNavTab(layer) to make that layer appear on the left.

          Trees

          The tree component is defined as an array of arrays of names of layers or nodes to show in the tree. They work just like layers/ nodes in the main tree (but branches between nodes will only work on the first node if you have duplicates.)

          Here is an example tree:

          js
          [["p"],
          +import{_ as e,q as t,p as a,ag as i}from"./chunks/framework.DvHfxfnp.js";const y=JSON.parse('{"title":"Trees and tree customization","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/trees-and-tree-customization.md","filePath":"public/kronos/docs/trees-and-tree-customization.md"}'),s={name:"public/kronos/docs/trees-and-tree-customization.md"},o=i(`

          Trees and tree customization

          If you want to have something beyond the standard tree on the left tab, you can do that in tree.js. You can change the layout of the tree, including making non-layer nodes, change it into something other than a tree, or hide the left tab altogether. This also introduces the "tree" component, which can be used in your layers as well.

          layoutInfo

          The most important part is layoutInfo, containing:

          • startTab: The id of the default tab to show on the left at the start.
          • showTree: True if the tree tab should be shown at the start of the game. (The other tab will fill the whole page)
          • treeLayout: If present, overrides the tree layout and places nodes as you describe instead (explained in the next section).

          Additionally, if you want the main layout to not be a tree, you can edit the "tree-tab" layer at the bottom of tree.js to modify it just like a normal layer's tab. You can even switch between left tabs, using showNavTab(layer) to make that layer appear on the left.

          Trees

          The tree component is defined as an array of arrays of names of layers or nodes to show in the tree. They work just like layers/ nodes in the main tree (but branches between nodes will only work on the first node if you have duplicates.)

          Here is an example tree:

          js
          [["p"],
            ["left", "blank", "right", "blank"]
            ["a", "b", "blank", "c", "weirdButton"]]

          Nodes

          Nodes are non-layer buttons that can go in trees. They are defined similarly to layers, but with addNode instead of addLayer.

          Features:

          • color: optional, The node's color. (A string in hex format with a #)

          • symbol: optional The text on the button (The id capitalized by default)

          • canClick(): Returns true if the player can click the node. ()

          • onClick(): The function called when the node is clicked.

          • layerShown(): optional, A function returning a bool which determines if this node should be visible. It can also return "ghost", which will hide the layer, but its node will still take up space in its tree.

          • branches: optional. An array of layer/node ids. On a tree, a line will appear from this node to all of the nodes in the list. Alternatively, an entry in the array can be a 2-element array consisting of the id and a color value. The color value can either be a string with a hex color code, or a number from 1-3 (theme-affected colors).

          • nodeStyle: optional. A CSS object, where the keys are CSS attributes, which styles this node on the tree.

          • tooltip() / tooltipLocked(): optional. Functions that return text, which is the tooltip for the node when the layer is unlocked or locked, respectively. By default the tooltips behave the same as in the original Prestige Tree.

          • row: optional, the row that this node appears in (for the default tree).

          • position: optional, Determines the horizontal position of the layer in its row in a default tree. By default, it uses the id, and layers/nodes are sorted in alphabetical order.

          `,14),n=[o];function l(r,h,d,p,u,c){return a(),t("div",null,n)}const g=e(s,[["render",l]]);export{y as __pageData,g as default}; diff --git a/assets/public_kronos_docs_trees-and-tree-customization.md.C6vJ-bgs.lean.js b/assets/public_kronos_docs_trees-and-tree-customization.md.bHBppIK5.lean.js similarity index 74% rename from assets/public_kronos_docs_trees-and-tree-customization.md.C6vJ-bgs.lean.js rename to assets/public_kronos_docs_trees-and-tree-customization.md.bHBppIK5.lean.js index b936ddce..5122d63b 100644 --- a/assets/public_kronos_docs_trees-and-tree-customization.md.C6vJ-bgs.lean.js +++ b/assets/public_kronos_docs_trees-and-tree-customization.md.bHBppIK5.lean.js @@ -1 +1 @@ -import{_ as e,c as t,o as a,ag as i}from"./chunks/framework.VBE0TPts.js";const y=JSON.parse('{"title":"Trees and tree customization","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/trees-and-tree-customization.md","filePath":"public/kronos/docs/trees-and-tree-customization.md"}'),s={name:"public/kronos/docs/trees-and-tree-customization.md"},o=i("",14),n=[o];function l(r,h,d,p,u,c){return a(),t("div",null,n)}const g=e(s,[["render",l]]);export{y as __pageData,g as default}; +import{_ as e,q as t,p as a,ag as i}from"./chunks/framework.DvHfxfnp.js";const y=JSON.parse('{"title":"Trees and tree customization","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/trees-and-tree-customization.md","filePath":"public/kronos/docs/trees-and-tree-customization.md"}'),s={name:"public/kronos/docs/trees-and-tree-customization.md"},o=i("",14),n=[o];function l(r,h,d,p,u,c){return a(),t("div",null,n)}const g=e(s,[["render",l]]);export{y as __pageData,g as default}; diff --git a/assets/public_kronos_docs_updating-tmt.md.BxVzngxM.js b/assets/public_kronos_docs_updating-tmt.md.BxVzngxM.js new file mode 100644 index 00000000..f5c701c1 --- /dev/null +++ b/assets/public_kronos_docs_updating-tmt.md.BxVzngxM.js @@ -0,0 +1 @@ +import{_ as t,q as e,p as o,ag as a}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"Updating The Modding Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/updating-tmt.md","filePath":"public/kronos/docs/updating-tmt.md"}'),i={name:"public/kronos/docs/updating-tmt.md"},n=a('

          Updating The Modding Tree

          This tutorial assumes that you have used the Getting Started Tutorial, and are using Github Desktop and VSCode for your mod.

          Here's what you have to do when there's a TMT update:

          1. Look at the changelog. It will warn you if the update will break anything or require any changes. Decide if you want to try to update.

          2. Open Github Desktop, and at the top middle, click "fetch origin". This will make Github Desktop get information about the update.

          3. Click where it says "current branch: master" at the top middle, and at the bottom of the thing that appears, click "choose a branch to merge into master".

          4. Select upstream/master. It will likely say there are conflicts, but you have tools to resolve them. Click "Merge upstream/master into master".

          5. A conflict happens when the things you're trying to merge have both made changes in the same place. Click "open in Visual Studio Code" next to the first file.

          6. Scroll down through the file, and look for the parts highlighted in red and green. One of these is your code, and the other is some code that will be modified by the update. Do your best to try to edit things to keep the updated changes, but keep your content.

          7. Continue to do this for all remaining changes.

          8. Do any other changes required by the update, run the game, fix issues, etc.

          ',4),r=[n];function h(s,d,l,p,u,c){return o(),e("div",null,r)}const _=t(i,[["render",h]]);export{m as __pageData,_ as default}; diff --git a/assets/public_kronos_docs_updating-tmt.md.BxVzngxM.lean.js b/assets/public_kronos_docs_updating-tmt.md.BxVzngxM.lean.js new file mode 100644 index 00000000..51b3cfe3 --- /dev/null +++ b/assets/public_kronos_docs_updating-tmt.md.BxVzngxM.lean.js @@ -0,0 +1 @@ +import{_ as t,q as e,p as o,ag as a}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"Updating The Modding Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/updating-tmt.md","filePath":"public/kronos/docs/updating-tmt.md"}'),i={name:"public/kronos/docs/updating-tmt.md"},n=a("",4),r=[n];function h(s,d,l,p,u,c){return o(),e("div",null,r)}const _=t(i,[["render",h]]);export{m as __pageData,_ as default}; diff --git a/assets/public_kronos_docs_updating-tmt.md.yvj4vsSM.js b/assets/public_kronos_docs_updating-tmt.md.yvj4vsSM.js deleted file mode 100644 index 529c61cc..00000000 --- a/assets/public_kronos_docs_updating-tmt.md.yvj4vsSM.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as t,c as e,o,ag as a}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"Updating The Modding Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/updating-tmt.md","filePath":"public/kronos/docs/updating-tmt.md"}'),i={name:"public/kronos/docs/updating-tmt.md"},n=a('

          Updating The Modding Tree

          This tutorial assumes that you have used the Getting Started Tutorial, and are using Github Desktop and VSCode for your mod.

          Here's what you have to do when there's a TMT update:

          1. Look at the changelog. It will warn you if the update will break anything or require any changes. Decide if you want to try to update.

          2. Open Github Desktop, and at the top middle, click "fetch origin". This will make Github Desktop get information about the update.

          3. Click where it says "current branch: master" at the top middle, and at the bottom of the thing that appears, click "choose a branch to merge into master".

          4. Select upstream/master. It will likely say there are conflicts, but you have tools to resolve them. Click "Merge upstream/master into master".

          5. A conflict happens when the things you're trying to merge have both made changes in the same place. Click "open in Visual Studio Code" next to the first file.

          6. Scroll down through the file, and look for the parts highlighted in red and green. One of these is your code, and the other is some code that will be modified by the update. Do your best to try to edit things to keep the updated changes, but keep your content.

          7. Continue to do this for all remaining changes.

          8. Do any other changes required by the update, run the game, fix issues, etc.

          ',4),r=[n];function h(s,d,l,p,u,c){return o(),e("div",null,r)}const _=t(i,[["render",h]]);export{m as __pageData,_ as default}; diff --git a/assets/public_kronos_docs_updating-tmt.md.yvj4vsSM.lean.js b/assets/public_kronos_docs_updating-tmt.md.yvj4vsSM.lean.js deleted file mode 100644 index 8961e75c..00000000 --- a/assets/public_kronos_docs_updating-tmt.md.yvj4vsSM.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as t,c as e,o,ag as a}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"Updating The Modding Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/updating-tmt.md","filePath":"public/kronos/docs/updating-tmt.md"}'),i={name:"public/kronos/docs/updating-tmt.md"},n=a("",4),r=[n];function h(s,d,l,p,u,c){return o(),e("div",null,r)}const _=t(i,[["render",h]]);export{m as __pageData,_ as default}; diff --git a/assets/public_kronos_docs_upgrades.md.BY_E6naZ.js b/assets/public_kronos_docs_upgrades.md.D1pH3BI1.js similarity index 96% rename from assets/public_kronos_docs_upgrades.md.BY_E6naZ.js rename to assets/public_kronos_docs_upgrades.md.D1pH3BI1.js index 48d25151..f98c69e0 100644 --- a/assets/public_kronos_docs_upgrades.md.BY_E6naZ.js +++ b/assets/public_kronos_docs_upgrades.md.D1pH3BI1.js @@ -1,8 +1,8 @@ -import{_ as e,c as t,o as s,ag as a}from"./chunks/framework.VBE0TPts.js";const f=JSON.parse('{"title":"Upgrades","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/upgrades.md","filePath":"public/kronos/docs/upgrades.md"}'),i={name:"public/kronos/docs/upgrades.md"},n=a(`

          Upgrades

          Useful functions for dealing with Upgrades and implementing their effects:

          • hasUpgrade(layer, id): determine if the player has the upgrade
          • upgradeEffect(layer, id): Returns the current effects of the upgrade, if any
          • buyUpgrade(layer, id): Buys an upgrade directly (if affordable)

          Hint: Basic point gain is calculated in mod.js's "getPointGen" function.

          Upgrades are stored in the following format:

          js
          upgrades: {
          +import{_ as e,q as t,p as s,ag as a}from"./chunks/framework.DvHfxfnp.js";const f=JSON.parse('{"title":"Upgrades","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/upgrades.md","filePath":"public/kronos/docs/upgrades.md"}'),i={name:"public/kronos/docs/upgrades.md"},n=a(`

          Upgrades

          Useful functions for dealing with Upgrades and implementing their effects:

          • hasUpgrade(layer, id): determine if the player has the upgrade
          • upgradeEffect(layer, id): Returns the current effects of the upgrade, if any
          • buyUpgrade(layer, id): Buys an upgrade directly (if affordable)

          Hint: Basic point gain is calculated in mod.js's "getPointGen" function.

          Upgrades are stored in the following format:

          js
          upgrades: {
               11: {
                   description: "Blah",
                   cost: new Decimal(100),
                   etc
               },
               etc
          -}

          Usually, upgrades should have an id where the first digit is the row and the second digit is the column.

          Individual upgrades can have these features:

          • title: optional. Displayed at the top in a larger font. It can also be a function that returns updating text. Can use basic HTML.

          • description: A description of the upgrade's effect. You will also have to implement the effect where it is applied. It can also be a function that returns updating text. Can use basic HTML.

          • effect(): optional. A function that calculates and returns the current values of any bonuses from the upgrade. Can return a value or an object containing multiple values.

          • effectDisplay(): optional. A function that returns a display of the current effects of the upgrade with formatting. Default displays nothing. Can use basic HTML.

          • fullDisplay(): OVERRIDE. Overrides the other displays and descriptions, and lets you set the full text for the upgrade. Can use basic HTML.

          • cost: A Decimal for the cost of the upgrade. By default, upgrades cost the main prestige currency for the layer.

          • unlocked(): optional. A function returning a bool to determine if the upgrade is visible or not. Default is unlocked.

          • onPurchase(): optional. This function will be called when the upgrade is purchased. Good for upgrades like "makes this layer act like it was unlocked first".

          • style: optional. Applies CSS to this upgrade, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the upgrade was stored under, for convenient access. The upgrade in the example's id is 11.

          By default, upgrades use the main prestige currency for the layer. You can include these to change them (but it needs to be a Decimal):

          • currencyDisplayName: optional. The name to display for the currency for the upgrade.

          • currencyInternalName: optional. The internal name for that currency.

          • currencyLayer: optional. The internal name of the layer that currency is stored in. If it's not in a layer (like Points), omit. If it's not stored directly in a layer, instead use the next feature.

          • currencyLocation: optional. If your currency is stored in something inside a layer (e.g. a buyable's amount), you can access it this way. This is a function returning the object in "player" that contains the value (like player[this.layer].buyables)

          If you want to do something more complicated like upgrades that cost two currencies, you can override the purchase system with these (and you need to use fullDisplay as well)

          • canAfford(): OVERRIDE, a function determining if you are able to buy the upgrade

          • pay(): OVERRIDE, a function that reduces your currencies when you buy the upgrade

          `,13),r=[n];function l(o,p,h,u,c,d){return s(),t("div",null,r)}const y=e(i,[["render",l]]);export{f as __pageData,y as default}; +}

          Usually, upgrades should have an id where the first digit is the row and the second digit is the column.

          Individual upgrades can have these features:

          • title: optional. Displayed at the top in a larger font. It can also be a function that returns updating text. Can use basic HTML.

          • description: A description of the upgrade's effect. You will also have to implement the effect where it is applied. It can also be a function that returns updating text. Can use basic HTML.

          • effect(): optional. A function that calculates and returns the current values of any bonuses from the upgrade. Can return a value or an object containing multiple values.

          • effectDisplay(): optional. A function that returns a display of the current effects of the upgrade with formatting. Default displays nothing. Can use basic HTML.

          • fullDisplay(): OVERRIDE. Overrides the other displays and descriptions, and lets you set the full text for the upgrade. Can use basic HTML.

          • cost: A Decimal for the cost of the upgrade. By default, upgrades cost the main prestige currency for the layer.

          • unlocked(): optional. A function returning a bool to determine if the upgrade is visible or not. Default is unlocked.

          • onPurchase(): optional. This function will be called when the upgrade is purchased. Good for upgrades like "makes this layer act like it was unlocked first".

          • style: optional. Applies CSS to this upgrade, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the upgrade was stored under, for convenient access. The upgrade in the example's id is 11.

          By default, upgrades use the main prestige currency for the layer. You can include these to change them (but it needs to be a Decimal):

          • currencyDisplayName: optional. The name to display for the currency for the upgrade.

          • currencyInternalName: optional. The internal name for that currency.

          • currencyLayer: optional. The internal name of the layer that currency is stored in. If it's not in a layer (like Points), omit. If it's not stored directly in a layer, instead use the next feature.

          • currencyLocation: optional. If your currency is stored in something inside a layer (e.g. a buyable's amount), you can access it this way. This is a function returning the object in "player" that contains the value (like player[this.layer].buyables)

          If you want to do something more complicated like upgrades that cost two currencies, you can override the purchase system with these (and you need to use fullDisplay as well)

          • canAfford(): OVERRIDE, a function determining if you are able to buy the upgrade

          • pay(): OVERRIDE, a function that reduces your currencies when you buy the upgrade

          `,13),r=[n];function l(o,p,h,u,d,c){return s(),t("div",null,r)}const y=e(i,[["render",l]]);export{f as __pageData,y as default}; diff --git a/assets/public_kronos_docs_upgrades.md.BY_E6naZ.lean.js b/assets/public_kronos_docs_upgrades.md.D1pH3BI1.lean.js similarity index 55% rename from assets/public_kronos_docs_upgrades.md.BY_E6naZ.lean.js rename to assets/public_kronos_docs_upgrades.md.D1pH3BI1.lean.js index 838eed96..88955310 100644 --- a/assets/public_kronos_docs_upgrades.md.BY_E6naZ.lean.js +++ b/assets/public_kronos_docs_upgrades.md.D1pH3BI1.lean.js @@ -1 +1 @@ -import{_ as e,c as t,o as s,ag as a}from"./chunks/framework.VBE0TPts.js";const f=JSON.parse('{"title":"Upgrades","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/upgrades.md","filePath":"public/kronos/docs/upgrades.md"}'),i={name:"public/kronos/docs/upgrades.md"},n=a("",13),r=[n];function l(o,p,h,u,c,d){return s(),t("div",null,r)}const y=e(i,[["render",l]]);export{f as __pageData,y as default}; +import{_ as e,q as t,p as s,ag as a}from"./chunks/framework.DvHfxfnp.js";const f=JSON.parse('{"title":"Upgrades","description":"","frontmatter":{},"headers":[],"relativePath":"public/kronos/docs/upgrades.md","filePath":"public/kronos/docs/upgrades.md"}'),i={name:"public/kronos/docs/upgrades.md"},n=a("",13),r=[n];function l(o,p,h,u,d,c){return s(),t("div",null,r)}const y=e(i,[["render",l]]);export{f as __pageData,y as default}; diff --git a/assets/public_lit_Old Things_2.0-format-changes.md.aA7GK9Ns.js b/assets/public_lit_Old Things_2.0-format-changes.md.BwaKJMKt.js similarity index 90% rename from assets/public_lit_Old Things_2.0-format-changes.md.aA7GK9Ns.js rename to assets/public_lit_Old Things_2.0-format-changes.md.BwaKJMKt.js index 40b2067e..8222585c 100644 --- a/assets/public_lit_Old Things_2.0-format-changes.md.aA7GK9Ns.js +++ b/assets/public_lit_Old Things_2.0-format-changes.md.BwaKJMKt.js @@ -1 +1 @@ -import{_ as e,c as a,o as t,ag as i}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"2.0 format changes","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/Old Things/2.0-format-changes.md","filePath":"public/lit/Old Things/2.0-format-changes.md"}'),l={name:"public/lit/Old Things/2.0-format-changes.md"},n=i('

          2.0 format changes

          • Temp format is changed from temp.something[layer] to temp[layer].something, for consistency
          • Challenges are now saved as an object with the amount of completions in each spot. (This will break saves.)
          • effectDisplay in Challenges and Upgrades no longer takes an argument, and neither does effect for Buyables
          • Buyable cost can take an argument for amount of buyables, but it needs to function if no argument is supplied (it should do the cost for the next purchase).
          • Generation of Points now happens in the main game loop (not in a layer update function), enabled by canGenPoints in game.js.
          • Changed fullLayerReset to layerDataReset, which takes an array of names of values to keep

          In addition, many names were changed, mostly expanding abbreviations:

          All instances of:

          • chall -> challenge
          • unl -> unlocked
          • upg -> upgrade (besides CSS)
          • amt -> amount
          • desc -> description
          • resCeil -> roundUpCost
          • order -> unlockOrder
          • incr_order -> increaseUnlockOrder

          Challenges:

          • desc -> challengeDescription
          • reward -> rewardDescription
          • effect -> rewardEffect
          • effectDisplay -> rewardDisplay
          • active -> challengeActive
          ',7),o=[n];function s(c,r,d,g,h,f){return t(),a("div",null,o)}const u=e(l,[["render",s]]);export{m as __pageData,u as default}; +import{_ as e,q as a,p as t,ag as i}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"2.0 format changes","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/Old Things/2.0-format-changes.md","filePath":"public/lit/Old Things/2.0-format-changes.md"}'),l={name:"public/lit/Old Things/2.0-format-changes.md"},n=i('

          2.0 format changes

          • Temp format is changed from temp.something[layer] to temp[layer].something, for consistency
          • Challenges are now saved as an object with the amount of completions in each spot. (This will break saves.)
          • effectDisplay in Challenges and Upgrades no longer takes an argument, and neither does effect for Buyables
          • Buyable cost can take an argument for amount of buyables, but it needs to function if no argument is supplied (it should do the cost for the next purchase).
          • Generation of Points now happens in the main game loop (not in a layer update function), enabled by canGenPoints in game.js.
          • Changed fullLayerReset to layerDataReset, which takes an array of names of values to keep

          In addition, many names were changed, mostly expanding abbreviations:

          All instances of:

          • chall -> challenge
          • unl -> unlocked
          • upg -> upgrade (besides CSS)
          • amt -> amount
          • desc -> description
          • resCeil -> roundUpCost
          • order -> unlockOrder
          • incr_order -> increaseUnlockOrder

          Challenges:

          • desc -> challengeDescription
          • reward -> rewardDescription
          • effect -> rewardEffect
          • effectDisplay -> rewardDisplay
          • active -> challengeActive
          ',7),o=[n];function s(r,c,d,g,h,p){return t(),a("div",null,o)}const u=e(l,[["render",s]]);export{m as __pageData,u as default}; diff --git a/assets/public_lit_Old Things_2.0-format-changes.md.aA7GK9Ns.lean.js b/assets/public_lit_Old Things_2.0-format-changes.md.BwaKJMKt.lean.js similarity index 59% rename from assets/public_lit_Old Things_2.0-format-changes.md.aA7GK9Ns.lean.js rename to assets/public_lit_Old Things_2.0-format-changes.md.BwaKJMKt.lean.js index db078341..e3b1cd6f 100644 --- a/assets/public_lit_Old Things_2.0-format-changes.md.aA7GK9Ns.lean.js +++ b/assets/public_lit_Old Things_2.0-format-changes.md.BwaKJMKt.lean.js @@ -1 +1 @@ -import{_ as e,c as a,o as t,ag as i}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"2.0 format changes","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/Old Things/2.0-format-changes.md","filePath":"public/lit/Old Things/2.0-format-changes.md"}'),l={name:"public/lit/Old Things/2.0-format-changes.md"},n=i("",7),o=[n];function s(c,r,d,g,h,f){return t(),a("div",null,o)}const u=e(l,[["render",s]]);export{m as __pageData,u as default}; +import{_ as e,q as a,p as t,ag as i}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"2.0 format changes","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/Old Things/2.0-format-changes.md","filePath":"public/lit/Old Things/2.0-format-changes.md"}'),l={name:"public/lit/Old Things/2.0-format-changes.md"},n=i("",7),o=[n];function s(r,c,d,g,h,p){return t(),a("div",null,o)}const u=e(l,[["render",s]]);export{m as __pageData,u as default}; diff --git a/assets/public_lit_README.md.84-k6GVT.js b/assets/public_lit_README.md.84-k6GVT.js new file mode 100644 index 00000000..d04aca9a --- /dev/null +++ b/assets/public_lit_README.md.84-k6GVT.js @@ -0,0 +1 @@ +import{_ as e,q as t,p as o,ag as a}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"Kronos","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/README.md","filePath":"public/lit/README.md"}'),r={name:"public/lit/README.md"},i=a('

          Kronos

          Play here.

          Updating the website:

          • git submodule update --remote
          • git add -A
          • git commit -m "Updated kronos"
          • git push
          ',4),l=[i];function s(c,d,n,_,p,u){return o(),t("div",null,l)}const f=e(r,[["render",s]]);export{m as __pageData,f as default}; diff --git a/assets/public_lit_README.md.84-k6GVT.lean.js b/assets/public_lit_README.md.84-k6GVT.lean.js new file mode 100644 index 00000000..08ea9034 --- /dev/null +++ b/assets/public_lit_README.md.84-k6GVT.lean.js @@ -0,0 +1 @@ +import{_ as e,q as t,p as o,ag as a}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"Kronos","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/README.md","filePath":"public/lit/README.md"}'),r={name:"public/lit/README.md"},i=a("",4),l=[i];function s(c,d,n,_,p,u){return o(),t("div",null,l)}const f=e(r,[["render",s]]);export{m as __pageData,f as default}; diff --git a/assets/public_lit_README.md.Dp_XDgLr.js b/assets/public_lit_README.md.Dp_XDgLr.js deleted file mode 100644 index 6074d51c..00000000 --- a/assets/public_lit_README.md.Dp_XDgLr.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as e,c as t,o,ag as a}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"Kronos","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/README.md","filePath":"public/lit/README.md"}'),r={name:"public/lit/README.md"},i=a('

          Kronos

          Play here.

          Updating the website:

          • git submodule update --remote
          • git add -A
          • git commit -m "Updated kronos"
          • git push
          ',4),l=[i];function s(c,d,n,_,p,u){return o(),t("div",null,l)}const f=e(r,[["render",s]]);export{m as __pageData,f as default}; diff --git a/assets/public_lit_README.md.Dp_XDgLr.lean.js b/assets/public_lit_README.md.Dp_XDgLr.lean.js deleted file mode 100644 index f8c25d12..00000000 --- a/assets/public_lit_README.md.Dp_XDgLr.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as e,c as t,o,ag as a}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"Kronos","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/README.md","filePath":"public/lit/README.md"}'),r={name:"public/lit/README.md"},i=a("",4),l=[i];function s(c,d,n,_,p,u){return o(),t("div",null,l)}const f=e(r,[["render",s]]);export{m as __pageData,f as default}; diff --git a/assets/public_lit_changelog.md.D7wPxHZ1.js b/assets/public_lit_changelog.md.BAnHXxRw.js similarity index 99% rename from assets/public_lit_changelog.md.D7wPxHZ1.js rename to assets/public_lit_changelog.md.BAnHXxRw.js index f89d6acb..0671abbf 100644 --- a/assets/public_lit_changelog.md.D7wPxHZ1.js +++ b/assets/public_lit_changelog.md.BAnHXxRw.js @@ -1 +1 @@ -import{_ as e,c as i,o as a,ag as l}from"./chunks/framework.VBE0TPts.js";const b=JSON.parse('{"title":"The Modding Tree changelog:","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/changelog.md","filePath":"public/lit/changelog.md"}'),t={name:"public/lit/changelog.md"},o=l('

          The Modding Tree changelog:

          v2.π: Incrementally Updated - 2/5/21

          • Performance improvements.
          • Fixed tooltips overlapping with the top display.
          • Clicking a popup dismisses it immediately.
          • Added support for bulk challenge completions.
          • "Best" is updated automatically.
          • Fixed keeping Decimal values on reset.
          • Code reorganization and style improvements by fudo.

          v2.3.5 - 12/21/20

          • Added resetTime, which tracks the time since a layer prestiged or was reset.
          • A layer node will be highlighted red if one of its subtabs is highlighted red.
          • Fixed issues with keeping challenges, buyables, and clickables on reset.
          • Improved the unlocking of custom layers.
          • Other minor fixes.

          v2.3.4 - 12/16/20

          • Added a node image feature.
          • Resource display now always shows the amount of the currency the layer's gain is based on.
          • Added spacing between tree nodes.
          • Another attempt to fix tooltip flickering.

          v2.3.3 - 12/13/20

          • Fixed the first node in a row always taking up space.
          • layerShown is now optional.
          • All prestige types can now use features for custom prestige types.

          v2.3.2 - 12/13/20

          • Fixed achievement/milestone popups.

          v2.3.1 - 12/12/20

          • Another attempt to fix flickering tooltips.
          • The "this" keyword should work everywhere except tabFormat arrays (although I may have missed some things).
          • Fixed tree branches not updating when scrolling on the right-side tab.
          • Fixed a spacing issue when a node's symbol is ""
          • Removed some old, unneeded files.

          v2.3: Cooler and Newer Edition - 12/10/20

          • Added achievement/milestone popups (thank you to Jacorb for this contribution!)
          • The changelog tab is back, and can be set in mod.js.
          • Layer nodes and respec buttons will not be clicked by pressing "enter".
          • Possible fix for flickering tooltips and strange transitions.
          • The victory screen text is configurable.
          • Added image and textStyle features to achievements.
          • Added an argument to use specific rows in an "upgrades" component.
          • Fixed the comma appearing in the main display when there was no effectDescription
          • Added the ability to easily make a tab that is a collection of layers in subtabs.
          • Improved spacing for embedding layers with subtabs into subtabs.

          v2.2.8 - 12/03/20

          • Double-clicking a layer node brings you to the main subtab for that layer.
          • Attempted to fix challenges visually updating a different way.
          • Added a softcap function for use in formulas.
          • Added displayRow feature, which lets layers be shown somewhere separate from where they are in the reset order (e.g. side layers)
          • Fixed autoupgrade issue.

          v2.2.7 - 11/30/20

          • Added autoUpgrade feature.
          • resource-display now shows resource gain per second if passiveGain is active.
          • Fixed formatting issues on some large numbers.
          • Better support for using classed objects in player and in layers/tmp.
          • Made hard resetting more effective.
          • Removed Herobrine from getStartClickables.

          v2.2.6 - 11/30/20

          • Added goalDescription for challenges and made the new "canComplete" system the standard.
          • Another attempt to fix challenges not visually updating.
          • Fixed side layers not appearing.
          • Fixed getStartClickables again.

          v2.2.5 - 11/29/20

          • Added features for overriding the displays and costs/goals of upgrades and challenges to make them fully custom.
          • best, total, and unlocked are always automatically added to layerData (but best and total will only display if you add them yourself).
          • Fixed getStartClickables.

          v2.2.4 - 11/28/20

          • Added softcap and softcapPower features (for Normal layers)
          • Offline time limit and default max tick length were fixed (previously the limits were 1000x too large)
          • Added fixOldSaves.
          • You can use HTML in main-display.
          • Fixed a number of minor oddities.

          v2.2.3 - 11/28/20

          • Layers will be highlighted if you can finish a challenge.
          • The "can complete challenge" color now overrides the "already completed" color.
          • Button nodes now work as side "layers".
          • Setting a tooltip to "" hides it entirely.

          v2.2.2 - 11/22/20

          • Fixed right half of the screen being unclickable in some circumstances.
          • Fixed tree branches being offset.
          • Fix to lastSafeTab.

          v2.2.1 - 11/7/20

          • Added a small highlight to layers you can meaningfully prestige on.
          • Added passiveGeneration and autoPrestige features to standardize prestige automation. (The old ways still work, but the new ones work better with other things)
          • Improved milestones visually a bit.
          • "best" and "total" are now only displayed if present in startData.
          • Fixed issues with things not updating visually. (Thank you to to Jacorb!)
          • Side layers and button nodes can now be highlighted.
          • Updated docs on the new tree-related features.

          v2.2: Uprooted - 11/7/20

          • You can now embed a layer inside of a subtab or microtab!
          • Added support for hiding or reformatting the tree tab
          • Added non-layer button nodes
          • Added shouldNotify to subtab/microtab buttons. (You can make them highlighted)
          • Added commas to large exponents.
          • Upgrades now only show "currently" if they have an effectDisplay (so not for constant effects).
          • Achievements are part of the default tab format.
          • NaN is now handled more intelligently.
          • Renamed files, and moved less relevant ones to another folder.
          • The "hide completed challenges" setting now only hides challenges at max completions.
          • Thank you to thepaperpilot for fixing errors in docs and improving the infobox appearance!
          • Many other minor fixes.

          v2.1.4 - 10/25/20

          • Added an infobox component. Thank you to thepaperpilot for this contribution!
          • Layer type is now optional, and defaults to "none".
          • Improved the look of bars and tab buttons.
          • Improved spacing between layer nodes (also thanks to thepaperpilot!)
          • Fixed the "blank" component breaking if only specifying the height.
          • Fixed some numbers not displaying with enough digits.
          • Made a few more things able to be functions.
          • A few other minor fixes.

          v2.1.3.1 - 10/21/20

          • Fixed the update function.

          v2.1.3 - 10/21/20

          • gainMult and gainExp are now optional.
          • Layer unlocking is now kept on reset.
          • Game should start up faster.
          • Layer updates now have a determined order and starts with earlier-rowed layers.
          • Automation now has a determined order and starts with later-rowed layers.
          • Fixed issues with resetting clickables and challenges.
          • Commas should no longer appear in the decimal places of a number.
          • Fixed potential issue in displaying the tree.

          v2.1.2 - 10/19/20

          • Added buyUpgrade function (buyUpg still works though)
          • Added author name to modInfo.
          • Fix to crash caused when the name of a subtab or microtab is changed.
          • Fixes to outdated information in docs.
          • Improvements to Discord links.
          • Thank you to thepaperpilot for contributing to this update!

          v2.1.1 - 10/17/20

          • Added resource-display component, which displays the base currency for the prestige layer, as well as the best and/or total of this layer's prestige currency.
          • Fixed the value for the base currency not updating in resource-display.

          v2.1: We should have thought of this sooner! - 10/17/20

          • Moved most of the code users will want to edit to mod.js, added documentation for it.
            • Specifically, modInfo, VERSION, canGenPoints, getPointGen, and maxTickLength
          • Added getStartPoints()
          • Added the ability to store non-layer-related data
          • Added the ability to display more things at the top of the tree tab below points.
          • Made the endgame condition customizable
          • Added "sell one" and "sell all" buttons for buyables.
          • Moved the old "game" to demo.js, and replaced it with a minimal game that won't cause issues when edited.
          • Fixed issues with version number
          • Fixed number formatting issue making things like "10e9" appear.

          v2.0.5 - 10/16/20

          • Made more features (including prestige parameters) able to be dynamic.
          • Layer nodes can be hidden but still take up space with "ghost" visibility
          • Added clickableEffect for real.
          • Fixed some visual issues with bars.
          • A few other minor tweaks and improvements.

          v2.0.4 - 10/16/20

          • Fixed HTML on buttons interfering with clicking on them.

          v2.0.3 - 10/16/20

          • Fixed hotkeys not displaying in info.
          • Fixed the game supressing all external hotkeys.
          • You can use more things as currencies for upgrade costs and challenge goals using currencyLocation.
          • Added maxTickLength, which can be used to prevent offline time or tab-switching from breaking time-limit based mechanics.
          • Made buyable respec buttons and clickable "master" buttons their own components, and gave them a hide/show feature.
          • Added a general "tooltip" feature for achievements.

          v2.0.2 - 10/15/20

          • Branches are now dynamic (they can be functions).
          • Fixed a crash related to offline time.
          • Fixed links being too wide.

          v2.0.1 - 10/15/20

          • Fixed side layers appearing multiple times.

          v2.0: The Pinnacle of Achievement Mountain - 10/15/20

          • Added progress bars, which are highly customizable and can be horizontal or vertical!
          • Added "side layers", displayed smaller and off to the side, and don't get reset by default. They can be used for global achievements and statistics. Speaking of which...
          • Added achievements!
          • Added clickables, a more generalized variant of buyables.
          • Almost every value in layer data can be either a function or a constant value!
          • Added support for multiple completions of challenges.
          • Added "none" prestige type, which removes the need for any other prestige-related features.
          • The points display and other gui elements stay at the top of the screen when the tree scrolls.
          • Added getter/setter functions for the amounts and effects of most Big Features
          • Moved modInfo to game.js, added a spot in modInfo for a Discord link, changelog link. Also added a separate mod version from the TMT version in VERSION.
          • Tree structure is based on layer data, no index.html editing is needed.
          • Tmp does not need to be manually updated.
          • You don't have to have the same amount of upgrades in every row (and challs and buyables)
          • "unlocked" is optional for all Big Components (defaults to true).
          • All displays will update correctly.
          • Changelog is no longer in index.html at all.
          • Generation of Points now happens in the main game loop
          • Changed the reset functions to make keeping things easier
          • Renamed many things to increase readability (see the list in the link below)
          • Improved documentation based on feedback

          v1.3.5:

          • Completely automated convertToDecimal, now you never have to worry about it again.
          • Branches can be defined without a color id. But they can also use hex values for color ids!
          • Created a tutorial for getting started with TMT and Github.
          • Page title is now automatically taken from mod name.

          v1.3.4 - 10/8/20

          • Added "midsection" feature to add things to a tab's layout while still keeping the standard layout.
          • Fix for being able to buy more buyables than you should.

          v1.3.3 - 10/7/20

          • Fix for the "order of operations" issue in temp.

          v1.3.1 - 10/7/20

          • Added custom CSS and tooltips for Layer Nodes.
          • Added custom CSS for upgrades, buyables, milestones, and challenges, both individually and layer-wide.
          • You can now use HTML in most display text!
          • You can now make milestones unlockable and not display immediately.
          • Fixed importing saves, and issue with upgrades not appearing, and probably more.
          • Optional "name" layer feature, used in confirmation messages.

          v1.3: Tabception... ception! - 10/7/20

          • Added subtabs! And also a Micro-tab component to let you make smaller subtab-esque areas anywhere.
          • Added a "custom" prestige formula type, and a number of features to support it.
          • Added points/sec display (can be disabled).
          • Added h-line, v-line and image-display components, plus components for individual upgrades, challenges, and milestones.
          • Added upgEffect, buyableEffect, and challEffect functions.
          • Added "hide completed challenges" setting.
          • Moved old changelogs to a separate place.
          • Fixed hasMilestone and incr_order.
          • Static layers now show the currency amount needed for the next one if you can buy max.

          v1.2.4 - 10/4/20

          • Layers are now highlighted if you can buy an upgrade, and a new feature, shouldNotify, lets you make it highlight other ways.
          • Fixed bugs with hasUpg, hasChall, hasMilestone, and inChallenge.
          • Changed the sample code to use the above functions for convenience.

          v1.2.3 - 10/3/20

          • Added a row component, which displays a list of objects in a row.
          • Added a column component, which displays a list of objects in a column (useful within a row).
          • Changed blanks to have a customizable width and height.

          v1.2: This Changes Everything! - 10/3/20

          • Many layer features can now be static values or functions. (This made some formats change, which will break old things)
          • You can now use the "this" keyword, to make code easier to transfer when making new layers.
          • Also added "this.layer", which is the current layer's name, and works on existing subfeatures (e.g. individual upgrades) as well! Subfeatures also have "this.id".
          • Fixed a big save issue. If you use a unique mod id, your save will never conflict with other mods.
          • Added a configurable offline time limit in modinfo at the top of index.html. (default 1 hour)
          • Added a few minor features, and updated the docs with new information.

          v1.1.1:

          • You can define hotkeys directly from layer config.

          v1.1: Enhanced Edition

          • Added "Buyables", which can function like Space Buildings or Enhancers.
          • Custom CSS can now be used on any component! Make the third argument an object with CSS parameters.
          • Lots of minor good things.

          v1.0:

          • First release.
          ',79),n=[o];function s(r,d,h,u,c,m){return a(),i("div",null,n)}const p=e(t,[["render",s]]);export{b as __pageData,p as default}; +import{_ as e,q as i,p as a,ag as l}from"./chunks/framework.DvHfxfnp.js";const b=JSON.parse('{"title":"The Modding Tree changelog:","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/changelog.md","filePath":"public/lit/changelog.md"}'),t={name:"public/lit/changelog.md"},o=l('

          The Modding Tree changelog:

          v2.π: Incrementally Updated - 2/5/21

          • Performance improvements.
          • Fixed tooltips overlapping with the top display.
          • Clicking a popup dismisses it immediately.
          • Added support for bulk challenge completions.
          • "Best" is updated automatically.
          • Fixed keeping Decimal values on reset.
          • Code reorganization and style improvements by fudo.

          v2.3.5 - 12/21/20

          • Added resetTime, which tracks the time since a layer prestiged or was reset.
          • A layer node will be highlighted red if one of its subtabs is highlighted red.
          • Fixed issues with keeping challenges, buyables, and clickables on reset.
          • Improved the unlocking of custom layers.
          • Other minor fixes.

          v2.3.4 - 12/16/20

          • Added a node image feature.
          • Resource display now always shows the amount of the currency the layer's gain is based on.
          • Added spacing between tree nodes.
          • Another attempt to fix tooltip flickering.

          v2.3.3 - 12/13/20

          • Fixed the first node in a row always taking up space.
          • layerShown is now optional.
          • All prestige types can now use features for custom prestige types.

          v2.3.2 - 12/13/20

          • Fixed achievement/milestone popups.

          v2.3.1 - 12/12/20

          • Another attempt to fix flickering tooltips.
          • The "this" keyword should work everywhere except tabFormat arrays (although I may have missed some things).
          • Fixed tree branches not updating when scrolling on the right-side tab.
          • Fixed a spacing issue when a node's symbol is ""
          • Removed some old, unneeded files.

          v2.3: Cooler and Newer Edition - 12/10/20

          • Added achievement/milestone popups (thank you to Jacorb for this contribution!)
          • The changelog tab is back, and can be set in mod.js.
          • Layer nodes and respec buttons will not be clicked by pressing "enter".
          • Possible fix for flickering tooltips and strange transitions.
          • The victory screen text is configurable.
          • Added image and textStyle features to achievements.
          • Added an argument to use specific rows in an "upgrades" component.
          • Fixed the comma appearing in the main display when there was no effectDescription
          • Added the ability to easily make a tab that is a collection of layers in subtabs.
          • Improved spacing for embedding layers with subtabs into subtabs.

          v2.2.8 - 12/03/20

          • Double-clicking a layer node brings you to the main subtab for that layer.
          • Attempted to fix challenges visually updating a different way.
          • Added a softcap function for use in formulas.
          • Added displayRow feature, which lets layers be shown somewhere separate from where they are in the reset order (e.g. side layers)
          • Fixed autoupgrade issue.

          v2.2.7 - 11/30/20

          • Added autoUpgrade feature.
          • resource-display now shows resource gain per second if passiveGain is active.
          • Fixed formatting issues on some large numbers.
          • Better support for using classed objects in player and in layers/tmp.
          • Made hard resetting more effective.
          • Removed Herobrine from getStartClickables.

          v2.2.6 - 11/30/20

          • Added goalDescription for challenges and made the new "canComplete" system the standard.
          • Another attempt to fix challenges not visually updating.
          • Fixed side layers not appearing.
          • Fixed getStartClickables again.

          v2.2.5 - 11/29/20

          • Added features for overriding the displays and costs/goals of upgrades and challenges to make them fully custom.
          • best, total, and unlocked are always automatically added to layerData (but best and total will only display if you add them yourself).
          • Fixed getStartClickables.

          v2.2.4 - 11/28/20

          • Added softcap and softcapPower features (for Normal layers)
          • Offline time limit and default max tick length were fixed (previously the limits were 1000x too large)
          • Added fixOldSaves.
          • You can use HTML in main-display.
          • Fixed a number of minor oddities.

          v2.2.3 - 11/28/20

          • Layers will be highlighted if you can finish a challenge.
          • The "can complete challenge" color now overrides the "already completed" color.
          • Button nodes now work as side "layers".
          • Setting a tooltip to "" hides it entirely.

          v2.2.2 - 11/22/20

          • Fixed right half of the screen being unclickable in some circumstances.
          • Fixed tree branches being offset.
          • Fix to lastSafeTab.

          v2.2.1 - 11/7/20

          • Added a small highlight to layers you can meaningfully prestige on.
          • Added passiveGeneration and autoPrestige features to standardize prestige automation. (The old ways still work, but the new ones work better with other things)
          • Improved milestones visually a bit.
          • "best" and "total" are now only displayed if present in startData.
          • Fixed issues with things not updating visually. (Thank you to to Jacorb!)
          • Side layers and button nodes can now be highlighted.
          • Updated docs on the new tree-related features.

          v2.2: Uprooted - 11/7/20

          • You can now embed a layer inside of a subtab or microtab!
          • Added support for hiding or reformatting the tree tab
          • Added non-layer button nodes
          • Added shouldNotify to subtab/microtab buttons. (You can make them highlighted)
          • Added commas to large exponents.
          • Upgrades now only show "currently" if they have an effectDisplay (so not for constant effects).
          • Achievements are part of the default tab format.
          • NaN is now handled more intelligently.
          • Renamed files, and moved less relevant ones to another folder.
          • The "hide completed challenges" setting now only hides challenges at max completions.
          • Thank you to thepaperpilot for fixing errors in docs and improving the infobox appearance!
          • Many other minor fixes.

          v2.1.4 - 10/25/20

          • Added an infobox component. Thank you to thepaperpilot for this contribution!
          • Layer type is now optional, and defaults to "none".
          • Improved the look of bars and tab buttons.
          • Improved spacing between layer nodes (also thanks to thepaperpilot!)
          • Fixed the "blank" component breaking if only specifying the height.
          • Fixed some numbers not displaying with enough digits.
          • Made a few more things able to be functions.
          • A few other minor fixes.

          v2.1.3.1 - 10/21/20

          • Fixed the update function.

          v2.1.3 - 10/21/20

          • gainMult and gainExp are now optional.
          • Layer unlocking is now kept on reset.
          • Game should start up faster.
          • Layer updates now have a determined order and starts with earlier-rowed layers.
          • Automation now has a determined order and starts with later-rowed layers.
          • Fixed issues with resetting clickables and challenges.
          • Commas should no longer appear in the decimal places of a number.
          • Fixed potential issue in displaying the tree.

          v2.1.2 - 10/19/20

          • Added buyUpgrade function (buyUpg still works though)
          • Added author name to modInfo.
          • Fix to crash caused when the name of a subtab or microtab is changed.
          • Fixes to outdated information in docs.
          • Improvements to Discord links.
          • Thank you to thepaperpilot for contributing to this update!

          v2.1.1 - 10/17/20

          • Added resource-display component, which displays the base currency for the prestige layer, as well as the best and/or total of this layer's prestige currency.
          • Fixed the value for the base currency not updating in resource-display.

          v2.1: We should have thought of this sooner! - 10/17/20

          • Moved most of the code users will want to edit to mod.js, added documentation for it.
            • Specifically, modInfo, VERSION, canGenPoints, getPointGen, and maxTickLength
          • Added getStartPoints()
          • Added the ability to store non-layer-related data
          • Added the ability to display more things at the top of the tree tab below points.
          • Made the endgame condition customizable
          • Added "sell one" and "sell all" buttons for buyables.
          • Moved the old "game" to demo.js, and replaced it with a minimal game that won't cause issues when edited.
          • Fixed issues with version number
          • Fixed number formatting issue making things like "10e9" appear.

          v2.0.5 - 10/16/20

          • Made more features (including prestige parameters) able to be dynamic.
          • Layer nodes can be hidden but still take up space with "ghost" visibility
          • Added clickableEffect for real.
          • Fixed some visual issues with bars.
          • A few other minor tweaks and improvements.

          v2.0.4 - 10/16/20

          • Fixed HTML on buttons interfering with clicking on them.

          v2.0.3 - 10/16/20

          • Fixed hotkeys not displaying in info.
          • Fixed the game supressing all external hotkeys.
          • You can use more things as currencies for upgrade costs and challenge goals using currencyLocation.
          • Added maxTickLength, which can be used to prevent offline time or tab-switching from breaking time-limit based mechanics.
          • Made buyable respec buttons and clickable "master" buttons their own components, and gave them a hide/show feature.
          • Added a general "tooltip" feature for achievements.

          v2.0.2 - 10/15/20

          • Branches are now dynamic (they can be functions).
          • Fixed a crash related to offline time.
          • Fixed links being too wide.

          v2.0.1 - 10/15/20

          • Fixed side layers appearing multiple times.

          v2.0: The Pinnacle of Achievement Mountain - 10/15/20

          • Added progress bars, which are highly customizable and can be horizontal or vertical!
          • Added "side layers", displayed smaller and off to the side, and don't get reset by default. They can be used for global achievements and statistics. Speaking of which...
          • Added achievements!
          • Added clickables, a more generalized variant of buyables.
          • Almost every value in layer data can be either a function or a constant value!
          • Added support for multiple completions of challenges.
          • Added "none" prestige type, which removes the need for any other prestige-related features.
          • The points display and other gui elements stay at the top of the screen when the tree scrolls.
          • Added getter/setter functions for the amounts and effects of most Big Features
          • Moved modInfo to game.js, added a spot in modInfo for a Discord link, changelog link. Also added a separate mod version from the TMT version in VERSION.
          • Tree structure is based on layer data, no index.html editing is needed.
          • Tmp does not need to be manually updated.
          • You don't have to have the same amount of upgrades in every row (and challs and buyables)
          • "unlocked" is optional for all Big Components (defaults to true).
          • All displays will update correctly.
          • Changelog is no longer in index.html at all.
          • Generation of Points now happens in the main game loop
          • Changed the reset functions to make keeping things easier
          • Renamed many things to increase readability (see the list in the link below)
          • Improved documentation based on feedback

          v1.3.5:

          • Completely automated convertToDecimal, now you never have to worry about it again.
          • Branches can be defined without a color id. But they can also use hex values for color ids!
          • Created a tutorial for getting started with TMT and Github.
          • Page title is now automatically taken from mod name.

          v1.3.4 - 10/8/20

          • Added "midsection" feature to add things to a tab's layout while still keeping the standard layout.
          • Fix for being able to buy more buyables than you should.

          v1.3.3 - 10/7/20

          • Fix for the "order of operations" issue in temp.

          v1.3.1 - 10/7/20

          • Added custom CSS and tooltips for Layer Nodes.
          • Added custom CSS for upgrades, buyables, milestones, and challenges, both individually and layer-wide.
          • You can now use HTML in most display text!
          • You can now make milestones unlockable and not display immediately.
          • Fixed importing saves, and issue with upgrades not appearing, and probably more.
          • Optional "name" layer feature, used in confirmation messages.

          v1.3: Tabception... ception! - 10/7/20

          • Added subtabs! And also a Micro-tab component to let you make smaller subtab-esque areas anywhere.
          • Added a "custom" prestige formula type, and a number of features to support it.
          • Added points/sec display (can be disabled).
          • Added h-line, v-line and image-display components, plus components for individual upgrades, challenges, and milestones.
          • Added upgEffect, buyableEffect, and challEffect functions.
          • Added "hide completed challenges" setting.
          • Moved old changelogs to a separate place.
          • Fixed hasMilestone and incr_order.
          • Static layers now show the currency amount needed for the next one if you can buy max.

          v1.2.4 - 10/4/20

          • Layers are now highlighted if you can buy an upgrade, and a new feature, shouldNotify, lets you make it highlight other ways.
          • Fixed bugs with hasUpg, hasChall, hasMilestone, and inChallenge.
          • Changed the sample code to use the above functions for convenience.

          v1.2.3 - 10/3/20

          • Added a row component, which displays a list of objects in a row.
          • Added a column component, which displays a list of objects in a column (useful within a row).
          • Changed blanks to have a customizable width and height.

          v1.2: This Changes Everything! - 10/3/20

          • Many layer features can now be static values or functions. (This made some formats change, which will break old things)
          • You can now use the "this" keyword, to make code easier to transfer when making new layers.
          • Also added "this.layer", which is the current layer's name, and works on existing subfeatures (e.g. individual upgrades) as well! Subfeatures also have "this.id".
          • Fixed a big save issue. If you use a unique mod id, your save will never conflict with other mods.
          • Added a configurable offline time limit in modinfo at the top of index.html. (default 1 hour)
          • Added a few minor features, and updated the docs with new information.

          v1.1.1:

          • You can define hotkeys directly from layer config.

          v1.1: Enhanced Edition

          • Added "Buyables", which can function like Space Buildings or Enhancers.
          • Custom CSS can now be used on any component! Make the third argument an object with CSS parameters.
          • Lots of minor good things.

          v1.0:

          • First release.
          ',79),n=[o];function s(r,d,h,u,c,m){return a(),i("div",null,n)}const p=e(t,[["render",s]]);export{b as __pageData,p as default}; diff --git a/assets/public_lit_changelog.md.D7wPxHZ1.lean.js b/assets/public_lit_changelog.md.BAnHXxRw.lean.js similarity index 70% rename from assets/public_lit_changelog.md.D7wPxHZ1.lean.js rename to assets/public_lit_changelog.md.BAnHXxRw.lean.js index d4fd911e..e9947b3e 100644 --- a/assets/public_lit_changelog.md.D7wPxHZ1.lean.js +++ b/assets/public_lit_changelog.md.BAnHXxRw.lean.js @@ -1 +1 @@ -import{_ as e,c as i,o as a,ag as l}from"./chunks/framework.VBE0TPts.js";const b=JSON.parse('{"title":"The Modding Tree changelog:","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/changelog.md","filePath":"public/lit/changelog.md"}'),t={name:"public/lit/changelog.md"},o=l("",79),n=[o];function s(r,d,h,u,c,m){return a(),i("div",null,n)}const p=e(t,[["render",s]]);export{b as __pageData,p as default}; +import{_ as e,q as i,p as a,ag as l}from"./chunks/framework.DvHfxfnp.js";const b=JSON.parse('{"title":"The Modding Tree changelog:","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/changelog.md","filePath":"public/lit/changelog.md"}'),t={name:"public/lit/changelog.md"},o=l("",79),n=[o];function s(r,d,h,u,c,m){return a(),i("div",null,n)}const p=e(t,[["render",s]]);export{b as __pageData,p as default}; diff --git a/assets/public_lit_docs_!general-info.md.DwyPmy7N.js b/assets/public_lit_docs_!general-info.md.D2rjMfl1.js similarity index 98% rename from assets/public_lit_docs_!general-info.md.DwyPmy7N.js rename to assets/public_lit_docs_!general-info.md.D2rjMfl1.js index 2347f3c4..e47e23c6 100644 --- a/assets/public_lit_docs_!general-info.md.DwyPmy7N.js +++ b/assets/public_lit_docs_!general-info.md.D2rjMfl1.js @@ -1 +1 @@ -import{_ as e,c as a,o as t,ag as o}from"./chunks/framework.VBE0TPts.js";const y=JSON.parse('{"title":"The-Modding-Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/!general-info.md","filePath":"public/lit/docs/!general-info.md"}'),n={name:"public/lit/docs/!general-info.md"},r=o('

          The-Modding-Tree

          The main way to add content is through creating layers. You can either add a layer directly in the layers object in layerSupport.js, or declare it in another file and register it by calling addLayer(layername, layerdata). There is an example layer registration in layers.js showing the recommended method. It is just an example and can be freely deleted. You can also use it as a reference or a base for your own layers.

          The first thing you need to do is fill out the modInfo object at the top of mod.js to set your mod's name, ID (a string), and other information. A unique modId will prevent your mod's saves from conflicting with other mods. Note that changing this after people have started playing will reset their saves.

          Most of the time, you won't need to dive deep into the code to create things, but you still can if you really want to, for example to add new Vue components in v.js.

          The Modding Tree uses break_eternity.js to store large values. This means that many numbers are Decimal objects, and must be treated differently. For example, you have to use new Decimal(x) to create a Decimal value instead of a plain number, and perform operations on them by calling functions. e.g, instead of x = x + y, use x = x.add(y). Keep in mind this also applies to comparison operators, which should be replaced with calling the .gt, .gte, .lt, .lte, .eq, and .neq functions. See the break_eternity.js docs for more details on working with Decimal values.

          Almost all values can be either a constant value, or a dynamic value. Dynamic values are defined by putting a function that returns what the value should be at any given time.

          All display text can use basic HTML elements (But you can't use most Vue features there).

          While reading this documentation, the following key will be used when describing features:

          • No label: This is required and the game may crash if it isn't included.
          • sometimes required: This is may be required, depending on other things in the layer.
          • optional: You can leave this out if you don't intend to use that feature for the layer.
          • assigned automagically: This value will be set automatically and override any value you set.
          • deprecated: This feature is not recommended to be used anymore, and may be removed in future versions of TMT.

          Table of Contents

          General

          • Getting Started: Getting your own copy of the code set up with Github Desktop.
          • Main mod info: How to set up general things for your mod in mod.js.
          • Basic layer breakdown: Breaking down the components of a layer with minimal features.
          • Layer features: Explanations of all of the different properties that you can give a layer.
          • Custom Tab Layouts: An optional way to give your tabs a different layout. You can even create entirely new components to use.
          • Custom game layouts: You can get rid of the tree tab, add buttons and other things to the tree, or even customize the tab's layout like a layer tab.
          • Updating TMT: Using Github Desktop to update your mod's version of TMT.

          Common components

          • Upgrades: How to create upgrades for a layer.
          • Milestones: How to create milestones for a layer.
          • Buyables: Create rebuyable upgrades for your layer (with the option to make them respec-able). Can be used to make Enhancers or Space Buildings.
          • Clickables: A more generalized variant of buyables, for any kind of thing that is sometimes clickable. Between these and Buyables, you can do just about anything.

          Other components and features

          • Challenges: How to create challenges for a layer.
          • Bars: Display some information as a progress bar, gauge, or similar. They are highly customizable, and can be horizontal and vertical as well.
          • Subtabs and Microtabs: Create subtabs for your tabs, as well as "microtab" components that you can put inside the tabs. You can even use them to embed a layer inside another layer!
          • Achievements: How to create achievements for a layer (or for the whole game).
          • Infoboxes: Boxes containing text that can be shown or hidden.
          • Trees: Make your own trees. You can make non-layer button nodes too!
          ',16),i=[r];function s(l,d,h,c,u,m){return t(),a("div",null,i)}const b=e(n,[["render",s]]);export{y as __pageData,b as default}; +import{_ as e,q as a,p as t,ag as o}from"./chunks/framework.DvHfxfnp.js";const y=JSON.parse('{"title":"The-Modding-Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/!general-info.md","filePath":"public/lit/docs/!general-info.md"}'),n={name:"public/lit/docs/!general-info.md"},r=o('

          The-Modding-Tree

          The main way to add content is through creating layers. You can either add a layer directly in the layers object in layerSupport.js, or declare it in another file and register it by calling addLayer(layername, layerdata). There is an example layer registration in layers.js showing the recommended method. It is just an example and can be freely deleted. You can also use it as a reference or a base for your own layers.

          The first thing you need to do is fill out the modInfo object at the top of mod.js to set your mod's name, ID (a string), and other information. A unique modId will prevent your mod's saves from conflicting with other mods. Note that changing this after people have started playing will reset their saves.

          Most of the time, you won't need to dive deep into the code to create things, but you still can if you really want to, for example to add new Vue components in v.js.

          The Modding Tree uses break_eternity.js to store large values. This means that many numbers are Decimal objects, and must be treated differently. For example, you have to use new Decimal(x) to create a Decimal value instead of a plain number, and perform operations on them by calling functions. e.g, instead of x = x + y, use x = x.add(y). Keep in mind this also applies to comparison operators, which should be replaced with calling the .gt, .gte, .lt, .lte, .eq, and .neq functions. See the break_eternity.js docs for more details on working with Decimal values.

          Almost all values can be either a constant value, or a dynamic value. Dynamic values are defined by putting a function that returns what the value should be at any given time.

          All display text can use basic HTML elements (But you can't use most Vue features there).

          While reading this documentation, the following key will be used when describing features:

          • No label: This is required and the game may crash if it isn't included.
          • sometimes required: This is may be required, depending on other things in the layer.
          • optional: You can leave this out if you don't intend to use that feature for the layer.
          • assigned automagically: This value will be set automatically and override any value you set.
          • deprecated: This feature is not recommended to be used anymore, and may be removed in future versions of TMT.

          Table of Contents

          General

          • Getting Started: Getting your own copy of the code set up with Github Desktop.
          • Main mod info: How to set up general things for your mod in mod.js.
          • Basic layer breakdown: Breaking down the components of a layer with minimal features.
          • Layer features: Explanations of all of the different properties that you can give a layer.
          • Custom Tab Layouts: An optional way to give your tabs a different layout. You can even create entirely new components to use.
          • Custom game layouts: You can get rid of the tree tab, add buttons and other things to the tree, or even customize the tab's layout like a layer tab.
          • Updating TMT: Using Github Desktop to update your mod's version of TMT.

          Common components

          • Upgrades: How to create upgrades for a layer.
          • Milestones: How to create milestones for a layer.
          • Buyables: Create rebuyable upgrades for your layer (with the option to make them respec-able). Can be used to make Enhancers or Space Buildings.
          • Clickables: A more generalized variant of buyables, for any kind of thing that is sometimes clickable. Between these and Buyables, you can do just about anything.

          Other components and features

          • Challenges: How to create challenges for a layer.
          • Bars: Display some information as a progress bar, gauge, or similar. They are highly customizable, and can be horizontal and vertical as well.
          • Subtabs and Microtabs: Create subtabs for your tabs, as well as "microtab" components that you can put inside the tabs. You can even use them to embed a layer inside another layer!
          • Achievements: How to create achievements for a layer (or for the whole game).
          • Infoboxes: Boxes containing text that can be shown or hidden.
          • Trees: Make your own trees. You can make non-layer button nodes too!
          ',16),i=[r];function s(l,d,h,c,u,m){return t(),a("div",null,i)}const b=e(n,[["render",s]]);export{y as __pageData,b as default}; diff --git a/assets/public_lit_docs_!general-info.md.DwyPmy7N.lean.js b/assets/public_lit_docs_!general-info.md.D2rjMfl1.lean.js similarity index 71% rename from assets/public_lit_docs_!general-info.md.DwyPmy7N.lean.js rename to assets/public_lit_docs_!general-info.md.D2rjMfl1.lean.js index dfdb65f4..95b31886 100644 --- a/assets/public_lit_docs_!general-info.md.DwyPmy7N.lean.js +++ b/assets/public_lit_docs_!general-info.md.D2rjMfl1.lean.js @@ -1 +1 @@ -import{_ as e,c as a,o as t,ag as o}from"./chunks/framework.VBE0TPts.js";const y=JSON.parse('{"title":"The-Modding-Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/!general-info.md","filePath":"public/lit/docs/!general-info.md"}'),n={name:"public/lit/docs/!general-info.md"},r=o("",16),i=[r];function s(l,d,h,c,u,m){return t(),a("div",null,i)}const b=e(n,[["render",s]]);export{y as __pageData,b as default}; +import{_ as e,q as a,p as t,ag as o}from"./chunks/framework.DvHfxfnp.js";const y=JSON.parse('{"title":"The-Modding-Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/!general-info.md","filePath":"public/lit/docs/!general-info.md"}'),n={name:"public/lit/docs/!general-info.md"},r=o("",16),i=[r];function s(l,d,h,c,u,m){return t(),a("div",null,i)}const b=e(n,[["render",s]]);export{y as __pageData,b as default}; diff --git a/assets/public_lit_docs_achievements.md.DaBdzZ0g.js b/assets/public_lit_docs_achievements.md.D0gRoIWt.js similarity index 97% rename from assets/public_lit_docs_achievements.md.DaBdzZ0g.js rename to assets/public_lit_docs_achievements.md.D0gRoIWt.js index 17d6ec7f..26545c33 100644 --- a/assets/public_lit_docs_achievements.md.DaBdzZ0g.js +++ b/assets/public_lit_docs_achievements.md.D0gRoIWt.js @@ -1,4 +1,4 @@ -import{_ as e,c as t,o as i,ag as a}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"Achievements","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/achievements.md","filePath":"public/lit/docs/achievements.md"}'),s={name:"public/lit/docs/achievements.md"},n=a(`

          Achievements

          Achievements are awarded to the player when they meet a certain goal, and optionally give some benefit. Currently they are pretty basic, but additional features will be added later to help.

          You can make global achievements by putting them in a side layer by making its row equal to "side" instead of a number.

          Useful functions for dealing with achievements and implementing their effects:

          • hasAchievement(layer, id): determine if the player has the Achievement.
          • achievementEffect(layer, id): Returns the current effects of the achievement, if any.

          Achievements should be formatted like this:

          js
          achievements: {
          +import{_ as e,q as t,p as i,ag as a}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"Achievements","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/achievements.md","filePath":"public/lit/docs/achievements.md"}'),s={name:"public/lit/docs/achievements.md"},n=a(`

          Achievements

          Achievements are awarded to the player when they meet a certain goal, and optionally give some benefit. Currently they are pretty basic, but additional features will be added later to help.

          You can make global achievements by putting them in a side layer by making its row equal to "side" instead of a number.

          Useful functions for dealing with achievements and implementing their effects:

          • hasAchievement(layer, id): determine if the player has the Achievement.
          • achievementEffect(layer, id): Returns the current effects of the achievement, if any.

          Achievements should be formatted like this:

          js
          achievements: {
               rows: # of rows,
               cols: # of columns,
               11: {
          diff --git a/assets/public_lit_docs_achievements.md.DaBdzZ0g.lean.js b/assets/public_lit_docs_achievements.md.D0gRoIWt.lean.js
          similarity index 70%
          rename from assets/public_lit_docs_achievements.md.DaBdzZ0g.lean.js
          rename to assets/public_lit_docs_achievements.md.D0gRoIWt.lean.js
          index e4bb3785..fce4d49e 100644
          --- a/assets/public_lit_docs_achievements.md.DaBdzZ0g.lean.js
          +++ b/assets/public_lit_docs_achievements.md.D0gRoIWt.lean.js
          @@ -1 +1 @@
          -import{_ as e,c as t,o as i,ag as a}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"Achievements","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/achievements.md","filePath":"public/lit/docs/achievements.md"}'),s={name:"public/lit/docs/achievements.md"},n=a("",11),l=[n];function o(h,p,r,c,d,u){return i(),t("div",null,l)}const k=e(s,[["render",o]]);export{m as __pageData,k as default};
          +import{_ as e,q as t,p as i,ag as a}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"Achievements","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/achievements.md","filePath":"public/lit/docs/achievements.md"}'),s={name:"public/lit/docs/achievements.md"},n=a("",11),l=[n];function o(h,p,r,c,d,u){return i(),t("div",null,l)}const k=e(s,[["render",o]]);export{m as __pageData,k as default};
          diff --git a/assets/public_lit_docs_bars.md.CnS5IMvm.js b/assets/public_lit_docs_bars.md.DFEFprv8.js
          similarity index 97%
          rename from assets/public_lit_docs_bars.md.CnS5IMvm.js
          rename to assets/public_lit_docs_bars.md.DFEFprv8.js
          index 92ad88d9..ac7b2fa2 100644
          --- a/assets/public_lit_docs_bars.md.CnS5IMvm.js
          +++ b/assets/public_lit_docs_bars.md.DFEFprv8.js
          @@ -1,4 +1,4 @@
          -import{_ as s,c as i,o as a,ag as t}from"./chunks/framework.VBE0TPts.js";const u=JSON.parse('{"title":"Bars","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/bars.md","filePath":"public/lit/docs/bars.md"}'),e={name:"public/lit/docs/bars.md"},n=t(`

          Bars

          Bars let you display information in a more direct way. It can be a progress bar, health bar, capacity gauge, or anything else.

          Bars are defined like other Big Features:

          js
          bars: {
          +import{_ as s,q as i,p as a,ag as t}from"./chunks/framework.DvHfxfnp.js";const u=JSON.parse('{"title":"Bars","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/bars.md","filePath":"public/lit/docs/bars.md"}'),e={name:"public/lit/docs/bars.md"},n=t(`

          Bars

          Bars let you display information in a more direct way. It can be a progress bar, health bar, capacity gauge, or anything else.

          Bars are defined like other Big Features:

          js
          bars: {
               bigBar: {
                   direction: RIGHT,
                   width: 200,
          diff --git a/assets/public_lit_docs_bars.md.CnS5IMvm.lean.js b/assets/public_lit_docs_bars.md.DFEFprv8.lean.js
          similarity index 68%
          rename from assets/public_lit_docs_bars.md.CnS5IMvm.lean.js
          rename to assets/public_lit_docs_bars.md.DFEFprv8.lean.js
          index 07e13b8d..cc37b5a8 100644
          --- a/assets/public_lit_docs_bars.md.CnS5IMvm.lean.js
          +++ b/assets/public_lit_docs_bars.md.DFEFprv8.lean.js
          @@ -1 +1 @@
          -import{_ as s,c as i,o as a,ag as t}from"./chunks/framework.VBE0TPts.js";const u=JSON.parse('{"title":"Bars","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/bars.md","filePath":"public/lit/docs/bars.md"}'),e={name:"public/lit/docs/bars.md"},n=t("",6),l=[n];function r(p,h,o,d,k,c){return a(),i("div",null,l)}const E=s(e,[["render",r]]);export{u as __pageData,E as default};
          +import{_ as s,q as i,p as a,ag as t}from"./chunks/framework.DvHfxfnp.js";const u=JSON.parse('{"title":"Bars","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/bars.md","filePath":"public/lit/docs/bars.md"}'),e={name:"public/lit/docs/bars.md"},n=t("",6),l=[n];function r(p,h,o,d,k,c){return a(),i("div",null,l)}const E=s(e,[["render",r]]);export{u as __pageData,E as default};
          diff --git a/assets/public_lit_docs_basic-layer-breakdown.md.B_DwLl-5.js b/assets/public_lit_docs_basic-layer-breakdown.md.DKkhjhoJ.js
          similarity index 97%
          rename from assets/public_lit_docs_basic-layer-breakdown.md.B_DwLl-5.js
          rename to assets/public_lit_docs_basic-layer-breakdown.md.DKkhjhoJ.js
          index 55b22c62..c6445277 100644
          --- a/assets/public_lit_docs_basic-layer-breakdown.md.B_DwLl-5.js
          +++ b/assets/public_lit_docs_basic-layer-breakdown.md.DKkhjhoJ.js
          @@ -1,4 +1,4 @@
          -import{_ as s,c as i,o as a,ag as n}from"./chunks/framework.VBE0TPts.js";const g=JSON.parse('{"title":"Basic layer breakdown","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/basic-layer-breakdown.md","filePath":"public/lit/docs/basic-layer-breakdown.md"}'),t={name:"public/lit/docs/basic-layer-breakdown.md"},e=n(`

          Basic layer breakdown

          This is a very minimal layer with minimal features. Most things will require additional features.

          js
          addLayer("p", {
          +import{_ as s,q as i,p as a,ag as n}from"./chunks/framework.DvHfxfnp.js";const g=JSON.parse('{"title":"Basic layer breakdown","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/basic-layer-breakdown.md","filePath":"public/lit/docs/basic-layer-breakdown.md"}'),t={name:"public/lit/docs/basic-layer-breakdown.md"},e=n(`

          Basic layer breakdown

          This is a very minimal layer with minimal features. Most things will require additional features.

          js
          addLayer("p", {
               startData() { return {                  // startData is a function that returns default data for a layer. 
                   unlocked: true,                     // You can add more variables here to add them to your layer.
                   points: new Decimal(0),             // "points" is the internal name for the main resource of the layer.
          @@ -25,4 +25,4 @@ import{_ as s,c as i,o as a,ag as n}from"./chunks/framework.VBE0TPts.js";const g
               },
           
               layerShown() { return true }            // Returns a bool for if this layer's node should be visible in the tree.
          -})
          `,3),h=[e];function l(k,p,r,E,d,o){return a(),i("div",null,h)}const c=s(t,[["render",l]]);export{g as __pageData,c as default}; +})
          `,3),h=[e];function l(p,k,r,E,d,o){return a(),i("div",null,h)}const c=s(t,[["render",l]]);export{g as __pageData,c as default}; diff --git a/assets/public_lit_docs_basic-layer-breakdown.md.B_DwLl-5.lean.js b/assets/public_lit_docs_basic-layer-breakdown.md.DKkhjhoJ.lean.js similarity index 59% rename from assets/public_lit_docs_basic-layer-breakdown.md.B_DwLl-5.lean.js rename to assets/public_lit_docs_basic-layer-breakdown.md.DKkhjhoJ.lean.js index f14387d5..e7b61993 100644 --- a/assets/public_lit_docs_basic-layer-breakdown.md.B_DwLl-5.lean.js +++ b/assets/public_lit_docs_basic-layer-breakdown.md.DKkhjhoJ.lean.js @@ -1 +1 @@ -import{_ as s,c as i,o as a,ag as n}from"./chunks/framework.VBE0TPts.js";const g=JSON.parse('{"title":"Basic layer breakdown","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/basic-layer-breakdown.md","filePath":"public/lit/docs/basic-layer-breakdown.md"}'),t={name:"public/lit/docs/basic-layer-breakdown.md"},e=n("",3),h=[e];function l(k,p,r,E,d,o){return a(),i("div",null,h)}const c=s(t,[["render",l]]);export{g as __pageData,c as default}; +import{_ as s,q as i,p as a,ag as n}from"./chunks/framework.DvHfxfnp.js";const g=JSON.parse('{"title":"Basic layer breakdown","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/basic-layer-breakdown.md","filePath":"public/lit/docs/basic-layer-breakdown.md"}'),t={name:"public/lit/docs/basic-layer-breakdown.md"},e=n("",3),h=[e];function l(p,k,r,E,d,o){return a(),i("div",null,h)}const c=s(t,[["render",l]]);export{g as __pageData,c as default}; diff --git a/assets/public_lit_docs_buyables.md.Cr6AwZWn.js b/assets/public_lit_docs_buyables.md.DrqS8H2k.js similarity index 98% rename from assets/public_lit_docs_buyables.md.Cr6AwZWn.js rename to assets/public_lit_docs_buyables.md.DrqS8H2k.js index 1882eb8d..a3ac2efb 100644 --- a/assets/public_lit_docs_buyables.md.Cr6AwZWn.js +++ b/assets/public_lit_docs_buyables.md.DrqS8H2k.js @@ -1,4 +1,4 @@ -import{_ as s,c as i,o as a,ag as t}from"./chunks/framework.VBE0TPts.js";const y=JSON.parse('{"title":"Buyables","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/buyables.md","filePath":"public/lit/docs/buyables.md"}'),e={name:"public/lit/docs/buyables.md"},l=t(`

          Buyables

          Buyables are usually things that can be bought multiple times with scaling costs. If you set a respec function, the player can reset the purchases to get their currency back.

          The amount of a buyable owned is a Decimal.

          Useful functions for dealing with buyables and implementing their effects:

          • getBuyableAmount(layer, id): get the amount of the buyable the player has
          • setBuyableAmount(layer, id, amount): set the amount of the buyable the player has
          • buyableEffect(layer, id): Returns the current effects of the buyable, if any.

          Buyables should be formatted like this:

          js
          buyables: {
          +import{_ as s,q as i,p as a,ag as t}from"./chunks/framework.DvHfxfnp.js";const y=JSON.parse('{"title":"Buyables","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/buyables.md","filePath":"public/lit/docs/buyables.md"}'),e={name:"public/lit/docs/buyables.md"},l=t(`

          Buyables

          Buyables are usually things that can be bought multiple times with scaling costs. If you set a respec function, the player can reset the purchases to get their currency back.

          The amount of a buyable owned is a Decimal.

          Useful functions for dealing with buyables and implementing their effects:

          • getBuyableAmount(layer, id): get the amount of the buyable the player has
          • setBuyableAmount(layer, id, amount): set the amount of the buyable the player has
          • buyableEffect(layer, id): Returns the current effects of the buyable, if any.

          Buyables should be formatted like this:

          js
          buyables: {
               rows: # of rows,
               cols: # of columns,
               11: {
          diff --git a/assets/public_lit_docs_buyables.md.Cr6AwZWn.lean.js b/assets/public_lit_docs_buyables.md.DrqS8H2k.lean.js
          similarity index 69%
          rename from assets/public_lit_docs_buyables.md.Cr6AwZWn.lean.js
          rename to assets/public_lit_docs_buyables.md.DrqS8H2k.lean.js
          index eafdbda5..f1a14baa 100644
          --- a/assets/public_lit_docs_buyables.md.Cr6AwZWn.lean.js
          +++ b/assets/public_lit_docs_buyables.md.DrqS8H2k.lean.js
          @@ -1 +1 @@
          -import{_ as s,c as i,o as a,ag as t}from"./chunks/framework.VBE0TPts.js";const y=JSON.parse('{"title":"Buyables","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/buyables.md","filePath":"public/lit/docs/buyables.md"}'),e={name:"public/lit/docs/buyables.md"},l=t("",12),n=[l];function h(p,k,r,o,d,E){return a(),i("div",null,n)}const g=s(e,[["render",h]]);export{y as __pageData,g as default};
          +import{_ as s,q as i,p as a,ag as t}from"./chunks/framework.DvHfxfnp.js";const y=JSON.parse('{"title":"Buyables","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/buyables.md","filePath":"public/lit/docs/buyables.md"}'),e={name:"public/lit/docs/buyables.md"},l=t("",12),n=[l];function h(p,k,r,o,d,E){return a(),i("div",null,n)}const g=s(e,[["render",h]]);export{y as __pageData,g as default};
          diff --git a/assets/public_lit_docs_challenges.md.BXbZcSAe.js b/assets/public_lit_docs_challenges.md.DtmSP6zf.js
          similarity index 98%
          rename from assets/public_lit_docs_challenges.md.BXbZcSAe.js
          rename to assets/public_lit_docs_challenges.md.DtmSP6zf.js
          index 2c06d582..da1ee59f 100644
          --- a/assets/public_lit_docs_challenges.md.BXbZcSAe.js
          +++ b/assets/public_lit_docs_challenges.md.DtmSP6zf.js
          @@ -1,4 +1,4 @@
          -import{_ as e,c as i,o as s,ag as a}from"./chunks/framework.VBE0TPts.js";const f=JSON.parse('{"title":"Challenges","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/challenges.md","filePath":"public/lit/docs/challenges.md"}'),t={name:"public/lit/docs/challenges.md"},n=a(`

          Challenges

          Challenges can have fully customizable win conditions. Useful functions for dealing with Challenges and implementing their effects:

          • inChallenge(layer, id): determine if the player is in a given challenge (or another challenge on the same layer that counts as this one).
          • hasChallenge(layer, id): determine if the player has completed the challenge.
          • challengeCompletions(layer, id): determine how many times the player completed the challenge.
          • challengeEffect(layer, id): Returns the current effects of the challenge, if any.

          Challenges are stored in the following format:

          js
          challenges: {
          +import{_ as e,q as i,p as s,ag as a}from"./chunks/framework.DvHfxfnp.js";const f=JSON.parse('{"title":"Challenges","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/challenges.md","filePath":"public/lit/docs/challenges.md"}'),t={name:"public/lit/docs/challenges.md"},n=a(`

          Challenges

          Challenges can have fully customizable win conditions. Useful functions for dealing with Challenges and implementing their effects:

          • inChallenge(layer, id): determine if the player is in a given challenge (or another challenge on the same layer that counts as this one).
          • hasChallenge(layer, id): determine if the player has completed the challenge.
          • challengeCompletions(layer, id): determine how many times the player completed the challenge.
          • challengeEffect(layer, id): Returns the current effects of the challenge, if any.

          Challenges are stored in the following format:

          js
          challenges: {
               rows: # of rows,
               cols: # of columns,
               11: {
          diff --git a/assets/public_lit_docs_challenges.md.BXbZcSAe.lean.js b/assets/public_lit_docs_challenges.md.DtmSP6zf.lean.js
          similarity index 70%
          rename from assets/public_lit_docs_challenges.md.BXbZcSAe.lean.js
          rename to assets/public_lit_docs_challenges.md.DtmSP6zf.lean.js
          index 137e81aa..ad595381 100644
          --- a/assets/public_lit_docs_challenges.md.BXbZcSAe.lean.js
          +++ b/assets/public_lit_docs_challenges.md.DtmSP6zf.lean.js
          @@ -1 +1 @@
          -import{_ as e,c as i,o as s,ag as a}from"./chunks/framework.VBE0TPts.js";const f=JSON.parse('{"title":"Challenges","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/challenges.md","filePath":"public/lit/docs/challenges.md"}'),t={name:"public/lit/docs/challenges.md"},n=a("",10),l=[n];function o(h,r,p,c,g,d){return s(),i("div",null,l)}const k=e(t,[["render",o]]);export{f as __pageData,k as default};
          +import{_ as e,q as i,p as s,ag as a}from"./chunks/framework.DvHfxfnp.js";const f=JSON.parse('{"title":"Challenges","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/challenges.md","filePath":"public/lit/docs/challenges.md"}'),t={name:"public/lit/docs/challenges.md"},n=a("",10),l=[n];function o(h,r,p,c,g,d){return s(),i("div",null,l)}const k=e(t,[["render",o]]);export{f as __pageData,k as default};
          diff --git a/assets/public_lit_docs_clickables.md.DQD4wzqI.js b/assets/public_lit_docs_clickables.md.CoIWXGHw.js
          similarity index 97%
          rename from assets/public_lit_docs_clickables.md.DQD4wzqI.js
          rename to assets/public_lit_docs_clickables.md.CoIWXGHw.js
          index 12fb1011..6d8a1193 100644
          --- a/assets/public_lit_docs_clickables.md.DQD4wzqI.js
          +++ b/assets/public_lit_docs_clickables.md.CoIWXGHw.js
          @@ -1,4 +1,4 @@
          -import{_ as e,c as s,o as i,ag as a}from"./chunks/framework.VBE0TPts.js";const b=JSON.parse('{"title":"Clickables","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/clickables.md","filePath":"public/lit/docs/clickables.md"}'),t={name:"public/lit/docs/clickables.md"},l=a(`

          Clickables

          Clickables are any kind of thing that you can click for an effect. They're a more generalized version of Buyables.

          DO NOT USE THESE TO MAKE THINGS THAT YOU CLICK REPEATEDLY FOR A BONUS BECAUSE THOSE ARE AWFUL.

          There are several differences between the two. One is that a buyable's saved data is its amount as a Decimal, while Clickables store a "state" which can be a number or string, but not Decimal, array, or object). Buyables have a number of extra features which you can see on their page. Clickables also have a smaller default size.

          Useful functions for dealing with achievements and implementing their effects:

          • getClickableState(layer, id): get the state of the clickable the player has
          • setClickableState(layer, id, state): set the state of the buyable the player has
          • clickableEffect(layer, id): Returns the current effects of the clickable, if any.

          Clickables should be formatted like this:

          js
          clickables: {
          +import{_ as e,q as s,p as i,ag as a}from"./chunks/framework.DvHfxfnp.js";const b=JSON.parse('{"title":"Clickables","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/clickables.md","filePath":"public/lit/docs/clickables.md"}'),t={name:"public/lit/docs/clickables.md"},l=a(`

          Clickables

          Clickables are any kind of thing that you can click for an effect. They're a more generalized version of Buyables.

          DO NOT USE THESE TO MAKE THINGS THAT YOU CLICK REPEATEDLY FOR A BONUS BECAUSE THOSE ARE AWFUL.

          There are several differences between the two. One is that a buyable's saved data is its amount as a Decimal, while Clickables store a "state" which can be a number or string, but not Decimal, array, or object). Buyables have a number of extra features which you can see on their page. Clickables also have a smaller default size.

          Useful functions for dealing with achievements and implementing their effects:

          • getClickableState(layer, id): get the state of the clickable the player has
          • setClickableState(layer, id, state): set the state of the buyable the player has
          • clickableEffect(layer, id): Returns the current effects of the clickable, if any.

          Clickables should be formatted like this:

          js
          clickables: {
               rows: # of rows,
               cols: # of columns,
               11: {
          diff --git a/assets/public_lit_docs_clickables.md.DQD4wzqI.lean.js b/assets/public_lit_docs_clickables.md.CoIWXGHw.lean.js
          similarity index 70%
          rename from assets/public_lit_docs_clickables.md.DQD4wzqI.lean.js
          rename to assets/public_lit_docs_clickables.md.CoIWXGHw.lean.js
          index 0ba89b9b..4695a558 100644
          --- a/assets/public_lit_docs_clickables.md.DQD4wzqI.lean.js
          +++ b/assets/public_lit_docs_clickables.md.CoIWXGHw.lean.js
          @@ -1 +1 @@
          -import{_ as e,c as s,o as i,ag as a}from"./chunks/framework.VBE0TPts.js";const b=JSON.parse('{"title":"Clickables","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/clickables.md","filePath":"public/lit/docs/clickables.md"}'),t={name:"public/lit/docs/clickables.md"},l=a("",12),n=[l];function o(c,r,h,p,k,u){return i(),s("div",null,n)}const g=e(t,[["render",o]]);export{b as __pageData,g as default};
          +import{_ as e,q as s,p as i,ag as a}from"./chunks/framework.DvHfxfnp.js";const b=JSON.parse('{"title":"Clickables","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/clickables.md","filePath":"public/lit/docs/clickables.md"}'),t={name:"public/lit/docs/clickables.md"},l=a("",12),n=[l];function o(c,r,h,p,k,u){return i(),s("div",null,n)}const g=e(t,[["render",o]]);export{b as __pageData,g as default};
          diff --git a/assets/public_lit_docs_custom-tab-layouts.md.CHYKKeeX.js b/assets/public_lit_docs_custom-tab-layouts.md.C-TlZHYA.js
          similarity index 98%
          rename from assets/public_lit_docs_custom-tab-layouts.md.CHYKKeeX.js
          rename to assets/public_lit_docs_custom-tab-layouts.md.C-TlZHYA.js
          index e1f4e8b3..1f382ea5 100644
          --- a/assets/public_lit_docs_custom-tab-layouts.md.CHYKKeeX.js
          +++ b/assets/public_lit_docs_custom-tab-layouts.md.C-TlZHYA.js
          @@ -1,4 +1,4 @@
          -import{_ as s,c as i,o as a,ag as t}from"./chunks/framework.VBE0TPts.js";const y=JSON.parse('{"title":"Custom tab layouts","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/custom-tab-layouts.md","filePath":"public/lit/docs/custom-tab-layouts.md"}'),e={name:"public/lit/docs/custom-tab-layouts.md"},n=t(`

          Custom tab layouts

          Note: If you are using subtabs, tabFormat is used differently, but you still use the same format within each subtabs. See here for more on subtabs.

          Custom tab layouts can be used to do basically anything in a tab window, especially combined with the "style" layer feature. The tabFormat feature is an array of things, like this:

          js
          tabFormat: [
          +import{_ as s,q as i,p as a,ag as t}from"./chunks/framework.DvHfxfnp.js";const y=JSON.parse('{"title":"Custom tab layouts","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/custom-tab-layouts.md","filePath":"public/lit/docs/custom-tab-layouts.md"}'),e={name:"public/lit/docs/custom-tab-layouts.md"},n=t(`

          Custom tab layouts

          Note: If you are using subtabs, tabFormat is used differently, but you still use the same format within each subtabs. See here for more on subtabs.

          Custom tab layouts can be used to do basically anything in a tab window, especially combined with the "style" layer feature. The tabFormat feature is an array of things, like this:

          js
          tabFormat: [
               "main-display",
               ["prestige-button", function() { return "Melt your points into " }],
               "blank",
          diff --git a/assets/public_lit_docs_custom-tab-layouts.md.CHYKKeeX.lean.js b/assets/public_lit_docs_custom-tab-layouts.md.C-TlZHYA.lean.js
          similarity index 72%
          rename from assets/public_lit_docs_custom-tab-layouts.md.CHYKKeeX.lean.js
          rename to assets/public_lit_docs_custom-tab-layouts.md.C-TlZHYA.lean.js
          index 189455d6..a24d47d3 100644
          --- a/assets/public_lit_docs_custom-tab-layouts.md.CHYKKeeX.lean.js
          +++ b/assets/public_lit_docs_custom-tab-layouts.md.C-TlZHYA.lean.js
          @@ -1 +1 @@
          -import{_ as s,c as i,o as a,ag as t}from"./chunks/framework.VBE0TPts.js";const y=JSON.parse('{"title":"Custom tab layouts","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/custom-tab-layouts.md","filePath":"public/lit/docs/custom-tab-layouts.md"}'),e={name:"public/lit/docs/custom-tab-layouts.md"},n=t("",9),l=[n];function h(o,p,r,u,k,d){return a(),i("div",null,l)}const E=s(e,[["render",h]]);export{y as __pageData,E as default};
          +import{_ as s,q as i,p as a,ag as t}from"./chunks/framework.DvHfxfnp.js";const y=JSON.parse('{"title":"Custom tab layouts","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/custom-tab-layouts.md","filePath":"public/lit/docs/custom-tab-layouts.md"}'),e={name:"public/lit/docs/custom-tab-layouts.md"},n=t("",9),l=[n];function h(o,p,r,u,k,d){return a(),i("div",null,l)}const E=s(e,[["render",h]]);export{y as __pageData,E as default};
          diff --git a/assets/public_lit_docs_getting-started.md.BoU9JbJY.js b/assets/public_lit_docs_getting-started.md.BoU9JbJY.js
          deleted file mode 100644
          index 6754355b..00000000
          --- a/assets/public_lit_docs_getting-started.md.BoU9JbJY.js
          +++ /dev/null
          @@ -1 +0,0 @@
          -import{_ as e,c as t,o,ag as i}from"./chunks/framework.VBE0TPts.js";const y=JSON.parse('{"title":"Getting started","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/getting-started.md","filePath":"public/lit/docs/getting-started.md"}'),a={name:"public/lit/docs/getting-started.md"},n=i('

          Getting started

          Welcome to The Modding Tree!

          Using the Modding Tree, at its simplest level, just requires getting a copy of it onto your computer. However, if you do it the right way, it will help in many ways.

          Don't let the word "Github" scare you away. It's actually much easier to use than most people think, especially because most people use it the hard way. The key is Github Desktop, which lets you do everything you need to, without even touching the command line.

          The benefits of using Github:

          • It makes it much, much easier to update The Modding Tree.
          • You can share your work without any extra effort using githack, or with a bit more effort, set up a github.io site.
          • It lets you undo changes to your code, and to have multiple versions of it.
          • It lets you collaborate with other people, if you want to.

          Getting set up with Github Desktop, Visual Studio Code, and The Modding Tree:

          1. Install Github Desktop and Visual Studio Code.

          2. Make a Github account. You can handle this on your own.

          3. Log in on your browser, and go back to The Modding Tree page. At the top right, there should be a button that says "fork". Click on it, and then on your username. You now have your own fork, or copy, of The Modding Tree.

          4. Open Github Desktop and log in. Ignore everything else and choose "clone a repository". A "repository" is basically a "Github project", like The Modding Tree. "Cloning" is downloading a copy of the repository to your computer.

          5. Look for The Modding Tree in the list of repositiories (it should be the only one) and click "clone".

          6. Select that you're using it for your own purposes, and click continue. It will download the files and handle everything.

          Using your repository

          1. Click on "show in explorer/finder" to the right, and then open the index.html file in the folder. The page should open up on your browser. This will let you view and test your project locally!

          2. To edit your project, click "open in VSCode" in Github Desktop.

          3. Open mod.js in VSCode, and look at the top part where it has a "modInfo" object. Fill in your mod's name to whatever you want, and change the id as well. (It can be any string value, and it's used to determine where the savefile is. Make it something that's probably unique, and don't change it again later or else it'll effectively wipe existing saves)

          4. Save mod.js, and then reload index.html in your browser. The title on the tab, as well as on the info page, will now be updated! You can reload the page every time you change the code to test it quickly and easily.

          5. Go back to Github Desktop. It's time to save your changes into the git system by making a "commit". This basically saves your work and creates a snapshot of what your code looks like at this moment, allowing you to look back at it later.

          6. At the bottom right corner, add a summary of your changes, and then click "commit to master".

          7. Finally, at the top middle, click "push origin" to push your changes out onto the online repository.

          8. You can view your project on line, or share it with others, by going to https://raw.githack.com/[YOUR-GITHUB-USERNAME]/The-Modding-Tree/master/index.html

          And now, you have successfully used Github! You can look at the documentation to see how The Modding Tree's system works and to make your mod a reality.

          ',11),r=[n];function s(l,h,u,d,p,c){return o(),t("div",null,r)}const m=e(a,[["render",s]]);export{y as __pageData,m as default}; diff --git a/assets/public_lit_docs_getting-started.md.BoU9JbJY.lean.js b/assets/public_lit_docs_getting-started.md.BoU9JbJY.lean.js deleted file mode 100644 index 80979006..00000000 --- a/assets/public_lit_docs_getting-started.md.BoU9JbJY.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as e,c as t,o,ag as i}from"./chunks/framework.VBE0TPts.js";const y=JSON.parse('{"title":"Getting started","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/getting-started.md","filePath":"public/lit/docs/getting-started.md"}'),a={name:"public/lit/docs/getting-started.md"},n=i("",11),r=[n];function s(l,h,u,d,p,c){return o(),t("div",null,r)}const m=e(a,[["render",s]]);export{y as __pageData,m as default}; diff --git a/assets/public_lit_docs_getting-started.md.BxRLZ8_n.js b/assets/public_lit_docs_getting-started.md.BxRLZ8_n.js new file mode 100644 index 00000000..64c3cf67 --- /dev/null +++ b/assets/public_lit_docs_getting-started.md.BxRLZ8_n.js @@ -0,0 +1 @@ +import{_ as e,q as t,p as o,ag as i}from"./chunks/framework.DvHfxfnp.js";const y=JSON.parse('{"title":"Getting started","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/getting-started.md","filePath":"public/lit/docs/getting-started.md"}'),a={name:"public/lit/docs/getting-started.md"},n=i('

          Getting started

          Welcome to The Modding Tree!

          Using the Modding Tree, at its simplest level, just requires getting a copy of it onto your computer. However, if you do it the right way, it will help in many ways.

          Don't let the word "Github" scare you away. It's actually much easier to use than most people think, especially because most people use it the hard way. The key is Github Desktop, which lets you do everything you need to, without even touching the command line.

          The benefits of using Github:

          • It makes it much, much easier to update The Modding Tree.
          • You can share your work without any extra effort using githack, or with a bit more effort, set up a github.io site.
          • It lets you undo changes to your code, and to have multiple versions of it.
          • It lets you collaborate with other people, if you want to.

          Getting set up with Github Desktop, Visual Studio Code, and The Modding Tree:

          1. Install Github Desktop and Visual Studio Code.

          2. Make a Github account. You can handle this on your own.

          3. Log in on your browser, and go back to The Modding Tree page. At the top right, there should be a button that says "fork". Click on it, and then on your username. You now have your own fork, or copy, of The Modding Tree.

          4. Open Github Desktop and log in. Ignore everything else and choose "clone a repository". A "repository" is basically a "Github project", like The Modding Tree. "Cloning" is downloading a copy of the repository to your computer.

          5. Look for The Modding Tree in the list of repositiories (it should be the only one) and click "clone".

          6. Select that you're using it for your own purposes, and click continue. It will download the files and handle everything.

          Using your repository

          1. Click on "show in explorer/finder" to the right, and then open the index.html file in the folder. The page should open up on your browser. This will let you view and test your project locally!

          2. To edit your project, click "open in VSCode" in Github Desktop.

          3. Open mod.js in VSCode, and look at the top part where it has a "modInfo" object. Fill in your mod's name to whatever you want, and change the id as well. (It can be any string value, and it's used to determine where the savefile is. Make it something that's probably unique, and don't change it again later or else it'll effectively wipe existing saves)

          4. Save mod.js, and then reload index.html in your browser. The title on the tab, as well as on the info page, will now be updated! You can reload the page every time you change the code to test it quickly and easily.

          5. Go back to Github Desktop. It's time to save your changes into the git system by making a "commit". This basically saves your work and creates a snapshot of what your code looks like at this moment, allowing you to look back at it later.

          6. At the bottom right corner, add a summary of your changes, and then click "commit to master".

          7. Finally, at the top middle, click "push origin" to push your changes out onto the online repository.

          8. You can view your project on line, or share it with others, by going to https://raw.githack.com/[YOUR-GITHUB-USERNAME]/The-Modding-Tree/master/index.html

          And now, you have successfully used Github! You can look at the documentation to see how The Modding Tree's system works and to make your mod a reality.

          ',11),r=[n];function s(l,h,u,d,p,c){return o(),t("div",null,r)}const m=e(a,[["render",s]]);export{y as __pageData,m as default}; diff --git a/assets/public_lit_docs_getting-started.md.BxRLZ8_n.lean.js b/assets/public_lit_docs_getting-started.md.BxRLZ8_n.lean.js new file mode 100644 index 00000000..776884a1 --- /dev/null +++ b/assets/public_lit_docs_getting-started.md.BxRLZ8_n.lean.js @@ -0,0 +1 @@ +import{_ as e,q as t,p as o,ag as i}from"./chunks/framework.DvHfxfnp.js";const y=JSON.parse('{"title":"Getting started","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/getting-started.md","filePath":"public/lit/docs/getting-started.md"}'),a={name:"public/lit/docs/getting-started.md"},n=i("",11),r=[n];function s(l,h,u,d,p,c){return o(),t("div",null,r)}const m=e(a,[["render",s]]);export{y as __pageData,m as default}; diff --git a/assets/public_lit_docs_infoboxes.md.71lto7Te.js b/assets/public_lit_docs_infoboxes.md.C0nPRfky.js similarity index 96% rename from assets/public_lit_docs_infoboxes.md.71lto7Te.js rename to assets/public_lit_docs_infoboxes.md.C0nPRfky.js index 26c543d8..08b8da9b 100644 --- a/assets/public_lit_docs_infoboxes.md.71lto7Te.js +++ b/assets/public_lit_docs_infoboxes.md.C0nPRfky.js @@ -1,4 +1,4 @@ -import{_ as s,c as i,o as e,ag as t}from"./chunks/framework.VBE0TPts.js";const u=JSON.parse('{"title":"Infoboxes","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/infoboxes.md","filePath":"public/lit/docs/infoboxes.md"}'),a={name:"public/lit/docs/infoboxes.md"},n=t(`

          Infoboxes

          Infoboxes are good for displaying "lore", or story elements, as well as for explaining complicated things.

          In the default tab layout, the first infobox will be displayed at the very top of the tab.

          Infoboxes are defined like other Big Features:

          js
          infoboxes: {
          +import{_ as s,q as i,p as e,ag as t}from"./chunks/framework.DvHfxfnp.js";const u=JSON.parse('{"title":"Infoboxes","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/infoboxes.md","filePath":"public/lit/docs/infoboxes.md"}'),a={name:"public/lit/docs/infoboxes.md"},n=t(`

          Infoboxes

          Infoboxes are good for displaying "lore", or story elements, as well as for explaining complicated things.

          In the default tab layout, the first infobox will be displayed at the very top of the tab.

          Infoboxes are defined like other Big Features:

          js
          infoboxes: {
               lore: {
                   title: "foo",
                   body() { return "bar" },
          diff --git a/assets/public_lit_docs_infoboxes.md.71lto7Te.lean.js b/assets/public_lit_docs_infoboxes.md.C0nPRfky.lean.js
          similarity index 69%
          rename from assets/public_lit_docs_infoboxes.md.71lto7Te.lean.js
          rename to assets/public_lit_docs_infoboxes.md.C0nPRfky.lean.js
          index 70004bbe..7d32cf25 100644
          --- a/assets/public_lit_docs_infoboxes.md.71lto7Te.lean.js
          +++ b/assets/public_lit_docs_infoboxes.md.C0nPRfky.lean.js
          @@ -1 +1 @@
          -import{_ as s,c as i,o as e,ag as t}from"./chunks/framework.VBE0TPts.js";const u=JSON.parse('{"title":"Infoboxes","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/infoboxes.md","filePath":"public/lit/docs/infoboxes.md"}'),a={name:"public/lit/docs/infoboxes.md"},n=t("",7),o=[n];function l(p,h,r,d,c,k){return e(),i("div",null,o)}const y=s(a,[["render",l]]);export{u as __pageData,y as default};
          +import{_ as s,q as i,p as e,ag as t}from"./chunks/framework.DvHfxfnp.js";const u=JSON.parse('{"title":"Infoboxes","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/infoboxes.md","filePath":"public/lit/docs/infoboxes.md"}'),a={name:"public/lit/docs/infoboxes.md"},n=t("",7),o=[n];function l(p,h,r,d,c,k){return e(),i("div",null,o)}const y=s(a,[["render",l]]);export{u as __pageData,y as default};
          diff --git a/assets/public_lit_docs_layer-features.md.FrysJ_Sk.js b/assets/public_lit_docs_layer-features.md.DF81fjyw.js
          similarity index 99%
          rename from assets/public_lit_docs_layer-features.md.FrysJ_Sk.js
          rename to assets/public_lit_docs_layer-features.md.DF81fjyw.js
          index e6d24083..45c53e01 100644
          --- a/assets/public_lit_docs_layer-features.md.FrysJ_Sk.js
          +++ b/assets/public_lit_docs_layer-features.md.DF81fjyw.js
          @@ -1,4 +1,4 @@
          -import{_ as e,c as t,o as a,ag as s}from"./chunks/framework.VBE0TPts.js";const y=JSON.parse('{"title":"Layer Features","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/layer-features.md","filePath":"public/lit/docs/layer-features.md"}'),i={name:"public/lit/docs/layer-features.md"},o=s(`

          Layer Features

          This is a more comprehensive list of established features to add to layers. You can add more freely, if you want to have other functions or values associated with your layer. These have special functionality, though.

          You can make almost any value dynamic by using a function in its place, including all display strings and styling/color features.

          Layer Definition features

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar to access the saved value. It makes copying code to new layers easier. It is also assigned to all upgrades and buyables and such.

          • name: optional. used in reset confirmations (and the default infobox title). If absent, it just uses the layer's id.

          • startData(): A function to return the default save data for this layer. Add any variables you have to it. Make sure to use Decimal values rather than normal numbers.

            Standard values: - Required: - unlocked: a bool determining if this layer is unlocked or not - points: a Decimal, the main currency for the layer - Optional: - total: A Decimal, tracks total amount of main prestige currency. Always tracked, but only shown if you add it here. - best: A Decimal, tracks highest amount of main prestige currency. Always tracked, but only shown if you add it here. - unlockOrder: used to keep track of relevant layers unlocked before this one. - resetTime: A number, time since this layer was last prestiged (or reset by another layer)

          • color: A color associated with this layer, used in many places. (A string in hex format with a #)

          • row: The row of the layer, starting at 0. This affects where the node appears on the standard tree, and which resets affect the layer.

            Using "side" instead of a number will cause the layer to appear off to the side as a smaller node (useful for achievements and statistics). Side layers are not affected by resets unless you add a doReset to them.

          • displayRow: OVERRIDE Changes where the layer node appears without changing where it is in the reset order.

          • resource: Name of the main currency you gain by resetting on this layer.

          • effect(): optional. A function that calculates and returns the current values of any bonuses inherent to the main currency. Can return a value or an object containing multiple values. You will also have to implement the effect where it is applied.

          • effectDescription: optional. A function that returns a description of this effect. If the text stays constant, it can just be a string.

          • layerShown(): optional, A function returning a bool which determines if this layer's node should be visible on the tree. It can also return "ghost", which will hide the layer, but its node will still take up space in the tree. Defaults to true.

          • hotkeys: optional. An array containing information on any hotkeys associated with this layer:

            js
            hotkeys: [
            +import{_ as e,q as t,p as a,ag as s}from"./chunks/framework.DvHfxfnp.js";const y=JSON.parse('{"title":"Layer Features","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/layer-features.md","filePath":"public/lit/docs/layer-features.md"}'),i={name:"public/lit/docs/layer-features.md"},o=s(`

            Layer Features

            This is a more comprehensive list of established features to add to layers. You can add more freely, if you want to have other functions or values associated with your layer. These have special functionality, though.

            You can make almost any value dynamic by using a function in its place, including all display strings and styling/color features.

            Layer Definition features

            • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar to access the saved value. It makes copying code to new layers easier. It is also assigned to all upgrades and buyables and such.

            • name: optional. used in reset confirmations (and the default infobox title). If absent, it just uses the layer's id.

            • startData(): A function to return the default save data for this layer. Add any variables you have to it. Make sure to use Decimal values rather than normal numbers.

              Standard values: - Required: - unlocked: a bool determining if this layer is unlocked or not - points: a Decimal, the main currency for the layer - Optional: - total: A Decimal, tracks total amount of main prestige currency. Always tracked, but only shown if you add it here. - best: A Decimal, tracks highest amount of main prestige currency. Always tracked, but only shown if you add it here. - unlockOrder: used to keep track of relevant layers unlocked before this one. - resetTime: A number, time since this layer was last prestiged (or reset by another layer)

            • color: A color associated with this layer, used in many places. (A string in hex format with a #)

            • row: The row of the layer, starting at 0. This affects where the node appears on the standard tree, and which resets affect the layer.

              Using "side" instead of a number will cause the layer to appear off to the side as a smaller node (useful for achievements and statistics). Side layers are not affected by resets unless you add a doReset to them.

            • displayRow: OVERRIDE Changes where the layer node appears without changing where it is in the reset order.

            • resource: Name of the main currency you gain by resetting on this layer.

            • effect(): optional. A function that calculates and returns the current values of any bonuses inherent to the main currency. Can return a value or an object containing multiple values. You will also have to implement the effect where it is applied.

            • effectDescription: optional. A function that returns a description of this effect. If the text stays constant, it can just be a string.

            • layerShown(): optional, A function returning a bool which determines if this layer's node should be visible on the tree. It can also return "ghost", which will hide the layer, but its node will still take up space in the tree. Defaults to true.

            • hotkeys: optional. An array containing information on any hotkeys associated with this layer:

              js
              hotkeys: [
                   {
                       key: "p", // What the hotkey button is. Use uppercase if it's combined with shift, or "ctrl+x" for holding down ctrl.
                       description: "p: reset your points for prestige points", // The description of the hotkey that is displayed in the game's How To Play tab
              diff --git a/assets/public_lit_docs_layer-features.md.FrysJ_Sk.lean.js b/assets/public_lit_docs_layer-features.md.DF81fjyw.lean.js
              similarity index 71%
              rename from assets/public_lit_docs_layer-features.md.FrysJ_Sk.lean.js
              rename to assets/public_lit_docs_layer-features.md.DF81fjyw.lean.js
              index dc0250a7..10b98e0e 100644
              --- a/assets/public_lit_docs_layer-features.md.FrysJ_Sk.lean.js
              +++ b/assets/public_lit_docs_layer-features.md.DF81fjyw.lean.js
              @@ -1 +1 @@
              -import{_ as e,c as t,o as a,ag as s}from"./chunks/framework.VBE0TPts.js";const y=JSON.parse('{"title":"Layer Features","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/layer-features.md","filePath":"public/lit/docs/layer-features.md"}'),i={name:"public/lit/docs/layer-features.md"},o=s("",19),r=[o];function n(l,h,u,p,d,c){return a(),t("div",null,r)}const f=e(i,[["render",n]]);export{y as __pageData,f as default};
              +import{_ as e,q as t,p as a,ag as s}from"./chunks/framework.DvHfxfnp.js";const y=JSON.parse('{"title":"Layer Features","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/layer-features.md","filePath":"public/lit/docs/layer-features.md"}'),i={name:"public/lit/docs/layer-features.md"},o=s("",19),r=[o];function n(l,h,u,p,d,c){return a(),t("div",null,r)}const f=e(i,[["render",n]]);export{y as __pageData,f as default};
              diff --git a/assets/public_lit_docs_main-mod-info.md.B2Wd3G2L.js b/assets/public_lit_docs_main-mod-info.md.CcRWcMdS.js
              similarity index 98%
              rename from assets/public_lit_docs_main-mod-info.md.B2Wd3G2L.js
              rename to assets/public_lit_docs_main-mod-info.md.CcRWcMdS.js
              index 7e974ed7..ac403b45 100644
              --- a/assets/public_lit_docs_main-mod-info.md.B2Wd3G2L.js
              +++ b/assets/public_lit_docs_main-mod-info.md.CcRWcMdS.js
              @@ -1,4 +1,4 @@
              -import{_ as i,c as t,o as e,ag as s}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"mod.js","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/main-mod-info.md","filePath":"public/lit/docs/main-mod-info.md"}'),a={name:"public/lit/docs/main-mod-info.md"},n=s(`

              mod.js

              All of the non-layer code and data that you're likely to edit is here in mod.js! Everything in mod.js will not be altered by updates, besides the addition of new things.

              Here's a breakdown of what's in it:

              • modInfo is where most of the basic configuration for the mod is. It contains:

                • name: The name of your mod. (a string)

                • id: The id for your mod, a unique string that is used to determine savefile location. Setting it is important!

                • author: The name of the author, displayed in the info tab.

                • pointsName: This changes what is displayed instead of "points" for the main currency. (It does not affect it in the code.)

                • discordName, discordLink: If you have a Discord server or other discussion place, you can add a link to it.

                  "discordName" is the text on the link, and "discordLink" is the url of an invite. If you're using a Discord invite, please make sure it's set to never expire.

                • offlineLimit: The maximum amount of offline time that the player can accumulate, in hours. Any extra time is lost. (a number)

                  This is useful because most of these mods are fast-paced enough that too much offline time ruins the balance, such as the time in between updates. That is why I suggest developers disable offline time on their own savefile.

                • initialStartPoints: A Decimal for the amount of points a new player should start with.

              • VERSION is used to describe the current version of your mod. It contains:

                • num: The mod's version number, displayed at the top right of the tree tab.
                • name: The version's name, displayed alongside the number in the info tab.
              • changelog is the HTML displayed in the changelog tab.

              • doNotCallTheseFunctionsEveryTick is very important. TMT calls every function anywhere in "layers" every tick to store the result, unless specifically told not to. Functions that have are used to do an action need to be identified. "Official" functions (those in the documentation) are all fine, but if you make any new ones, add their names to this array.

              js
              // (The ones here are examples, all official functions are already taken care of)
              +import{_ as i,q as t,p as e,ag as s}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"mod.js","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/main-mod-info.md","filePath":"public/lit/docs/main-mod-info.md"}'),a={name:"public/lit/docs/main-mod-info.md"},n=s(`

              mod.js

              All of the non-layer code and data that you're likely to edit is here in mod.js! Everything in mod.js will not be altered by updates, besides the addition of new things.

              Here's a breakdown of what's in it:

              • modInfo is where most of the basic configuration for the mod is. It contains:

                • name: The name of your mod. (a string)

                • id: The id for your mod, a unique string that is used to determine savefile location. Setting it is important!

                • author: The name of the author, displayed in the info tab.

                • pointsName: This changes what is displayed instead of "points" for the main currency. (It does not affect it in the code.)

                • discordName, discordLink: If you have a Discord server or other discussion place, you can add a link to it.

                  "discordName" is the text on the link, and "discordLink" is the url of an invite. If you're using a Discord invite, please make sure it's set to never expire.

                • offlineLimit: The maximum amount of offline time that the player can accumulate, in hours. Any extra time is lost. (a number)

                  This is useful because most of these mods are fast-paced enough that too much offline time ruins the balance, such as the time in between updates. That is why I suggest developers disable offline time on their own savefile.

                • initialStartPoints: A Decimal for the amount of points a new player should start with.

              • VERSION is used to describe the current version of your mod. It contains:

                • num: The mod's version number, displayed at the top right of the tree tab.
                • name: The version's name, displayed alongside the number in the info tab.
              • changelog is the HTML displayed in the changelog tab.

              • doNotCallTheseFunctionsEveryTick is very important. TMT calls every function anywhere in "layers" every tick to store the result, unless specifically told not to. Functions that have are used to do an action need to be identified. "Official" functions (those in the documentation) are all fine, but if you make any new ones, add their names to this array.

              js
              // (The ones here are examples, all official functions are already taken care of)
               var doNotCallTheseFunctionsEveryTick = ["doReset", "buy", "onPurchase", "blowUpEverything"]
              • getStartPoints(): A function to determine the amount of points the player starts with after a reset. (returns a Decimal value)

              • canGenPoints(): A function returning a boolean for if points should be generated. Use this if you want an upgrade to unlock generating points.

              • getPointGen(): A function that calculates your points per second. Anything that affects your point gain should go into the calculation here.

              • addedPlayerData(): A function that returns any non-layer-related data that you want to be added to the save data and "player" object.

              js
              function addedPlayerData() { return {
               	weather: "Yes",
               	happiness: new Decimal(72),
              diff --git a/assets/public_lit_docs_main-mod-info.md.B2Wd3G2L.lean.js b/assets/public_lit_docs_main-mod-info.md.CcRWcMdS.lean.js
              similarity index 70%
              rename from assets/public_lit_docs_main-mod-info.md.B2Wd3G2L.lean.js
              rename to assets/public_lit_docs_main-mod-info.md.CcRWcMdS.lean.js
              index 6f850a96..f1f0eccd 100644
              --- a/assets/public_lit_docs_main-mod-info.md.B2Wd3G2L.lean.js
              +++ b/assets/public_lit_docs_main-mod-info.md.CcRWcMdS.lean.js
              @@ -1 +1 @@
              -import{_ as i,c as t,o as e,ag as s}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"mod.js","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/main-mod-info.md","filePath":"public/lit/docs/main-mod-info.md"}'),a={name:"public/lit/docs/main-mod-info.md"},n=s("",10),o=[n];function l(h,p,r,d,u,c){return e(),t("div",null,o)}const y=i(a,[["render",l]]);export{m as __pageData,y as default};
              +import{_ as i,q as t,p as e,ag as s}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"mod.js","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/main-mod-info.md","filePath":"public/lit/docs/main-mod-info.md"}'),a={name:"public/lit/docs/main-mod-info.md"},n=s("",10),o=[n];function l(h,p,r,d,u,c){return e(),t("div",null,o)}const y=i(a,[["render",l]]);export{m as __pageData,y as default};
              diff --git a/assets/public_lit_docs_milestones.md.CKbDaByO.js b/assets/public_lit_docs_milestones.md.CGwN80sv.js
              similarity index 97%
              rename from assets/public_lit_docs_milestones.md.CKbDaByO.js
              rename to assets/public_lit_docs_milestones.md.CGwN80sv.js
              index 2b303e6b..c916d1f1 100644
              --- a/assets/public_lit_docs_milestones.md.CKbDaByO.js
              +++ b/assets/public_lit_docs_milestones.md.CGwN80sv.js
              @@ -1,4 +1,4 @@
              -import{_ as e,c as s,o as i,ag as t}from"./chunks/framework.VBE0TPts.js";const k=JSON.parse('{"title":"Milestones","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/milestones.md","filePath":"public/lit/docs/milestones.md"}'),a={name:"public/lit/docs/milestones.md"},n=t(`

              Milestones

              Milestones are awarded to the player when they meet a certain goal, and give some benefit. Milestones should be formatted like this:

              js
              milestones: {
              +import{_ as e,q as s,p as i,ag as t}from"./chunks/framework.DvHfxfnp.js";const k=JSON.parse('{"title":"Milestones","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/milestones.md","filePath":"public/lit/docs/milestones.md"}'),a={name:"public/lit/docs/milestones.md"},n=t(`

              Milestones

              Milestones are awarded to the player when they meet a certain goal, and give some benefit. Milestones should be formatted like this:

              js
              milestones: {
                   0: {
                       requirementDescription: "123 waffles",
                       effectDescription: "blah",
              diff --git a/assets/public_lit_docs_milestones.md.CKbDaByO.lean.js b/assets/public_lit_docs_milestones.md.CGwN80sv.lean.js
              similarity index 70%
              rename from assets/public_lit_docs_milestones.md.CKbDaByO.lean.js
              rename to assets/public_lit_docs_milestones.md.CGwN80sv.lean.js
              index e73f9547..de3bf506 100644
              --- a/assets/public_lit_docs_milestones.md.CKbDaByO.lean.js
              +++ b/assets/public_lit_docs_milestones.md.CGwN80sv.lean.js
              @@ -1 +1 @@
              -import{_ as e,c as s,o as i,ag as t}from"./chunks/framework.VBE0TPts.js";const k=JSON.parse('{"title":"Milestones","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/milestones.md","filePath":"public/lit/docs/milestones.md"}'),a={name:"public/lit/docs/milestones.md"},n=t("",7),l=[n];function o(h,p,r,d,c,g){return i(),s("div",null,l)}const m=e(a,[["render",o]]);export{k as __pageData,m as default};
              +import{_ as e,q as s,p as i,ag as t}from"./chunks/framework.DvHfxfnp.js";const k=JSON.parse('{"title":"Milestones","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/milestones.md","filePath":"public/lit/docs/milestones.md"}'),a={name:"public/lit/docs/milestones.md"},n=t("",7),l=[n];function o(h,p,r,d,c,g){return i(),s("div",null,l)}const m=e(a,[["render",o]]);export{k as __pageData,m as default};
              diff --git a/assets/public_lit_docs_subtabs-and-microtabs.md.DkrjReOt.js b/assets/public_lit_docs_subtabs-and-microtabs.md.BQEflp-r.js
              similarity index 97%
              rename from assets/public_lit_docs_subtabs-and-microtabs.md.DkrjReOt.js
              rename to assets/public_lit_docs_subtabs-and-microtabs.md.BQEflp-r.js
              index 1489f5be..e7d11194 100644
              --- a/assets/public_lit_docs_subtabs-and-microtabs.md.DkrjReOt.js
              +++ b/assets/public_lit_docs_subtabs-and-microtabs.md.BQEflp-r.js
              @@ -1,4 +1,4 @@
              -import{_ as s,c as a,o as t,ag as i}from"./chunks/framework.VBE0TPts.js";const u=JSON.parse('{"title":"Subtabs and Microtabs","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/subtabs-and-microtabs.md","filePath":"public/lit/docs/subtabs-and-microtabs.md"}'),n={name:"public/lit/docs/subtabs-and-microtabs.md"},e=i(`

              Subtabs and Microtabs

              Subtabs are separate sections of a tab that you can view by selecting one at the top of the tab. Microtabs are smaller areas that function in much the same way. You can also embed layers inside of subtabs/microtabs.

              Subtabs are defined by using the tab format like this, where each element of tabFormat is given the name of that subtab:

              js
              tabFormat: {
              +import{_ as s,q as a,p as t,ag as i}from"./chunks/framework.DvHfxfnp.js";const u=JSON.parse('{"title":"Subtabs and Microtabs","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/subtabs-and-microtabs.md","filePath":"public/lit/docs/subtabs-and-microtabs.md"}'),n={name:"public/lit/docs/subtabs-and-microtabs.md"},e=i(`

              Subtabs and Microtabs

              Subtabs are separate sections of a tab that you can view by selecting one at the top of the tab. Microtabs are smaller areas that function in much the same way. You can also embed layers inside of subtabs/microtabs.

              Subtabs are defined by using the tab format like this, where each element of tabFormat is given the name of that subtab:

              js
              tabFormat: {
                   "Main tab": {
                       content: [tab format things],
                       *subtab features*
              @@ -22,4 +22,4 @@ import{_ as s,c as a,o as t,ag as i}from"./chunks/framework.VBE0TPts.js";const u
                   otherStuff: {
                       // There could be another set of microtabs here
                   }
              -}

              Normal subtabs and microtab subtabs both use the same features:

              Features:

              • content: The tab layout code for the subtab, in the tab layout format.

              • style: optional. Applies CSS to the whole subtab when switched to, in the form of an "CSS Object", where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

              • buttonStyle: optional. A CSS object, which affects the appearance of the button for that subtab.

              • unlocked(): optional. a function to determine if the button for this subtab should be visible. By default, a subtab is always unlocked. You can't use the "this" keyword in this function.

              • shouldNotify(): optional, if true, the tab button will be highlighted to notify the player that there is something there.

              • embedLayer: SIGNIFICANT, the id of another layer. If you have this, it will override "content", "style" and "shouldNotify", instead displaying the entire layer in the subtab.

              `,9),l=[e];function h(p,o,r,k,c,d){return t(),a("div",null,l)}const E=s(n,[["render",h]]);export{u as __pageData,E as default}; +}

              Normal subtabs and microtab subtabs both use the same features:

              Features:

              • content: The tab layout code for the subtab, in the tab layout format.

              • style: optional. Applies CSS to the whole subtab when switched to, in the form of an "CSS Object", where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

              • buttonStyle: optional. A CSS object, which affects the appearance of the button for that subtab.

              • unlocked(): optional. a function to determine if the button for this subtab should be visible. By default, a subtab is always unlocked. You can't use the "this" keyword in this function.

              • shouldNotify(): optional, if true, the tab button will be highlighted to notify the player that there is something there.

              • embedLayer: SIGNIFICANT, the id of another layer. If you have this, it will override "content", "style" and "shouldNotify", instead displaying the entire layer in the subtab.

              `,9),l=[e];function h(p,o,r,k,d,b){return t(),a("div",null,l)}const E=s(n,[["render",h]]);export{u as __pageData,E as default}; diff --git a/assets/public_lit_docs_subtabs-and-microtabs.md.DkrjReOt.lean.js b/assets/public_lit_docs_subtabs-and-microtabs.md.BQEflp-r.lean.js similarity index 59% rename from assets/public_lit_docs_subtabs-and-microtabs.md.DkrjReOt.lean.js rename to assets/public_lit_docs_subtabs-and-microtabs.md.BQEflp-r.lean.js index ffa89449..68f98bca 100644 --- a/assets/public_lit_docs_subtabs-and-microtabs.md.DkrjReOt.lean.js +++ b/assets/public_lit_docs_subtabs-and-microtabs.md.BQEflp-r.lean.js @@ -1 +1 @@ -import{_ as s,c as a,o as t,ag as i}from"./chunks/framework.VBE0TPts.js";const u=JSON.parse('{"title":"Subtabs and Microtabs","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/subtabs-and-microtabs.md","filePath":"public/lit/docs/subtabs-and-microtabs.md"}'),n={name:"public/lit/docs/subtabs-and-microtabs.md"},e=i("",9),l=[e];function h(p,o,r,k,c,d){return t(),a("div",null,l)}const E=s(n,[["render",h]]);export{u as __pageData,E as default}; +import{_ as s,q as a,p as t,ag as i}from"./chunks/framework.DvHfxfnp.js";const u=JSON.parse('{"title":"Subtabs and Microtabs","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/subtabs-and-microtabs.md","filePath":"public/lit/docs/subtabs-and-microtabs.md"}'),n={name:"public/lit/docs/subtabs-and-microtabs.md"},e=i("",9),l=[e];function h(p,o,r,k,d,b){return t(),a("div",null,l)}const E=s(n,[["render",h]]);export{u as __pageData,E as default}; diff --git a/assets/public_lit_docs_trees-and-tree-customization.md.D-rEc1nB.js b/assets/public_lit_docs_trees-and-tree-customization.md.C8iASWgy.js similarity index 97% rename from assets/public_lit_docs_trees-and-tree-customization.md.D-rEc1nB.js rename to assets/public_lit_docs_trees-and-tree-customization.md.C8iASWgy.js index 97f2353e..b67e4450 100644 --- a/assets/public_lit_docs_trees-and-tree-customization.md.D-rEc1nB.js +++ b/assets/public_lit_docs_trees-and-tree-customization.md.C8iASWgy.js @@ -1,3 +1,3 @@ -import{_ as e,c as t,o as i,ag as a}from"./chunks/framework.VBE0TPts.js";const y=JSON.parse('{"title":"Trees and tree customization","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/trees-and-tree-customization.md","filePath":"public/lit/docs/trees-and-tree-customization.md"}'),s={name:"public/lit/docs/trees-and-tree-customization.md"},o=a(`

              Trees and tree customization

              If you want to have something beyond the standard tree on the left tab, you can do that in tree.js. You can change the layout of the tree, including making non-layer nodes, change it into something other than a tree, or hide the left tab altogether. This also introduces the "tree" component, which can be used in your layers as well.

              layoutInfo

              The most important part is layoutInfo, containing:

              • startTab: The id of the default tab to show on the left at the start.
              • showTree: True if the tree tab should be shown at the start of the game. (The other tab will fill the whole page)
              • treeLayout: If present, overrides the tree layout and places nodes as you describe instead (explained in the next section).

              Additionally, if you want the main layout to not be a tree, you can edit the "tree-tab" layer at the bottom of tree.js to modify it just like a normal layer's tab. You can even switch between left tabs, using showNavTab(layer) to make that layer appear on the left.

              Trees

              The tree component is defined as an array of arrays of names of layers or nodes to show in the tree. They work just like layers/ nodes in the main tree (but branches between nodes will only work on the first node if you have duplicates.)

              Here is an example tree:

              js
              [["p"],
              +import{_ as e,q as t,p as i,ag as a}from"./chunks/framework.DvHfxfnp.js";const y=JSON.parse('{"title":"Trees and tree customization","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/trees-and-tree-customization.md","filePath":"public/lit/docs/trees-and-tree-customization.md"}'),s={name:"public/lit/docs/trees-and-tree-customization.md"},o=a(`

              Trees and tree customization

              If you want to have something beyond the standard tree on the left tab, you can do that in tree.js. You can change the layout of the tree, including making non-layer nodes, change it into something other than a tree, or hide the left tab altogether. This also introduces the "tree" component, which can be used in your layers as well.

              layoutInfo

              The most important part is layoutInfo, containing:

              • startTab: The id of the default tab to show on the left at the start.
              • showTree: True if the tree tab should be shown at the start of the game. (The other tab will fill the whole page)
              • treeLayout: If present, overrides the tree layout and places nodes as you describe instead (explained in the next section).

              Additionally, if you want the main layout to not be a tree, you can edit the "tree-tab" layer at the bottom of tree.js to modify it just like a normal layer's tab. You can even switch between left tabs, using showNavTab(layer) to make that layer appear on the left.

              Trees

              The tree component is defined as an array of arrays of names of layers or nodes to show in the tree. They work just like layers/ nodes in the main tree (but branches between nodes will only work on the first node if you have duplicates.)

              Here is an example tree:

              js
              [["p"],
                ["left", "blank", "right", "blank"]
                ["a", "b", "blank", "c", "weirdButton"]]

              Nodes

              Nodes are non-layer buttons that can go in trees. They are defined similarly to layers, but with addNode instead of addLayer.

              Features:

              • color: optional, The node's color. (A string in hex format with a #)

              • symbol: optional The text on the button (The id capitalized by default)

              • canClick(): Returns true if the player can click the node. ()

              • onClick(): The function called when the node is clicked.

              • layerShown(): optional, A function returning a bool which determines if this node should be visible. It can also return "ghost", which will hide the layer, but its node will still take up space in its tree.

              • branches: optional. An array of layer/node ids. On a tree, a line will appear from this node to all of the nodes in the list. Alternatively, an entry in the array can be a 2-element array consisting of the id and a color value. The color value can either be a string with a hex color code, or a number from 1-3 (theme-affected colors).

              • nodeStyle: optional. A CSS object, where the keys are CSS attributes, which styles this node on the tree.

              • tooltip() / tooltipLocked(): optional. Functions that return text, which is the tooltip for the node when the layer is unlocked or locked, respectively. By default the tooltips behave the same as in the original Prestige Tree.

              • row: optional, the row that this node appears in (for the default tree).

              • position: optional, Determines the horizontal position of the layer in its row in a default tree. By default, it uses the id, and layers/nodes are sorted in alphabetical order.

              `,14),n=[o];function l(r,h,d,p,u,c){return i(),t("div",null,n)}const g=e(s,[["render",l]]);export{y as __pageData,g as default}; diff --git a/assets/public_lit_docs_trees-and-tree-customization.md.D-rEc1nB.lean.js b/assets/public_lit_docs_trees-and-tree-customization.md.C8iASWgy.lean.js similarity index 74% rename from assets/public_lit_docs_trees-and-tree-customization.md.D-rEc1nB.lean.js rename to assets/public_lit_docs_trees-and-tree-customization.md.C8iASWgy.lean.js index 5cf5281c..87e6ae59 100644 --- a/assets/public_lit_docs_trees-and-tree-customization.md.D-rEc1nB.lean.js +++ b/assets/public_lit_docs_trees-and-tree-customization.md.C8iASWgy.lean.js @@ -1 +1 @@ -import{_ as e,c as t,o as i,ag as a}from"./chunks/framework.VBE0TPts.js";const y=JSON.parse('{"title":"Trees and tree customization","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/trees-and-tree-customization.md","filePath":"public/lit/docs/trees-and-tree-customization.md"}'),s={name:"public/lit/docs/trees-and-tree-customization.md"},o=a("",14),n=[o];function l(r,h,d,p,u,c){return i(),t("div",null,n)}const g=e(s,[["render",l]]);export{y as __pageData,g as default}; +import{_ as e,q as t,p as i,ag as a}from"./chunks/framework.DvHfxfnp.js";const y=JSON.parse('{"title":"Trees and tree customization","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/trees-and-tree-customization.md","filePath":"public/lit/docs/trees-and-tree-customization.md"}'),s={name:"public/lit/docs/trees-and-tree-customization.md"},o=a("",14),n=[o];function l(r,h,d,p,u,c){return i(),t("div",null,n)}const g=e(s,[["render",l]]);export{y as __pageData,g as default}; diff --git a/assets/public_lit_docs_updating-tmt.md.C3AjdOjF.js b/assets/public_lit_docs_updating-tmt.md.C3AjdOjF.js new file mode 100644 index 00000000..7933b0df --- /dev/null +++ b/assets/public_lit_docs_updating-tmt.md.C3AjdOjF.js @@ -0,0 +1 @@ +import{_ as t,q as e,p as o,ag as a}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"Updating The Modding Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/updating-tmt.md","filePath":"public/lit/docs/updating-tmt.md"}'),i={name:"public/lit/docs/updating-tmt.md"},n=a('

              Updating The Modding Tree

              This tutorial assumes that you have used the Getting Started Tutorial, and are using Github Desktop and VSCode for your mod.

              Here's what you have to do when there's a TMT update:

              1. Look at the changelog. It will warn you if the update will break anything or require any changes. Decide if you want to try to update.

              2. Open Github Desktop, and at the top middle, click "fetch origin". This will make Github Desktop get information about the update.

              3. Click where it says "current branch: master" at the top middle, and at the bottom of the thing that appears, click "choose a branch to merge into master".

              4. Select upstream/master. It will likely say there are conflicts, but you have tools to resolve them. Click "Merge upstream/master into master".

              5. A conflict happens when the things you're trying to merge have both made changes in the same place. Click "open in Visual Studio Code" next to the first file.

              6. Scroll down through the file, and look for the parts highlighted in red and green. One of these is your code, and the other is some code that will be modified by the update. Do your best to try to edit things to keep the updated changes, but keep your content.

              7. Continue to do this for all remaining changes.

              8. Do any other changes required by the update, run the game, fix issues, etc.

              ',4),r=[n];function h(d,s,l,p,u,c){return o(),e("div",null,r)}const _=t(i,[["render",h]]);export{m as __pageData,_ as default}; diff --git a/assets/public_lit_docs_updating-tmt.md.C3AjdOjF.lean.js b/assets/public_lit_docs_updating-tmt.md.C3AjdOjF.lean.js new file mode 100644 index 00000000..8390619d --- /dev/null +++ b/assets/public_lit_docs_updating-tmt.md.C3AjdOjF.lean.js @@ -0,0 +1 @@ +import{_ as t,q as e,p as o,ag as a}from"./chunks/framework.DvHfxfnp.js";const m=JSON.parse('{"title":"Updating The Modding Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/updating-tmt.md","filePath":"public/lit/docs/updating-tmt.md"}'),i={name:"public/lit/docs/updating-tmt.md"},n=a("",4),r=[n];function h(d,s,l,p,u,c){return o(),e("div",null,r)}const _=t(i,[["render",h]]);export{m as __pageData,_ as default}; diff --git a/assets/public_lit_docs_updating-tmt.md.CjXsxPz8.js b/assets/public_lit_docs_updating-tmt.md.CjXsxPz8.js deleted file mode 100644 index 9ffc95f0..00000000 --- a/assets/public_lit_docs_updating-tmt.md.CjXsxPz8.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as t,c as e,o,ag as a}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"Updating The Modding Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/updating-tmt.md","filePath":"public/lit/docs/updating-tmt.md"}'),i={name:"public/lit/docs/updating-tmt.md"},n=a('

              Updating The Modding Tree

              This tutorial assumes that you have used the Getting Started Tutorial, and are using Github Desktop and VSCode for your mod.

              Here's what you have to do when there's a TMT update:

              1. Look at the changelog. It will warn you if the update will break anything or require any changes. Decide if you want to try to update.

              2. Open Github Desktop, and at the top middle, click "fetch origin". This will make Github Desktop get information about the update.

              3. Click where it says "current branch: master" at the top middle, and at the bottom of the thing that appears, click "choose a branch to merge into master".

              4. Select upstream/master. It will likely say there are conflicts, but you have tools to resolve them. Click "Merge upstream/master into master".

              5. A conflict happens when the things you're trying to merge have both made changes in the same place. Click "open in Visual Studio Code" next to the first file.

              6. Scroll down through the file, and look for the parts highlighted in red and green. One of these is your code, and the other is some code that will be modified by the update. Do your best to try to edit things to keep the updated changes, but keep your content.

              7. Continue to do this for all remaining changes.

              8. Do any other changes required by the update, run the game, fix issues, etc.

              ',4),r=[n];function h(d,s,l,p,u,c){return o(),e("div",null,r)}const _=t(i,[["render",h]]);export{m as __pageData,_ as default}; diff --git a/assets/public_lit_docs_updating-tmt.md.CjXsxPz8.lean.js b/assets/public_lit_docs_updating-tmt.md.CjXsxPz8.lean.js deleted file mode 100644 index 9f48e15f..00000000 --- a/assets/public_lit_docs_updating-tmt.md.CjXsxPz8.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as t,c as e,o,ag as a}from"./chunks/framework.VBE0TPts.js";const m=JSON.parse('{"title":"Updating The Modding Tree","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/updating-tmt.md","filePath":"public/lit/docs/updating-tmt.md"}'),i={name:"public/lit/docs/updating-tmt.md"},n=a("",4),r=[n];function h(d,s,l,p,u,c){return o(),e("div",null,r)}const _=t(i,[["render",h]]);export{m as __pageData,_ as default}; diff --git a/assets/public_lit_docs_upgrades.md.DCCBwvKJ.js b/assets/public_lit_docs_upgrades.md.D1Ns9VTR.js similarity index 98% rename from assets/public_lit_docs_upgrades.md.DCCBwvKJ.js rename to assets/public_lit_docs_upgrades.md.D1Ns9VTR.js index 6e0d80d1..346ad382 100644 --- a/assets/public_lit_docs_upgrades.md.DCCBwvKJ.js +++ b/assets/public_lit_docs_upgrades.md.D1Ns9VTR.js @@ -1,4 +1,4 @@ -import{_ as e,c as s,o as i,ag as a}from"./chunks/framework.VBE0TPts.js";const y=JSON.parse('{"title":"Upgrades","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/upgrades.md","filePath":"public/lit/docs/upgrades.md"}'),t={name:"public/lit/docs/upgrades.md"},n=a(`

              Upgrades

              Useful functions for dealing with Upgrades and implementing their effects:

              • hasUpgrade(layer, id): determine if the player has the upgrade
              • upgradeEffect(layer, id): Returns the current effects of the upgrade, if any
              • buyUpgrade(layer, id): Buys an upgrade directly (if affordable)

              Hint: Basic point gain is calculated in mod.js's "getPointGen" function.

              Upgrades are stored in the following format:

              js
              upgrades: {
              +import{_ as e,q as s,p as i,ag as a}from"./chunks/framework.DvHfxfnp.js";const y=JSON.parse('{"title":"Upgrades","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/upgrades.md","filePath":"public/lit/docs/upgrades.md"}'),t={name:"public/lit/docs/upgrades.md"},n=a(`

              Upgrades

              Useful functions for dealing with Upgrades and implementing their effects:

              • hasUpgrade(layer, id): determine if the player has the upgrade
              • upgradeEffect(layer, id): Returns the current effects of the upgrade, if any
              • buyUpgrade(layer, id): Buys an upgrade directly (if affordable)

              Hint: Basic point gain is calculated in mod.js's "getPointGen" function.

              Upgrades are stored in the following format:

              js
              upgrades: {
                   rows: # of rows,
                   cols: # of columns,
                   11: {
              diff --git a/assets/public_lit_docs_upgrades.md.DCCBwvKJ.lean.js b/assets/public_lit_docs_upgrades.md.D1Ns9VTR.lean.js
              similarity index 69%
              rename from assets/public_lit_docs_upgrades.md.DCCBwvKJ.lean.js
              rename to assets/public_lit_docs_upgrades.md.D1Ns9VTR.lean.js
              index 2c6cd591..3ac2f07d 100644
              --- a/assets/public_lit_docs_upgrades.md.DCCBwvKJ.lean.js
              +++ b/assets/public_lit_docs_upgrades.md.D1Ns9VTR.lean.js
              @@ -1 +1 @@
              -import{_ as e,c as s,o as i,ag as a}from"./chunks/framework.VBE0TPts.js";const y=JSON.parse('{"title":"Upgrades","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/upgrades.md","filePath":"public/lit/docs/upgrades.md"}'),t={name:"public/lit/docs/upgrades.md"},n=a("",13),l=[n];function r(o,p,h,u,d,c){return i(),s("div",null,l)}const k=e(t,[["render",r]]);export{y as __pageData,k as default};
              +import{_ as e,q as s,p as i,ag as a}from"./chunks/framework.DvHfxfnp.js";const y=JSON.parse('{"title":"Upgrades","description":"","frontmatter":{},"headers":[],"relativePath":"public/lit/docs/upgrades.md","filePath":"public/lit/docs/upgrades.md"}'),t={name:"public/lit/docs/upgrades.md"},n=a("",13),l=[n];function r(o,p,h,u,d,c){return i(),s("div",null,l)}const k=e(t,[["render",r]]);export{y as __pageData,k as default};
              diff --git a/assets/style.BPlHIFta.css b/assets/style.ByNYS6_U.css
              similarity index 96%
              rename from assets/style.BPlHIFta.css
              rename to assets/style.ByNYS6_U.css
              index 28923f9f..a7e51a15 100644
              --- a/assets/style.BPlHIFta.css
              +++ b/assets/style.ByNYS6_U.css
              @@ -1 +1 @@
              -:root{--vp-c-white: #ffffff;--vp-c-black: #000000;--vp-c-neutral: var(--vp-c-black);--vp-c-neutral-inverse: var(--vp-c-white)}.dark{--vp-c-neutral: var(--vp-c-white);--vp-c-neutral-inverse: var(--vp-c-black)}:root{--vp-c-gray-1: #dddde3;--vp-c-gray-2: #e4e4e9;--vp-c-gray-3: #ebebef;--vp-c-gray-soft: rgba(142, 150, 170, .14);--vp-c-indigo-1: #3451b2;--vp-c-indigo-2: #3a5ccc;--vp-c-indigo-3: #5672cd;--vp-c-indigo-soft: rgba(100, 108, 255, .14);--vp-c-purple-1: #6f42c1;--vp-c-purple-2: #7e4cc9;--vp-c-purple-3: #8e5cd9;--vp-c-purple-soft: rgba(159, 122, 234, .14);--vp-c-green-1: #18794e;--vp-c-green-2: #299764;--vp-c-green-3: #30a46c;--vp-c-green-soft: rgba(16, 185, 129, .14);--vp-c-yellow-1: #915930;--vp-c-yellow-2: #946300;--vp-c-yellow-3: #9f6a00;--vp-c-yellow-soft: rgba(234, 179, 8, .14);--vp-c-red-1: #b8272c;--vp-c-red-2: #d5393e;--vp-c-red-3: #e0575b;--vp-c-red-soft: rgba(244, 63, 94, .14);--vp-c-sponsor: #db2777}.dark{--vp-c-gray-1: #515c67;--vp-c-gray-2: #414853;--vp-c-gray-3: #32363f;--vp-c-gray-soft: rgba(101, 117, 133, .16);--vp-c-indigo-1: #a8b1ff;--vp-c-indigo-2: #5c73e7;--vp-c-indigo-3: #3e63dd;--vp-c-indigo-soft: rgba(100, 108, 255, .16);--vp-c-purple-1: #c8abfa;--vp-c-purple-2: #a879e6;--vp-c-purple-3: #8e5cd9;--vp-c-purple-soft: rgba(159, 122, 234, .16);--vp-c-green-1: #3dd68c;--vp-c-green-2: #30a46c;--vp-c-green-3: #298459;--vp-c-green-soft: rgba(16, 185, 129, .16);--vp-c-yellow-1: #f9b44e;--vp-c-yellow-2: #da8b17;--vp-c-yellow-3: #a46a0a;--vp-c-yellow-soft: rgba(234, 179, 8, .16);--vp-c-red-1: #f66f81;--vp-c-red-2: #f14158;--vp-c-red-3: #b62a3c;--vp-c-red-soft: rgba(244, 63, 94, .16)}:root{--vp-c-bg: #ffffff;--vp-c-bg-alt: #f6f6f7;--vp-c-bg-elv: #ffffff;--vp-c-bg-soft: #f6f6f7}.dark{--vp-c-bg: #1b1b1f;--vp-c-bg-alt: #161618;--vp-c-bg-elv: #202127;--vp-c-bg-soft: #202127}:root{--vp-c-border: #c2c2c4;--vp-c-divider: #e2e2e3;--vp-c-gutter: #e2e2e3}.dark{--vp-c-border: #3c3f44;--vp-c-divider: #2e2e32;--vp-c-gutter: #000000}:root{--vp-c-text-1: rgba(60, 60, 67);--vp-c-text-2: rgba(60, 60, 67, .78);--vp-c-text-3: rgba(60, 60, 67, .56)}.dark{--vp-c-text-1: rgba(255, 255, 245, .86);--vp-c-text-2: rgba(235, 235, 245, .6);--vp-c-text-3: rgba(235, 235, 245, .38)}:root{--vp-c-default-1: var(--vp-c-gray-1);--vp-c-default-2: var(--vp-c-gray-2);--vp-c-default-3: var(--vp-c-gray-3);--vp-c-default-soft: var(--vp-c-gray-soft);--vp-c-brand-1: var(--vp-c-indigo-1);--vp-c-brand-2: var(--vp-c-indigo-2);--vp-c-brand-3: var(--vp-c-indigo-3);--vp-c-brand-soft: var(--vp-c-indigo-soft);--vp-c-brand: var(--vp-c-brand-1);--vp-c-tip-1: var(--vp-c-brand-1);--vp-c-tip-2: var(--vp-c-brand-2);--vp-c-tip-3: var(--vp-c-brand-3);--vp-c-tip-soft: var(--vp-c-brand-soft);--vp-c-note-1: var(--vp-c-brand-1);--vp-c-note-2: var(--vp-c-brand-2);--vp-c-note-3: var(--vp-c-brand-3);--vp-c-note-soft: var(--vp-c-brand-soft);--vp-c-success-1: var(--vp-c-green-1);--vp-c-success-2: var(--vp-c-green-2);--vp-c-success-3: var(--vp-c-green-3);--vp-c-success-soft: var(--vp-c-green-soft);--vp-c-important-1: var(--vp-c-purple-1);--vp-c-important-2: var(--vp-c-purple-2);--vp-c-important-3: var(--vp-c-purple-3);--vp-c-important-soft: var(--vp-c-purple-soft);--vp-c-warning-1: var(--vp-c-yellow-1);--vp-c-warning-2: var(--vp-c-yellow-2);--vp-c-warning-3: var(--vp-c-yellow-3);--vp-c-warning-soft: var(--vp-c-yellow-soft);--vp-c-danger-1: var(--vp-c-red-1);--vp-c-danger-2: var(--vp-c-red-2);--vp-c-danger-3: var(--vp-c-red-3);--vp-c-danger-soft: var(--vp-c-red-soft);--vp-c-caution-1: var(--vp-c-red-1);--vp-c-caution-2: var(--vp-c-red-2);--vp-c-caution-3: var(--vp-c-red-3);--vp-c-caution-soft: var(--vp-c-red-soft)}:root{--vp-font-family-base: "Inter", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--vp-font-family-mono: ui-monospace, "Menlo", "Monaco", "Consolas", "Liberation Mono", "Courier New", monospace;font-optical-sizing:auto}:root:where(:lang(zh)){--vp-font-family-base: "Punctuation SC", "Inter", ui-sans-serif, system-ui, "PingFang SC", "Noto Sans CJK SC", "Noto Sans SC", "Heiti SC", "Microsoft YaHei", "DengXian", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"}:root{--vp-shadow-1: 0 1px 2px rgba(0, 0, 0, .04), 0 1px 2px rgba(0, 0, 0, .06);--vp-shadow-2: 0 3px 12px rgba(0, 0, 0, .07), 0 1px 4px rgba(0, 0, 0, .07);--vp-shadow-3: 0 12px 32px rgba(0, 0, 0, .1), 0 2px 6px rgba(0, 0, 0, .08);--vp-shadow-4: 0 14px 44px rgba(0, 0, 0, .12), 0 3px 9px rgba(0, 0, 0, .12);--vp-shadow-5: 0 18px 56px rgba(0, 0, 0, .16), 0 4px 12px rgba(0, 0, 0, .16)}:root{--vp-z-index-footer: 10;--vp-z-index-local-nav: 20;--vp-z-index-nav: 30;--vp-z-index-layout-top: 40;--vp-z-index-backdrop: 50;--vp-z-index-sidebar: 60}@media (min-width: 960px){:root{--vp-z-index-sidebar: 25}}:root{--vp-layout-max-width: 1440px}:root{--vp-header-anchor-symbol: "#"}:root{--vp-code-line-height: 1.7;--vp-code-font-size: .875em;--vp-code-color: var(--vp-c-brand-1);--vp-code-link-color: var(--vp-c-brand-1);--vp-code-link-hover-color: var(--vp-c-brand-2);--vp-code-bg: var(--vp-c-default-soft);--vp-code-block-color: var(--vp-c-text-2);--vp-code-block-bg: var(--vp-c-bg-alt);--vp-code-block-divider-color: var(--vp-c-gutter);--vp-code-lang-color: var(--vp-c-text-3);--vp-code-line-highlight-color: var(--vp-c-default-soft);--vp-code-line-number-color: var(--vp-c-text-3);--vp-code-line-diff-add-color: var(--vp-c-success-soft);--vp-code-line-diff-add-symbol-color: var(--vp-c-success-1);--vp-code-line-diff-remove-color: var(--vp-c-danger-soft);--vp-code-line-diff-remove-symbol-color: var(--vp-c-danger-1);--vp-code-line-warning-color: var(--vp-c-warning-soft);--vp-code-line-error-color: var(--vp-c-danger-soft);--vp-code-copy-code-border-color: var(--vp-c-divider);--vp-code-copy-code-bg: var(--vp-c-bg-soft);--vp-code-copy-code-hover-border-color: var(--vp-c-divider);--vp-code-copy-code-hover-bg: var(--vp-c-bg);--vp-code-copy-code-active-text: var(--vp-c-text-2);--vp-code-copy-copied-text-content: "Copied";--vp-code-tab-divider: var(--vp-code-block-divider-color);--vp-code-tab-text-color: var(--vp-c-text-2);--vp-code-tab-bg: var(--vp-code-block-bg);--vp-code-tab-hover-text-color: var(--vp-c-text-1);--vp-code-tab-active-text-color: var(--vp-c-text-1);--vp-code-tab-active-bar-color: var(--vp-c-brand-1)}:root{--vp-button-brand-border: transparent;--vp-button-brand-text: var(--vp-c-white);--vp-button-brand-bg: var(--vp-c-brand-3);--vp-button-brand-hover-border: transparent;--vp-button-brand-hover-text: var(--vp-c-white);--vp-button-brand-hover-bg: var(--vp-c-brand-2);--vp-button-brand-active-border: transparent;--vp-button-brand-active-text: var(--vp-c-white);--vp-button-brand-active-bg: var(--vp-c-brand-1);--vp-button-alt-border: transparent;--vp-button-alt-text: var(--vp-c-text-1);--vp-button-alt-bg: var(--vp-c-default-3);--vp-button-alt-hover-border: transparent;--vp-button-alt-hover-text: var(--vp-c-text-1);--vp-button-alt-hover-bg: var(--vp-c-default-2);--vp-button-alt-active-border: transparent;--vp-button-alt-active-text: var(--vp-c-text-1);--vp-button-alt-active-bg: var(--vp-c-default-1);--vp-button-sponsor-border: var(--vp-c-text-2);--vp-button-sponsor-text: var(--vp-c-text-2);--vp-button-sponsor-bg: transparent;--vp-button-sponsor-hover-border: var(--vp-c-sponsor);--vp-button-sponsor-hover-text: var(--vp-c-sponsor);--vp-button-sponsor-hover-bg: transparent;--vp-button-sponsor-active-border: var(--vp-c-sponsor);--vp-button-sponsor-active-text: var(--vp-c-sponsor);--vp-button-sponsor-active-bg: transparent}:root{--vp-custom-block-font-size: 14px;--vp-custom-block-code-font-size: 13px;--vp-custom-block-info-border: transparent;--vp-custom-block-info-text: var(--vp-c-text-1);--vp-custom-block-info-bg: var(--vp-c-default-soft);--vp-custom-block-info-code-bg: var(--vp-c-default-soft);--vp-custom-block-note-border: transparent;--vp-custom-block-note-text: var(--vp-c-text-1);--vp-custom-block-note-bg: var(--vp-c-default-soft);--vp-custom-block-note-code-bg: var(--vp-c-default-soft);--vp-custom-block-tip-border: transparent;--vp-custom-block-tip-text: var(--vp-c-text-1);--vp-custom-block-tip-bg: var(--vp-c-tip-soft);--vp-custom-block-tip-code-bg: var(--vp-c-tip-soft);--vp-custom-block-important-border: transparent;--vp-custom-block-important-text: var(--vp-c-text-1);--vp-custom-block-important-bg: var(--vp-c-important-soft);--vp-custom-block-important-code-bg: var(--vp-c-important-soft);--vp-custom-block-warning-border: transparent;--vp-custom-block-warning-text: var(--vp-c-text-1);--vp-custom-block-warning-bg: var(--vp-c-warning-soft);--vp-custom-block-warning-code-bg: var(--vp-c-warning-soft);--vp-custom-block-danger-border: transparent;--vp-custom-block-danger-text: var(--vp-c-text-1);--vp-custom-block-danger-bg: var(--vp-c-danger-soft);--vp-custom-block-danger-code-bg: var(--vp-c-danger-soft);--vp-custom-block-caution-border: transparent;--vp-custom-block-caution-text: var(--vp-c-text-1);--vp-custom-block-caution-bg: var(--vp-c-caution-soft);--vp-custom-block-caution-code-bg: var(--vp-c-caution-soft);--vp-custom-block-details-border: var(--vp-custom-block-info-border);--vp-custom-block-details-text: var(--vp-custom-block-info-text);--vp-custom-block-details-bg: var(--vp-custom-block-info-bg);--vp-custom-block-details-code-bg: var(--vp-custom-block-info-code-bg)}:root{--vp-input-border-color: var(--vp-c-border);--vp-input-bg-color: var(--vp-c-bg-alt);--vp-input-switch-bg-color: var(--vp-c-default-soft)}:root{--vp-nav-height: 64px;--vp-nav-bg-color: var(--vp-c-bg);--vp-nav-screen-bg-color: var(--vp-c-bg);--vp-nav-logo-height: 24px}.hide-nav{--vp-nav-height: 0px}.hide-nav .VPSidebar{--vp-nav-height: 22px}:root{--vp-local-nav-bg-color: var(--vp-c-bg)}:root{--vp-sidebar-width: 272px;--vp-sidebar-bg-color: var(--vp-c-bg-alt)}:root{--vp-backdrop-bg-color: rgba(0, 0, 0, .6)}:root{--vp-home-hero-name-color: var(--vp-c-brand-1);--vp-home-hero-name-background: transparent;--vp-home-hero-image-background-image: none;--vp-home-hero-image-filter: none}:root{--vp-badge-info-border: transparent;--vp-badge-info-text: var(--vp-c-text-2);--vp-badge-info-bg: var(--vp-c-default-soft);--vp-badge-tip-border: transparent;--vp-badge-tip-text: var(--vp-c-tip-1);--vp-badge-tip-bg: var(--vp-c-tip-soft);--vp-badge-warning-border: transparent;--vp-badge-warning-text: var(--vp-c-warning-1);--vp-badge-warning-bg: var(--vp-c-warning-soft);--vp-badge-danger-border: transparent;--vp-badge-danger-text: var(--vp-c-danger-1);--vp-badge-danger-bg: var(--vp-c-danger-soft)}:root{--vp-carbon-ads-text-color: var(--vp-c-text-1);--vp-carbon-ads-poweredby-color: var(--vp-c-text-2);--vp-carbon-ads-bg-color: var(--vp-c-bg-soft);--vp-carbon-ads-hover-text-color: var(--vp-c-brand-1);--vp-carbon-ads-hover-poweredby-color: var(--vp-c-text-1)}:root{--vp-local-search-bg: var(--vp-c-bg);--vp-local-search-result-bg: var(--vp-c-bg);--vp-local-search-result-border: var(--vp-c-divider);--vp-local-search-result-selected-bg: var(--vp-c-bg);--vp-local-search-result-selected-border: var(--vp-c-brand-1);--vp-local-search-highlight-bg: var(--vp-c-brand-1);--vp-local-search-highlight-text: var(--vp-c-neutral-inverse)}@media (prefers-reduced-motion: reduce){*,:before,:after{animation-delay:-1ms!important;animation-duration:1ms!important;animation-iteration-count:1!important;background-attachment:initial!important;scroll-behavior:auto!important;transition-duration:0s!important;transition-delay:0s!important}}*,:before,:after{box-sizing:border-box}html{line-height:1.4;font-size:16px;-webkit-text-size-adjust:100%}html.dark{color-scheme:dark}body{margin:0;width:100%;min-width:320px;min-height:100vh;line-height:24px;font-family:var(--vp-font-family-base);font-size:16px;font-weight:400;color:var(--vp-c-text-1);background-color:var(--vp-c-bg);font-synthesis:style;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}main{display:block}h1,h2,h3,h4,h5,h6{margin:0;line-height:24px;font-size:16px;font-weight:400}p{margin:0}strong,b{font-weight:600}a,area,button,[role=button],input,label,select,summary,textarea{touch-action:manipulation}a{color:inherit;text-decoration:inherit}ol,ul{list-style:none;margin:0;padding:0}blockquote{margin:0}pre,code,kbd,samp{font-family:var(--vp-font-family-mono)}img,svg,video,canvas,audio,iframe,embed,object{display:block}figure{margin:0}img,video{max-width:100%;height:auto}button,input,optgroup,select,textarea{border:0;padding:0;line-height:inherit;color:inherit}button{padding:0;font-family:inherit;background-color:transparent;background-image:none}button:enabled,[role=button]:enabled{cursor:pointer}button:focus,button:focus-visible{outline:1px dotted;outline:4px auto -webkit-focus-ring-color}button:focus:not(:focus-visible){outline:none!important}input:focus,textarea:focus,select:focus{outline:none}table{border-collapse:collapse}input{background-color:transparent}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:var(--vp-c-text-3)}input::-ms-input-placeholder,textarea::-ms-input-placeholder{color:var(--vp-c-text-3)}input::placeholder,textarea::placeholder{color:var(--vp-c-text-3)}input::-webkit-outer-spin-button,input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}input[type=number]{-moz-appearance:textfield}textarea{resize:vertical}select{-webkit-appearance:none}fieldset{margin:0;padding:0}h1,h2,h3,h4,h5,h6,li,p{overflow-wrap:break-word}vite-error-overlay{z-index:9999}mjx-container{display:inline-block;margin:auto 2px -2px}mjx-container>svg{display:inline-block;margin:auto}[class^=vpi-],[class*=" vpi-"],.vp-icon{width:1em;height:1em}[class^=vpi-].bg,[class*=" vpi-"].bg,.vp-icon.bg{background-size:100% 100%;background-color:transparent}[class^=vpi-]:not(.bg),[class*=" vpi-"]:not(.bg),.vp-icon:not(.bg){-webkit-mask:var(--icon) no-repeat;mask:var(--icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit}.vpi-align-left{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M21 6H3M15 12H3M17 18H3'/%3E%3C/svg%3E")}.vpi-arrow-right,.vpi-arrow-down,.vpi-arrow-left,.vpi-arrow-up{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M5 12h14M12 5l7 7-7 7'/%3E%3C/svg%3E")}.vpi-chevron-right,.vpi-chevron-down,.vpi-chevron-left,.vpi-chevron-up{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='m9 18 6-6-6-6'/%3E%3C/svg%3E")}.vpi-chevron-down,.vpi-arrow-down{transform:rotate(90deg)}.vpi-chevron-left,.vpi-arrow-left{transform:rotate(180deg)}.vpi-chevron-up,.vpi-arrow-up{transform:rotate(-90deg)}.vpi-square-pen{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7'/%3E%3Cpath d='M18.375 2.625a2.121 2.121 0 1 1 3 3L12 15l-4 1 1-4Z'/%3E%3C/svg%3E")}.vpi-plus{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M5 12h14M12 5v14'/%3E%3C/svg%3E")}.vpi-sun{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='4'/%3E%3Cpath d='M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41'/%3E%3C/svg%3E")}.vpi-moon{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z'/%3E%3C/svg%3E")}.vpi-more-horizontal{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='1'/%3E%3Ccircle cx='19' cy='12' r='1'/%3E%3Ccircle cx='5' cy='12' r='1'/%3E%3C/svg%3E")}.vpi-languages{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='m5 8 6 6M4 14l6-6 2-3M2 5h12M7 2h1M22 22l-5-10-5 10M14 18h6'/%3E%3C/svg%3E")}.vpi-heart{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z'/%3E%3C/svg%3E")}.vpi-search{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E")}.vpi-layout-list{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Crect width='7' height='7' x='3' y='3' rx='1'/%3E%3Crect width='7' height='7' x='3' y='14' rx='1'/%3E%3Cpath d='M14 4h7M14 9h7M14 15h7M14 20h7'/%3E%3C/svg%3E")}.vpi-delete{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M20 5H9l-7 7 7 7h11a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2ZM18 9l-6 6M12 9l6 6'/%3E%3C/svg%3E")}.vpi-corner-down-left{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='m9 10-5 5 5 5'/%3E%3Cpath d='M20 4v7a4 4 0 0 1-4 4H4'/%3E%3C/svg%3E")}:root{--vp-icon-copy: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3C/svg%3E");--vp-icon-copied: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3Cpath d='m9 14 2 2 4-4'/%3E%3C/svg%3E")}.vpi-social-discord{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418Z'/%3E%3C/svg%3E")}.vpi-social-facebook{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z'/%3E%3C/svg%3E")}.vpi-social-github{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E")}.vpi-social-instagram{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M7.03.084c-1.277.06-2.149.264-2.91.563a5.874 5.874 0 0 0-2.124 1.388 5.878 5.878 0 0 0-1.38 2.127C.321 4.926.12 5.8.064 7.076.008 8.354-.005 8.764.001 12.023c.007 3.259.021 3.667.083 4.947.061 1.277.264 2.149.563 2.911.308.789.72 1.457 1.388 2.123a5.872 5.872 0 0 0 2.129 1.38c.763.295 1.636.496 2.913.552 1.278.056 1.689.069 4.947.063 3.257-.007 3.668-.021 4.947-.082 1.28-.06 2.147-.265 2.91-.563a5.881 5.881 0 0 0 2.123-1.388 5.881 5.881 0 0 0 1.38-2.129c.295-.763.496-1.636.551-2.912.056-1.28.07-1.69.063-4.948-.006-3.258-.02-3.667-.081-4.947-.06-1.28-.264-2.148-.564-2.911a5.892 5.892 0 0 0-1.387-2.123 5.857 5.857 0 0 0-2.128-1.38C19.074.322 18.202.12 16.924.066 15.647.009 15.236-.006 11.977 0 8.718.008 8.31.021 7.03.084m.14 21.693c-1.17-.05-1.805-.245-2.228-.408a3.736 3.736 0 0 1-1.382-.895 3.695 3.695 0 0 1-.9-1.378c-.165-.423-.363-1.058-.417-2.228-.06-1.264-.072-1.644-.08-4.848-.006-3.204.006-3.583.061-4.848.05-1.169.246-1.805.408-2.228.216-.561.477-.96.895-1.382a3.705 3.705 0 0 1 1.379-.9c.423-.165 1.057-.361 2.227-.417 1.265-.06 1.644-.072 4.848-.08 3.203-.006 3.583.006 4.85.062 1.168.05 1.804.244 2.227.408.56.216.96.475 1.382.895.421.42.681.817.9 1.378.165.422.362 1.056.417 2.227.06 1.265.074 1.645.08 4.848.005 3.203-.006 3.583-.061 4.848-.051 1.17-.245 1.805-.408 2.23-.216.56-.477.96-.896 1.38a3.705 3.705 0 0 1-1.378.9c-.422.165-1.058.362-2.226.418-1.266.06-1.645.072-4.85.079-3.204.007-3.582-.006-4.848-.06m9.783-16.192a1.44 1.44 0 1 0 1.437-1.442 1.44 1.44 0 0 0-1.437 1.442M5.839 12.012a6.161 6.161 0 1 0 12.323-.024 6.162 6.162 0 0 0-12.323.024M8 12.008A4 4 0 1 1 12.008 16 4 4 0 0 1 8 12.008'/%3E%3C/svg%3E")}.vpi-social-linkedin{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.064 2.064 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z'/%3E%3C/svg%3E")}.vpi-social-mastodon{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z'/%3E%3C/svg%3E")}.vpi-social-npm{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M1.763 0C.786 0 0 .786 0 1.763v20.474C0 23.214.786 24 1.763 24h20.474c.977 0 1.763-.786 1.763-1.763V1.763C24 .786 23.214 0 22.237 0zM5.13 5.323l13.837.019-.009 13.836h-3.464l.01-10.382h-3.456L12.04 19.17H5.113z'/%3E%3C/svg%3E")}.vpi-social-slack{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zm1.271 0a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zm0 1.271a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zm10.122 2.521a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zm-1.268 0a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zm-2.523 10.122a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zm0-1.268a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z'/%3E%3C/svg%3E")}.vpi-social-twitter,.vpi-social-x{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z'/%3E%3C/svg%3E")}.vpi-social-youtube{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z'/%3E%3C/svg%3E")}.visually-hidden{position:absolute;width:1px;height:1px;white-space:nowrap;clip:rect(0 0 0 0);clip-path:inset(50%);overflow:hidden}.custom-block{border:1px solid transparent;border-radius:8px;padding:16px 16px 8px;line-height:24px;font-size:var(--vp-custom-block-font-size);color:var(--vp-c-text-2)}.custom-block.info{border-color:var(--vp-custom-block-info-border);color:var(--vp-custom-block-info-text);background-color:var(--vp-custom-block-info-bg)}.custom-block.info a,.custom-block.info code{color:var(--vp-c-brand-1)}.custom-block.info a:hover,.custom-block.info a:hover>code{color:var(--vp-c-brand-2)}.custom-block.info code{background-color:var(--vp-custom-block-info-code-bg)}.custom-block.note{border-color:var(--vp-custom-block-note-border);color:var(--vp-custom-block-note-text);background-color:var(--vp-custom-block-note-bg)}.custom-block.note a,.custom-block.note code{color:var(--vp-c-brand-1)}.custom-block.note a:hover,.custom-block.note a:hover>code{color:var(--vp-c-brand-2)}.custom-block.note code{background-color:var(--vp-custom-block-note-code-bg)}.custom-block.tip{border-color:var(--vp-custom-block-tip-border);color:var(--vp-custom-block-tip-text);background-color:var(--vp-custom-block-tip-bg)}.custom-block.tip a,.custom-block.tip code{color:var(--vp-c-tip-1)}.custom-block.tip a:hover,.custom-block.tip a:hover>code{color:var(--vp-c-tip-2)}.custom-block.tip code{background-color:var(--vp-custom-block-tip-code-bg)}.custom-block.important{border-color:var(--vp-custom-block-important-border);color:var(--vp-custom-block-important-text);background-color:var(--vp-custom-block-important-bg)}.custom-block.important a,.custom-block.important code{color:var(--vp-c-important-1)}.custom-block.important a:hover,.custom-block.important a:hover>code{color:var(--vp-c-important-2)}.custom-block.important code{background-color:var(--vp-custom-block-important-code-bg)}.custom-block.warning{border-color:var(--vp-custom-block-warning-border);color:var(--vp-custom-block-warning-text);background-color:var(--vp-custom-block-warning-bg)}.custom-block.warning a,.custom-block.warning code{color:var(--vp-c-warning-1)}.custom-block.warning a:hover,.custom-block.warning a:hover>code{color:var(--vp-c-warning-2)}.custom-block.warning code{background-color:var(--vp-custom-block-warning-code-bg)}.custom-block.danger{border-color:var(--vp-custom-block-danger-border);color:var(--vp-custom-block-danger-text);background-color:var(--vp-custom-block-danger-bg)}.custom-block.danger a,.custom-block.danger code{color:var(--vp-c-danger-1)}.custom-block.danger a:hover,.custom-block.danger a:hover>code{color:var(--vp-c-danger-2)}.custom-block.danger code{background-color:var(--vp-custom-block-danger-code-bg)}.custom-block.caution{border-color:var(--vp-custom-block-caution-border);color:var(--vp-custom-block-caution-text);background-color:var(--vp-custom-block-caution-bg)}.custom-block.caution a,.custom-block.caution code{color:var(--vp-c-caution-1)}.custom-block.caution a:hover,.custom-block.caution a:hover>code{color:var(--vp-c-caution-2)}.custom-block.caution code{background-color:var(--vp-custom-block-caution-code-bg)}.custom-block.details{border-color:var(--vp-custom-block-details-border);color:var(--vp-custom-block-details-text);background-color:var(--vp-custom-block-details-bg)}.custom-block.details a{color:var(--vp-c-brand-1)}.custom-block.details a:hover,.custom-block.details a:hover>code{color:var(--vp-c-brand-2)}.custom-block.details code{background-color:var(--vp-custom-block-details-code-bg)}.custom-block-title{font-weight:600}.custom-block p+p{margin:8px 0}.custom-block.details summary{margin:0 0 8px;font-weight:700;cursor:pointer;-webkit-user-select:none;user-select:none}.custom-block.details summary+p{margin:8px 0}.custom-block a{color:inherit;font-weight:600;text-decoration:underline;text-underline-offset:2px;transition:opacity .25s}.custom-block a:hover{opacity:.75}.custom-block code{font-size:var(--vp-custom-block-code-font-size)}.custom-block.custom-block th,.custom-block.custom-block blockquote>p{font-size:var(--vp-custom-block-font-size);color:inherit}.dark .vp-code span{color:var(--shiki-dark, inherit)}html:not(.dark) .vp-code span{color:var(--shiki-light, inherit)}.vp-code-group{margin-top:16px}.vp-code-group .tabs{position:relative;display:flex;margin-right:-24px;margin-left:-24px;padding:0 12px;background-color:var(--vp-code-tab-bg);overflow-x:auto;overflow-y:hidden;box-shadow:inset 0 -1px var(--vp-code-tab-divider)}@media (min-width: 640px){.vp-code-group .tabs{margin-right:0;margin-left:0;border-radius:8px 8px 0 0}}.vp-code-group .tabs input{position:fixed;opacity:0;pointer-events:none}.vp-code-group .tabs label{position:relative;display:inline-block;border-bottom:1px solid transparent;padding:0 12px;line-height:48px;font-size:14px;font-weight:500;color:var(--vp-code-tab-text-color);white-space:nowrap;cursor:pointer;transition:color .25s}.vp-code-group .tabs label:after{position:absolute;right:8px;bottom:-1px;left:8px;z-index:1;height:2px;border-radius:2px;content:"";background-color:transparent;transition:background-color .25s}.vp-code-group label:hover{color:var(--vp-code-tab-hover-text-color)}.vp-code-group input:checked+label{color:var(--vp-code-tab-active-text-color)}.vp-code-group input:checked+label:after{background-color:var(--vp-code-tab-active-bar-color)}.vp-code-group div[class*=language-],.vp-block{display:none;margin-top:0!important;border-top-left-radius:0!important;border-top-right-radius:0!important}.vp-code-group div[class*=language-].active,.vp-block.active{display:block}.vp-block{padding:20px 24px}.vp-doc h1,.vp-doc h2,.vp-doc h3,.vp-doc h4,.vp-doc h5,.vp-doc h6{position:relative;font-weight:600;outline:none}.vp-doc h1{letter-spacing:-.02em;line-height:40px;font-size:28px}.vp-doc h2{margin:48px 0 16px;border-top:1px solid var(--vp-c-divider);padding-top:24px;letter-spacing:-.02em;line-height:32px;font-size:24px}.vp-doc h3{margin:32px 0 0;letter-spacing:-.01em;line-height:28px;font-size:20px}.vp-doc .header-anchor{position:absolute;top:0;left:0;margin-left:-.87em;font-weight:500;-webkit-user-select:none;user-select:none;opacity:0;text-decoration:none;transition:color .25s,opacity .25s}.vp-doc .header-anchor:before{content:var(--vp-header-anchor-symbol)}.vp-doc h1:hover .header-anchor,.vp-doc h1 .header-anchor:focus,.vp-doc h2:hover .header-anchor,.vp-doc h2 .header-anchor:focus,.vp-doc h3:hover .header-anchor,.vp-doc h3 .header-anchor:focus,.vp-doc h4:hover .header-anchor,.vp-doc h4 .header-anchor:focus,.vp-doc h5:hover .header-anchor,.vp-doc h5 .header-anchor:focus,.vp-doc h6:hover .header-anchor,.vp-doc h6 .header-anchor:focus{opacity:1}@media (min-width: 768px){.vp-doc h1{letter-spacing:-.02em;line-height:40px;font-size:32px}}.vp-doc h2 .header-anchor{top:24px}.vp-doc p,.vp-doc summary{margin:16px 0}.vp-doc p{line-height:28px}.vp-doc blockquote{margin:16px 0;border-left:2px solid var(--vp-c-divider);padding-left:16px;transition:border-color .5s}.vp-doc blockquote>p{margin:0;font-size:16px;color:var(--vp-c-text-2);transition:color .5s}.vp-doc a{font-weight:500;color:var(--vp-c-brand-1);text-decoration:underline;text-underline-offset:2px;transition:color .25s,opacity .25s}.vp-doc a:hover{color:var(--vp-c-brand-2)}.vp-doc strong{font-weight:600}.vp-doc ul,.vp-doc ol{padding-left:1.25rem;margin:16px 0}.vp-doc ul{list-style:disc}.vp-doc ol{list-style:decimal}.vp-doc li+li{margin-top:8px}.vp-doc li>ol,.vp-doc li>ul{margin:8px 0 0}.vp-doc table{display:block;border-collapse:collapse;margin:20px 0;overflow-x:auto}.vp-doc tr{background-color:var(--vp-c-bg);border-top:1px solid var(--vp-c-divider);transition:background-color .5s}.vp-doc tr:nth-child(2n){background-color:var(--vp-c-bg-soft)}.vp-doc th,.vp-doc td{border:1px solid var(--vp-c-divider);padding:8px 16px}.vp-doc th{text-align:left;font-size:14px;font-weight:600;color:var(--vp-c-text-2);background-color:var(--vp-c-bg-soft)}.vp-doc td{font-size:14px}.vp-doc hr{margin:16px 0;border:none;border-top:1px solid var(--vp-c-divider)}.vp-doc .custom-block{margin:16px 0}.vp-doc .custom-block p{margin:8px 0;line-height:24px}.vp-doc .custom-block p:first-child{margin:0}.vp-doc .custom-block div[class*=language-]{margin:8px 0;border-radius:8px}.vp-doc .custom-block div[class*=language-] code{font-weight:400;background-color:transparent}.vp-doc .custom-block .vp-code-group .tabs{margin:0;border-radius:8px 8px 0 0}.vp-doc :not(pre,h1,h2,h3,h4,h5,h6)>code{font-size:var(--vp-code-font-size);color:var(--vp-code-color)}.vp-doc :not(pre)>code{border-radius:4px;padding:3px 6px;background-color:var(--vp-code-bg);transition:color .25s,background-color .5s}.vp-doc a>code{color:var(--vp-code-link-color)}.vp-doc a:hover>code{color:var(--vp-code-link-hover-color)}.vp-doc h1>code,.vp-doc h2>code,.vp-doc h3>code{font-size:.9em}.vp-doc div[class*=language-],.vp-block{position:relative;margin:16px -24px;background-color:var(--vp-code-block-bg);overflow-x:auto;transition:background-color .5s}@media (min-width: 640px){.vp-doc div[class*=language-],.vp-block{border-radius:8px;margin:16px 0}}@media (max-width: 639px){.vp-doc li div[class*=language-]{border-radius:8px 0 0 8px}}.vp-doc div[class*=language-]+div[class*=language-],.vp-doc div[class$=-api]+div[class*=language-],.vp-doc div[class*=language-]+div[class$=-api]>div[class*=language-]{margin-top:-8px}.vp-doc [class*=language-] pre,.vp-doc [class*=language-] code{direction:ltr;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}.vp-doc [class*=language-] pre{position:relative;z-index:1;margin:0;padding:20px 0;background:transparent;overflow-x:auto}.vp-doc [class*=language-] code{display:block;padding:0 24px;width:fit-content;min-width:100%;line-height:var(--vp-code-line-height);font-size:var(--vp-code-font-size);color:var(--vp-code-block-color);transition:color .5s}.vp-doc [class*=language-] code .highlighted{background-color:var(--vp-code-line-highlight-color);transition:background-color .5s;margin:0 -24px;padding:0 24px;width:calc(100% + 48px);display:inline-block}.vp-doc [class*=language-] code .highlighted.error{background-color:var(--vp-code-line-error-color)}.vp-doc [class*=language-] code .highlighted.warning{background-color:var(--vp-code-line-warning-color)}.vp-doc [class*=language-] code .diff{transition:background-color .5s;margin:0 -24px;padding:0 24px;width:calc(100% + 48px);display:inline-block}.vp-doc [class*=language-] code .diff:before{position:absolute;left:10px}.vp-doc [class*=language-] .has-focused-lines .line:not(.has-focus){filter:blur(.095rem);opacity:.4;transition:filter .35s,opacity .35s}.vp-doc [class*=language-] .has-focused-lines .line:not(.has-focus){opacity:.7;transition:filter .35s,opacity .35s}.vp-doc [class*=language-]:hover .has-focused-lines .line:not(.has-focus){filter:blur(0);opacity:1}.vp-doc [class*=language-] code .diff.remove{background-color:var(--vp-code-line-diff-remove-color);opacity:.7}.vp-doc [class*=language-] code .diff.remove:before{content:"-";color:var(--vp-code-line-diff-remove-symbol-color)}.vp-doc [class*=language-] code .diff.add{background-color:var(--vp-code-line-diff-add-color)}.vp-doc [class*=language-] code .diff.add:before{content:"+";color:var(--vp-code-line-diff-add-symbol-color)}.vp-doc div[class*=language-].line-numbers-mode{padding-left:32px}.vp-doc .line-numbers-wrapper{position:absolute;top:0;bottom:0;left:0;z-index:3;border-right:1px solid var(--vp-code-block-divider-color);padding-top:20px;width:32px;text-align:center;font-family:var(--vp-font-family-mono);line-height:var(--vp-code-line-height);font-size:var(--vp-code-font-size);color:var(--vp-code-line-number-color);transition:border-color .5s,color .5s}.vp-doc [class*=language-]>button.copy{direction:ltr;position:absolute;top:12px;right:12px;z-index:3;border:1px solid var(--vp-code-copy-code-border-color);border-radius:4px;width:40px;height:40px;background-color:var(--vp-code-copy-code-bg);opacity:0;cursor:pointer;background-image:var(--vp-icon-copy);background-position:50%;background-size:20px;background-repeat:no-repeat;transition:border-color .25s,background-color .25s,opacity .25s}.vp-doc [class*=language-]:hover>button.copy,.vp-doc [class*=language-]>button.copy:focus{opacity:1}.vp-doc [class*=language-]>button.copy:hover,.vp-doc [class*=language-]>button.copy.copied{border-color:var(--vp-code-copy-code-hover-border-color);background-color:var(--vp-code-copy-code-hover-bg)}.vp-doc [class*=language-]>button.copy.copied,.vp-doc [class*=language-]>button.copy:hover.copied{border-radius:0 4px 4px 0;background-color:var(--vp-code-copy-code-hover-bg);background-image:var(--vp-icon-copied)}.vp-doc [class*=language-]>button.copy.copied:before,.vp-doc [class*=language-]>button.copy:hover.copied:before{position:relative;top:-1px;transform:translate(calc(-100% - 1px));display:flex;justify-content:center;align-items:center;border:1px solid var(--vp-code-copy-code-hover-border-color);border-right:0;border-radius:4px 0 0 4px;padding:0 10px;width:fit-content;height:40px;text-align:center;font-size:12px;font-weight:500;color:var(--vp-code-copy-code-active-text);background-color:var(--vp-code-copy-code-hover-bg);white-space:nowrap;content:var(--vp-code-copy-copied-text-content)}.vp-doc [class*=language-]>span.lang{position:absolute;top:2px;right:8px;z-index:2;font-size:12px;font-weight:500;color:var(--vp-code-lang-color);transition:color .4s,opacity .4s}.vp-doc [class*=language-]:hover>button.copy+span.lang,.vp-doc [class*=language-]>button.copy:focus+span.lang{opacity:0}.vp-doc .VPTeamMembers{margin-top:24px}.vp-doc .VPTeamMembers.small.count-1 .container{margin:0!important;max-width:calc((100% - 24px)/2)!important}.vp-doc .VPTeamMembers.small.count-2 .container,.vp-doc .VPTeamMembers.small.count-3 .container{max-width:100%!important}.vp-doc .VPTeamMembers.medium.count-1 .container{margin:0!important;max-width:calc((100% - 24px)/2)!important}:is(.vp-external-link-icon,.vp-doc a[href*="://"],.vp-doc a[target=_blank]):not(.no-icon):after{display:inline-block;margin-top:-1px;margin-left:4px;width:11px;height:11px;background:currentColor;color:var(--vp-c-text-3);flex-shrink:0;--icon: url("data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' %3E%3Cpath d='M0 0h24v24H0V0z' fill='none' /%3E%3Cpath d='M9 5v2h6.59L4 18.59 5.41 20 17 8.41V15h2V5H9z' /%3E%3C/svg%3E");-webkit-mask-image:var(--icon);mask-image:var(--icon)}.vp-external-link-icon:after{content:""}.external-link-icon-enabled :is(.vp-doc a[href*="://"],.vp-doc a[target=_blank]):after{content:"";color:currentColor}.vp-sponsor{border-radius:16px;overflow:hidden}.vp-sponsor.aside{border-radius:12px}.vp-sponsor-section+.vp-sponsor-section{margin-top:4px}.vp-sponsor-tier{margin:0 0 4px!important;text-align:center;letter-spacing:1px!important;line-height:24px;width:100%;font-weight:600;color:var(--vp-c-text-2);background-color:var(--vp-c-bg-soft)}.vp-sponsor.normal .vp-sponsor-tier{padding:13px 0 11px;font-size:14px}.vp-sponsor.aside .vp-sponsor-tier{padding:9px 0 7px;font-size:12px}.vp-sponsor-grid+.vp-sponsor-tier{margin-top:4px}.vp-sponsor-grid{display:flex;flex-wrap:wrap;gap:4px}.vp-sponsor-grid.xmini .vp-sponsor-grid-link{height:64px}.vp-sponsor-grid.xmini .vp-sponsor-grid-image{max-width:64px;max-height:22px}.vp-sponsor-grid.mini .vp-sponsor-grid-link{height:72px}.vp-sponsor-grid.mini .vp-sponsor-grid-image{max-width:96px;max-height:24px}.vp-sponsor-grid.small .vp-sponsor-grid-link{height:96px}.vp-sponsor-grid.small .vp-sponsor-grid-image{max-width:96px;max-height:24px}.vp-sponsor-grid.medium .vp-sponsor-grid-link{height:112px}.vp-sponsor-grid.medium .vp-sponsor-grid-image{max-width:120px;max-height:36px}.vp-sponsor-grid.big .vp-sponsor-grid-link{height:184px}.vp-sponsor-grid.big .vp-sponsor-grid-image{max-width:192px;max-height:56px}.vp-sponsor-grid[data-vp-grid="2"] .vp-sponsor-grid-item{width:calc((100% - 4px)/2)}.vp-sponsor-grid[data-vp-grid="3"] .vp-sponsor-grid-item{width:calc((100% - 4px * 2) / 3)}.vp-sponsor-grid[data-vp-grid="4"] .vp-sponsor-grid-item{width:calc((100% - 12px)/4)}.vp-sponsor-grid[data-vp-grid="5"] .vp-sponsor-grid-item{width:calc((100% - 16px)/5)}.vp-sponsor-grid[data-vp-grid="6"] .vp-sponsor-grid-item{width:calc((100% - 4px * 5) / 6)}.vp-sponsor-grid-item{flex-shrink:0;width:100%;background-color:var(--vp-c-bg-soft);transition:background-color .25s}.vp-sponsor-grid-item:hover{background-color:var(--vp-c-default-soft)}.vp-sponsor-grid-item:hover .vp-sponsor-grid-image{filter:grayscale(0) invert(0)}.vp-sponsor-grid-item.empty:hover{background-color:var(--vp-c-bg-soft)}.dark .vp-sponsor-grid-item:hover{background-color:var(--vp-c-white)}.dark .vp-sponsor-grid-item.empty:hover{background-color:var(--vp-c-bg-soft)}.vp-sponsor-grid-link{display:flex}.vp-sponsor-grid-box{display:flex;justify-content:center;align-items:center;width:100%}.vp-sponsor-grid-image{max-width:100%;filter:grayscale(1);transition:filter .25s}.dark .vp-sponsor-grid-image{filter:grayscale(1) invert(1)}.VPBadge{display:inline-block;margin-left:2px;border:1px solid transparent;border-radius:12px;padding:0 10px;line-height:22px;font-size:12px;font-weight:500;transform:translateY(-2px)}.VPBadge.small{padding:0 6px;line-height:18px;font-size:10px;transform:translateY(-8px)}.VPDocFooter .VPBadge{display:none}.vp-doc h1>.VPBadge{margin-top:4px;vertical-align:top}.vp-doc h2>.VPBadge{margin-top:3px;padding:0 8px;vertical-align:top}.vp-doc h3>.VPBadge{vertical-align:middle}.vp-doc h4>.VPBadge,.vp-doc h5>.VPBadge,.vp-doc h6>.VPBadge{vertical-align:middle;line-height:18px}.VPBadge.info{border-color:var(--vp-badge-info-border);color:var(--vp-badge-info-text);background-color:var(--vp-badge-info-bg)}.VPBadge.tip{border-color:var(--vp-badge-tip-border);color:var(--vp-badge-tip-text);background-color:var(--vp-badge-tip-bg)}.VPBadge.warning{border-color:var(--vp-badge-warning-border);color:var(--vp-badge-warning-text);background-color:var(--vp-badge-warning-bg)}.VPBadge.danger{border-color:var(--vp-badge-danger-border);color:var(--vp-badge-danger-text);background-color:var(--vp-badge-danger-bg)}.VPBackdrop[data-v-c79a1216]{position:fixed;top:0;right:0;bottom:0;left:0;z-index:var(--vp-z-index-backdrop);background:var(--vp-backdrop-bg-color);transition:opacity .5s}.VPBackdrop.fade-enter-from[data-v-c79a1216],.VPBackdrop.fade-leave-to[data-v-c79a1216]{opacity:0}.VPBackdrop.fade-leave-active[data-v-c79a1216]{transition-duration:.25s}@media (min-width: 1280px){.VPBackdrop[data-v-c79a1216]{display:none}}.NotFound[data-v-d6be1790]{padding:64px 24px 96px;text-align:center}@media (min-width: 768px){.NotFound[data-v-d6be1790]{padding:96px 32px 168px}}.code[data-v-d6be1790]{line-height:64px;font-size:64px;font-weight:600}.title[data-v-d6be1790]{padding-top:12px;letter-spacing:2px;line-height:20px;font-size:20px;font-weight:700}.divider[data-v-d6be1790]{margin:24px auto 18px;width:64px;height:1px;background-color:var(--vp-c-divider)}.quote[data-v-d6be1790]{margin:0 auto;max-width:256px;font-size:14px;font-weight:500;color:var(--vp-c-text-2)}.action[data-v-d6be1790]{padding-top:20px}.link[data-v-d6be1790]{display:inline-block;border:1px solid var(--vp-c-brand-1);border-radius:16px;padding:3px 16px;font-size:14px;font-weight:500;color:var(--vp-c-brand-1);transition:border-color .25s,color .25s}.link[data-v-d6be1790]:hover{border-color:var(--vp-c-brand-2);color:var(--vp-c-brand-2)}.root[data-v-b933a997]{position:relative;z-index:1}.nested[data-v-b933a997]{padding-right:16px;padding-left:16px}.outline-link[data-v-b933a997]{display:block;line-height:32px;font-size:14px;font-weight:400;color:var(--vp-c-text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;transition:color .5s}.outline-link[data-v-b933a997]:hover,.outline-link.active[data-v-b933a997]{color:var(--vp-c-text-1);transition:color .25s}.outline-link.nested[data-v-b933a997]{padding-left:13px}.VPDocAsideOutline[data-v-a5bbad30]{display:none}.VPDocAsideOutline.has-outline[data-v-a5bbad30]{display:block}.content[data-v-a5bbad30]{position:relative;border-left:1px solid var(--vp-c-divider);padding-left:16px;font-size:13px;font-weight:500}.outline-marker[data-v-a5bbad30]{position:absolute;top:32px;left:-1px;z-index:0;opacity:0;width:2px;border-radius:2px;height:18px;background-color:var(--vp-c-brand-1);transition:top .25s cubic-bezier(0,1,.5,1),background-color .5s,opacity .25s}.outline-title[data-v-a5bbad30]{line-height:32px;font-size:14px;font-weight:600}.VPDocAside[data-v-3f215769]{display:flex;flex-direction:column;flex-grow:1}.spacer[data-v-3f215769]{flex-grow:1}.VPDocAside[data-v-3f215769] .spacer+.VPDocAsideSponsors,.VPDocAside[data-v-3f215769] .spacer+.VPDocAsideCarbonAds{margin-top:24px}.VPDocAside[data-v-3f215769] .VPDocAsideSponsors+.VPDocAsideCarbonAds{margin-top:16px}.VPLastUpdated[data-v-7e05ebdb]{line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-2)}@media (min-width: 640px){.VPLastUpdated[data-v-7e05ebdb]{line-height:32px;font-size:14px;font-weight:500}}.VPDocFooter[data-v-d4a0bba5]{margin-top:64px}.edit-info[data-v-d4a0bba5]{padding-bottom:18px}@media (min-width: 640px){.edit-info[data-v-d4a0bba5]{display:flex;justify-content:space-between;align-items:center;padding-bottom:14px}}.edit-link-button[data-v-d4a0bba5]{display:flex;align-items:center;border:0;line-height:32px;font-size:14px;font-weight:500;color:var(--vp-c-brand-1);transition:color .25s}.edit-link-button[data-v-d4a0bba5]:hover{color:var(--vp-c-brand-2)}.edit-link-icon[data-v-d4a0bba5]{margin-right:8px}.prev-next[data-v-d4a0bba5]{border-top:1px solid var(--vp-c-divider);padding-top:24px;display:grid;grid-row-gap:8px}@media (min-width: 640px){.prev-next[data-v-d4a0bba5]{grid-template-columns:repeat(2,1fr);grid-column-gap:16px}}.pager-link[data-v-d4a0bba5]{display:block;border:1px solid var(--vp-c-divider);border-radius:8px;padding:11px 16px 13px;width:100%;height:100%;transition:border-color .25s}.pager-link[data-v-d4a0bba5]:hover{border-color:var(--vp-c-brand-1)}.pager-link.next[data-v-d4a0bba5]{margin-left:auto;text-align:right}.desc[data-v-d4a0bba5]{display:block;line-height:20px;font-size:12px;font-weight:500;color:var(--vp-c-text-2)}.title[data-v-d4a0bba5]{display:block;line-height:20px;font-size:14px;font-weight:500;color:var(--vp-c-brand-1);transition:color .25s}.VPDoc[data-v-39a288b8]{padding:32px 24px 96px;width:100%}@media (min-width: 768px){.VPDoc[data-v-39a288b8]{padding:48px 32px 128px}}@media (min-width: 960px){.VPDoc[data-v-39a288b8]{padding:48px 32px 0}.VPDoc:not(.has-sidebar) .container[data-v-39a288b8]{display:flex;justify-content:center;max-width:992px}.VPDoc:not(.has-sidebar) .content[data-v-39a288b8]{max-width:752px}}@media (min-width: 1280px){.VPDoc .container[data-v-39a288b8]{display:flex;justify-content:center}.VPDoc .aside[data-v-39a288b8]{display:block}}@media (min-width: 1440px){.VPDoc:not(.has-sidebar) .content[data-v-39a288b8]{max-width:784px}.VPDoc:not(.has-sidebar) .container[data-v-39a288b8]{max-width:1104px}}.container[data-v-39a288b8]{margin:0 auto;width:100%}.aside[data-v-39a288b8]{position:relative;display:none;order:2;flex-grow:1;padding-left:32px;width:100%;max-width:256px}.left-aside[data-v-39a288b8]{order:1;padding-left:unset;padding-right:32px}.aside-container[data-v-39a288b8]{position:fixed;top:0;padding-top:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + var(--vp-doc-top-height, 0px) + 48px);width:224px;height:100vh;overflow-x:hidden;overflow-y:auto;scrollbar-width:none}.aside-container[data-v-39a288b8]::-webkit-scrollbar{display:none}.aside-curtain[data-v-39a288b8]{position:fixed;bottom:0;z-index:10;width:224px;height:32px;background:linear-gradient(transparent,var(--vp-c-bg) 70%)}.aside-content[data-v-39a288b8]{display:flex;flex-direction:column;min-height:calc(100vh - (var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 48px));padding-bottom:32px}.content[data-v-39a288b8]{position:relative;margin:0 auto;width:100%}@media (min-width: 960px){.content[data-v-39a288b8]{padding:0 32px 128px}}@media (min-width: 1280px){.content[data-v-39a288b8]{order:1;margin:0;min-width:640px}}.content-container[data-v-39a288b8]{margin:0 auto}.VPDoc.has-aside .content-container[data-v-39a288b8]{max-width:688px}.VPButton[data-v-cad61b99]{display:inline-block;border:1px solid transparent;text-align:center;font-weight:600;white-space:nowrap;transition:color .25s,border-color .25s,background-color .25s}.VPButton[data-v-cad61b99]:active{transition:color .1s,border-color .1s,background-color .1s}.VPButton.medium[data-v-cad61b99]{border-radius:20px;padding:0 20px;line-height:38px;font-size:14px}.VPButton.big[data-v-cad61b99]{border-radius:24px;padding:0 24px;line-height:46px;font-size:16px}.VPButton.brand[data-v-cad61b99]{border-color:var(--vp-button-brand-border);color:var(--vp-button-brand-text);background-color:var(--vp-button-brand-bg)}.VPButton.brand[data-v-cad61b99]:hover{border-color:var(--vp-button-brand-hover-border);color:var(--vp-button-brand-hover-text);background-color:var(--vp-button-brand-hover-bg)}.VPButton.brand[data-v-cad61b99]:active{border-color:var(--vp-button-brand-active-border);color:var(--vp-button-brand-active-text);background-color:var(--vp-button-brand-active-bg)}.VPButton.alt[data-v-cad61b99]{border-color:var(--vp-button-alt-border);color:var(--vp-button-alt-text);background-color:var(--vp-button-alt-bg)}.VPButton.alt[data-v-cad61b99]:hover{border-color:var(--vp-button-alt-hover-border);color:var(--vp-button-alt-hover-text);background-color:var(--vp-button-alt-hover-bg)}.VPButton.alt[data-v-cad61b99]:active{border-color:var(--vp-button-alt-active-border);color:var(--vp-button-alt-active-text);background-color:var(--vp-button-alt-active-bg)}.VPButton.sponsor[data-v-cad61b99]{border-color:var(--vp-button-sponsor-border);color:var(--vp-button-sponsor-text);background-color:var(--vp-button-sponsor-bg)}.VPButton.sponsor[data-v-cad61b99]:hover{border-color:var(--vp-button-sponsor-hover-border);color:var(--vp-button-sponsor-hover-text);background-color:var(--vp-button-sponsor-hover-bg)}.VPButton.sponsor[data-v-cad61b99]:active{border-color:var(--vp-button-sponsor-active-border);color:var(--vp-button-sponsor-active-text);background-color:var(--vp-button-sponsor-active-bg)}html:not(.dark) .VPImage.dark[data-v-8426fc1a]{display:none}.dark .VPImage.light[data-v-8426fc1a]{display:none}.VPHero[data-v-303bb580]{margin-top:calc((var(--vp-nav-height) + var(--vp-layout-top-height, 0px)) * -1);padding:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 48px) 24px 48px}@media (min-width: 640px){.VPHero[data-v-303bb580]{padding:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 80px) 48px 64px}}@media (min-width: 960px){.VPHero[data-v-303bb580]{padding:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 80px) 64px 64px}}.container[data-v-303bb580]{display:flex;flex-direction:column;margin:0 auto;max-width:1152px}@media (min-width: 960px){.container[data-v-303bb580]{flex-direction:row}}.main[data-v-303bb580]{position:relative;z-index:10;order:2;flex-grow:1;flex-shrink:0}.VPHero.has-image .container[data-v-303bb580]{text-align:center}@media (min-width: 960px){.VPHero.has-image .container[data-v-303bb580]{text-align:left}}@media (min-width: 960px){.main[data-v-303bb580]{order:1;width:calc((100% / 3) * 2)}.VPHero.has-image .main[data-v-303bb580]{max-width:592px}}.name[data-v-303bb580],.text[data-v-303bb580]{max-width:392px;letter-spacing:-.4px;line-height:40px;font-size:32px;font-weight:700;white-space:pre-wrap}.VPHero.has-image .name[data-v-303bb580],.VPHero.has-image .text[data-v-303bb580]{margin:0 auto}.name[data-v-303bb580]{color:var(--vp-home-hero-name-color)}.clip[data-v-303bb580]{background:var(--vp-home-hero-name-background);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:var(--vp-home-hero-name-color)}@media (min-width: 640px){.name[data-v-303bb580],.text[data-v-303bb580]{max-width:576px;line-height:56px;font-size:48px}}@media (min-width: 960px){.name[data-v-303bb580],.text[data-v-303bb580]{line-height:64px;font-size:56px}.VPHero.has-image .name[data-v-303bb580],.VPHero.has-image .text[data-v-303bb580]{margin:0}}.tagline[data-v-303bb580]{padding-top:8px;max-width:392px;line-height:28px;font-size:18px;font-weight:500;white-space:pre-wrap;color:var(--vp-c-text-2)}.VPHero.has-image .tagline[data-v-303bb580]{margin:0 auto}@media (min-width: 640px){.tagline[data-v-303bb580]{padding-top:12px;max-width:576px;line-height:32px;font-size:20px}}@media (min-width: 960px){.tagline[data-v-303bb580]{line-height:36px;font-size:24px}.VPHero.has-image .tagline[data-v-303bb580]{margin:0}}.actions[data-v-303bb580]{display:flex;flex-wrap:wrap;margin:-6px;padding-top:24px}.VPHero.has-image .actions[data-v-303bb580]{justify-content:center}@media (min-width: 640px){.actions[data-v-303bb580]{padding-top:32px}}@media (min-width: 960px){.VPHero.has-image .actions[data-v-303bb580]{justify-content:flex-start}}.action[data-v-303bb580]{flex-shrink:0;padding:6px}.image[data-v-303bb580]{order:1;margin:-76px -24px -48px}@media (min-width: 640px){.image[data-v-303bb580]{margin:-108px -24px -48px}}@media (min-width: 960px){.image[data-v-303bb580]{flex-grow:1;order:2;margin:0;min-height:100%}}.image-container[data-v-303bb580]{position:relative;margin:0 auto;width:320px;height:320px}@media (min-width: 640px){.image-container[data-v-303bb580]{width:392px;height:392px}}@media (min-width: 960px){.image-container[data-v-303bb580]{display:flex;justify-content:center;align-items:center;width:100%;height:100%;transform:translate(-32px,-32px)}}.image-bg[data-v-303bb580]{position:absolute;top:50%;left:50%;border-radius:50%;width:192px;height:192px;background-image:var(--vp-home-hero-image-background-image);filter:var(--vp-home-hero-image-filter);transform:translate(-50%,-50%)}@media (min-width: 640px){.image-bg[data-v-303bb580]{width:256px;height:256px}}@media (min-width: 960px){.image-bg[data-v-303bb580]{width:320px;height:320px}}[data-v-303bb580] .image-src{position:absolute;top:50%;left:50%;max-width:192px;max-height:192px;transform:translate(-50%,-50%)}@media (min-width: 640px){[data-v-303bb580] .image-src{max-width:256px;max-height:256px}}@media (min-width: 960px){[data-v-303bb580] .image-src{max-width:320px;max-height:320px}}.VPFeature[data-v-a3976bdc]{display:block;border:1px solid var(--vp-c-bg-soft);border-radius:12px;height:100%;background-color:var(--vp-c-bg-soft);transition:border-color .25s,background-color .25s}.VPFeature.link[data-v-a3976bdc]:hover{border-color:var(--vp-c-brand-1)}.box[data-v-a3976bdc]{display:flex;flex-direction:column;padding:24px;height:100%}.box[data-v-a3976bdc]>.VPImage{margin-bottom:20px}.icon[data-v-a3976bdc]{display:flex;justify-content:center;align-items:center;margin-bottom:20px;border-radius:6px;background-color:var(--vp-c-default-soft);width:48px;height:48px;font-size:24px;transition:background-color .25s}.title[data-v-a3976bdc]{line-height:24px;font-size:16px;font-weight:600}.details[data-v-a3976bdc]{flex-grow:1;padding-top:8px;line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-2)}.link-text[data-v-a3976bdc]{padding-top:8px}.link-text-value[data-v-a3976bdc]{display:flex;align-items:center;font-size:14px;font-weight:500;color:var(--vp-c-brand-1)}.link-text-icon[data-v-a3976bdc]{margin-left:6px}.VPFeatures[data-v-a6181336]{position:relative;padding:0 24px}@media (min-width: 640px){.VPFeatures[data-v-a6181336]{padding:0 48px}}@media (min-width: 960px){.VPFeatures[data-v-a6181336]{padding:0 64px}}.container[data-v-a6181336]{margin:0 auto;max-width:1152px}.items[data-v-a6181336]{display:flex;flex-wrap:wrap;margin:-8px}.item[data-v-a6181336]{padding:8px;width:100%}@media (min-width: 640px){.item.grid-2[data-v-a6181336],.item.grid-4[data-v-a6181336],.item.grid-6[data-v-a6181336]{width:50%}}@media (min-width: 768px){.item.grid-2[data-v-a6181336],.item.grid-4[data-v-a6181336]{width:50%}.item.grid-3[data-v-a6181336],.item.grid-6[data-v-a6181336]{width:calc(100% / 3)}}@media (min-width: 960px){.item.grid-4[data-v-a6181336]{width:25%}}.container[data-v-8e2d4988]{margin:auto;width:100%;max-width:1280px;padding:0 24px}@media (min-width: 640px){.container[data-v-8e2d4988]{padding:0 48px}}@media (min-width: 960px){.container[data-v-8e2d4988]{width:100%;padding:0 64px}}.vp-doc[data-v-8e2d4988] .VPHomeSponsors,.vp-doc[data-v-8e2d4988] .VPTeamPage{margin-left:var(--vp-offset, calc(50% - 50vw) );margin-right:var(--vp-offset, calc(50% - 50vw) )}.vp-doc[data-v-8e2d4988] .VPHomeSponsors h2{border-top:none;letter-spacing:normal}.vp-doc[data-v-8e2d4988] .VPHomeSponsors a,.vp-doc[data-v-8e2d4988] .VPTeamPage a{text-decoration:none}.VPHome[data-v-686f80a6]{margin-bottom:96px}@media (min-width: 768px){.VPHome[data-v-686f80a6]{margin-bottom:128px}}.VPContent[data-v-1428d186]{flex-grow:1;flex-shrink:0;margin:var(--vp-layout-top-height, 0px) auto 0;width:100%}.VPContent.is-home[data-v-1428d186]{width:100%;max-width:100%}.VPContent.has-sidebar[data-v-1428d186]{margin:0}@media (min-width: 960px){.VPContent[data-v-1428d186]{padding-top:var(--vp-nav-height)}.VPContent.has-sidebar[data-v-1428d186]{margin:var(--vp-layout-top-height, 0px) 0 0;padding-left:var(--vp-sidebar-width)}}@media (min-width: 1440px){.VPContent.has-sidebar[data-v-1428d186]{padding-right:calc((100vw - var(--vp-layout-max-width)) / 2);padding-left:calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width))}}.VPFooter[data-v-e315a0ad]{position:relative;z-index:var(--vp-z-index-footer);border-top:1px solid var(--vp-c-gutter);padding:32px 24px;background-color:var(--vp-c-bg)}.VPFooter.has-sidebar[data-v-e315a0ad]{display:none}.VPFooter[data-v-e315a0ad] a{text-decoration-line:underline;text-underline-offset:2px;transition:color .25s}.VPFooter[data-v-e315a0ad] a:hover{color:var(--vp-c-text-1)}@media (min-width: 768px){.VPFooter[data-v-e315a0ad]{padding:32px}}.container[data-v-e315a0ad]{margin:0 auto;max-width:var(--vp-layout-max-width);text-align:center}.message[data-v-e315a0ad],.copyright[data-v-e315a0ad]{line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-2)}.VPLocalNavOutlineDropdown[data-v-17a5e62e]{padding:12px 20px 11px}@media (min-width: 960px){.VPLocalNavOutlineDropdown[data-v-17a5e62e]{padding:12px 36px 11px}}.VPLocalNavOutlineDropdown button[data-v-17a5e62e]{display:block;font-size:12px;font-weight:500;line-height:24px;color:var(--vp-c-text-2);transition:color .5s;position:relative}.VPLocalNavOutlineDropdown button[data-v-17a5e62e]:hover{color:var(--vp-c-text-1);transition:color .25s}.VPLocalNavOutlineDropdown button.open[data-v-17a5e62e]{color:var(--vp-c-text-1)}.icon[data-v-17a5e62e]{display:inline-block;vertical-align:middle;margin-left:2px;font-size:14px;transform:rotate(0);transition:transform .25s}@media (min-width: 960px){.VPLocalNavOutlineDropdown button[data-v-17a5e62e]{font-size:14px}.icon[data-v-17a5e62e]{font-size:16px}}.open>.icon[data-v-17a5e62e]{transform:rotate(90deg)}.items[data-v-17a5e62e]{position:absolute;top:40px;right:16px;left:16px;display:grid;gap:1px;border:1px solid var(--vp-c-border);border-radius:8px;background-color:var(--vp-c-gutter);max-height:calc(var(--vp-vh, 100vh) - 86px);overflow:hidden auto;box-shadow:var(--vp-shadow-3)}@media (min-width: 960px){.items[data-v-17a5e62e]{right:auto;left:calc(var(--vp-sidebar-width) + 32px);width:320px}}.header[data-v-17a5e62e]{background-color:var(--vp-c-bg-soft)}.top-link[data-v-17a5e62e]{display:block;padding:0 16px;line-height:48px;font-size:14px;font-weight:500;color:var(--vp-c-brand-1)}.outline[data-v-17a5e62e]{padding:8px 0;background-color:var(--vp-c-bg-soft)}.flyout-enter-active[data-v-17a5e62e]{transition:all .2s ease-out}.flyout-leave-active[data-v-17a5e62e]{transition:all .15s ease-in}.flyout-enter-from[data-v-17a5e62e],.flyout-leave-to[data-v-17a5e62e]{opacity:0;transform:translateY(-16px)}.VPLocalNav[data-v-a6f0e41e]{position:sticky;top:0;left:0;z-index:var(--vp-z-index-local-nav);border-bottom:1px solid var(--vp-c-gutter);padding-top:var(--vp-layout-top-height, 0px);width:100%;background-color:var(--vp-local-nav-bg-color)}.VPLocalNav.fixed[data-v-a6f0e41e]{position:fixed}@media (min-width: 960px){.VPLocalNav[data-v-a6f0e41e]{top:var(--vp-nav-height)}.VPLocalNav.has-sidebar[data-v-a6f0e41e]{padding-left:var(--vp-sidebar-width)}.VPLocalNav.empty[data-v-a6f0e41e]{display:none}}@media (min-width: 1280px){.VPLocalNav[data-v-a6f0e41e]{display:none}}@media (min-width: 1440px){.VPLocalNav.has-sidebar[data-v-a6f0e41e]{padding-left:calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width))}}.container[data-v-a6f0e41e]{display:flex;justify-content:space-between;align-items:center}.menu[data-v-a6f0e41e]{display:flex;align-items:center;padding:12px 24px 11px;line-height:24px;font-size:12px;font-weight:500;color:var(--vp-c-text-2);transition:color .5s}.menu[data-v-a6f0e41e]:hover{color:var(--vp-c-text-1);transition:color .25s}@media (min-width: 768px){.menu[data-v-a6f0e41e]{padding:0 32px}}@media (min-width: 960px){.menu[data-v-a6f0e41e]{display:none}}.menu-icon[data-v-a6f0e41e]{margin-right:8px;font-size:14px}.VPOutlineDropdown[data-v-a6f0e41e]{padding:12px 24px 11px}@media (min-width: 768px){.VPOutlineDropdown[data-v-a6f0e41e]{padding:12px 32px 11px}}.VPSwitch[data-v-1d5665e3]{position:relative;border-radius:11px;display:block;width:40px;height:22px;flex-shrink:0;border:1px solid var(--vp-input-border-color);background-color:var(--vp-input-switch-bg-color);transition:border-color .25s!important}.VPSwitch[data-v-1d5665e3]:hover{border-color:var(--vp-c-brand-1)}.check[data-v-1d5665e3]{position:absolute;top:1px;left:1px;width:18px;height:18px;border-radius:50%;background-color:var(--vp-c-neutral-inverse);box-shadow:var(--vp-shadow-1);transition:transform .25s!important}.icon[data-v-1d5665e3]{position:relative;display:block;width:18px;height:18px;border-radius:50%;overflow:hidden}.icon[data-v-1d5665e3] [class^=vpi-]{position:absolute;top:3px;left:3px;width:12px;height:12px;color:var(--vp-c-text-2)}.dark .icon[data-v-1d5665e3] [class^=vpi-]{color:var(--vp-c-text-1);transition:opacity .25s!important}.sun[data-v-d1f28634]{opacity:1}.moon[data-v-d1f28634],.dark .sun[data-v-d1f28634]{opacity:0}.dark .moon[data-v-d1f28634]{opacity:1}.dark .VPSwitchAppearance[data-v-d1f28634] .check{transform:translate(18px)}.VPNavBarAppearance[data-v-e6aabb21]{display:none}@media (min-width: 1280px){.VPNavBarAppearance[data-v-e6aabb21]{display:flex;align-items:center}}.VPMenuGroup+.VPMenuLink[data-v-43f1e123]{margin:12px -12px 0;border-top:1px solid var(--vp-c-divider);padding:12px 12px 0}.link[data-v-43f1e123]{display:block;border-radius:6px;padding:0 12px;line-height:32px;font-size:14px;font-weight:500;color:var(--vp-c-text-1);white-space:nowrap;transition:background-color .25s,color .25s}.link[data-v-43f1e123]:hover{color:var(--vp-c-brand-1);background-color:var(--vp-c-default-soft)}.link.active[data-v-43f1e123]{color:var(--vp-c-brand-1)}.VPMenuGroup[data-v-69e747b5]{margin:12px -12px 0;border-top:1px solid var(--vp-c-divider);padding:12px 12px 0}.VPMenuGroup[data-v-69e747b5]:first-child{margin-top:0;border-top:0;padding-top:0}.VPMenuGroup+.VPMenuGroup[data-v-69e747b5]{margin-top:12px;border-top:1px solid var(--vp-c-divider)}.title[data-v-69e747b5]{padding:0 12px;line-height:32px;font-size:14px;font-weight:600;color:var(--vp-c-text-2);white-space:nowrap;transition:color .25s}.VPMenu[data-v-e7ea1737]{border-radius:12px;padding:12px;min-width:128px;border:1px solid var(--vp-c-divider);background-color:var(--vp-c-bg-elv);box-shadow:var(--vp-shadow-3);transition:background-color .5s;max-height:calc(100vh - var(--vp-nav-height));overflow-y:auto}.VPMenu[data-v-e7ea1737] .group{margin:0 -12px;padding:0 12px 12px}.VPMenu[data-v-e7ea1737] .group+.group{border-top:1px solid var(--vp-c-divider);padding:11px 12px 12px}.VPMenu[data-v-e7ea1737] .group:last-child{padding-bottom:0}.VPMenu[data-v-e7ea1737] .group+.item{border-top:1px solid var(--vp-c-divider);padding:11px 16px 0}.VPMenu[data-v-e7ea1737] .item{padding:0 16px;white-space:nowrap}.VPMenu[data-v-e7ea1737] .label{flex-grow:1;line-height:28px;font-size:12px;font-weight:500;color:var(--vp-c-text-2);transition:color .5s}.VPMenu[data-v-e7ea1737] .action{padding-left:24px}.VPFlyout[data-v-b6c34ac9]{position:relative}.VPFlyout[data-v-b6c34ac9]:hover{color:var(--vp-c-brand-1);transition:color .25s}.VPFlyout:hover .text[data-v-b6c34ac9]{color:var(--vp-c-text-2)}.VPFlyout:hover .icon[data-v-b6c34ac9]{fill:var(--vp-c-text-2)}.VPFlyout.active .text[data-v-b6c34ac9]{color:var(--vp-c-brand-1)}.VPFlyout.active:hover .text[data-v-b6c34ac9]{color:var(--vp-c-brand-2)}.VPFlyout:hover .menu[data-v-b6c34ac9],.button[aria-expanded=true]+.menu[data-v-b6c34ac9]{opacity:1;visibility:visible;transform:translateY(0)}.button[aria-expanded=false]+.menu[data-v-b6c34ac9]{opacity:0;visibility:hidden;transform:translateY(0)}.button[data-v-b6c34ac9]{display:flex;align-items:center;padding:0 12px;height:var(--vp-nav-height);color:var(--vp-c-text-1);transition:color .5s}.text[data-v-b6c34ac9]{display:flex;align-items:center;line-height:var(--vp-nav-height);font-size:14px;font-weight:500;color:var(--vp-c-text-1);transition:color .25s}.option-icon[data-v-b6c34ac9]{margin-right:0;font-size:16px}.text-icon[data-v-b6c34ac9]{margin-left:4px;font-size:14px}.icon[data-v-b6c34ac9]{font-size:20px;transition:fill .25s}.menu[data-v-b6c34ac9]{position:absolute;top:calc(var(--vp-nav-height) / 2 + 20px);right:0;opacity:0;visibility:hidden;transition:opacity .25s,visibility .25s,transform .25s}.VPSocialLink[data-v-eee4e7cb]{display:flex;justify-content:center;align-items:center;width:36px;height:36px;color:var(--vp-c-text-2);transition:color .5s}.VPSocialLink[data-v-eee4e7cb]:hover{color:var(--vp-c-text-1);transition:color .25s}.VPSocialLink[data-v-eee4e7cb]>svg,.VPSocialLink[data-v-eee4e7cb]>[class^=vpi-social-]{width:20px;height:20px;fill:currentColor}.VPSocialLinks[data-v-7bc22406]{display:flex;justify-content:center}.VPNavBarExtra[data-v-d0bd9dde]{display:none;margin-right:-12px}@media (min-width: 768px){.VPNavBarExtra[data-v-d0bd9dde]{display:block}}@media (min-width: 1280px){.VPNavBarExtra[data-v-d0bd9dde]{display:none}}.trans-title[data-v-d0bd9dde]{padding:0 24px 0 12px;line-height:32px;font-size:14px;font-weight:700;color:var(--vp-c-text-1)}.item.appearance[data-v-d0bd9dde],.item.social-links[data-v-d0bd9dde]{display:flex;align-items:center;padding:0 12px}.item.appearance[data-v-d0bd9dde]{min-width:176px}.appearance-action[data-v-d0bd9dde]{margin-right:-2px}.social-links-list[data-v-d0bd9dde]{margin:-4px -8px}.VPNavBarHamburger[data-v-e5dd9c1c]{display:flex;justify-content:center;align-items:center;width:48px;height:var(--vp-nav-height)}@media (min-width: 768px){.VPNavBarHamburger[data-v-e5dd9c1c]{display:none}}.container[data-v-e5dd9c1c]{position:relative;width:16px;height:14px;overflow:hidden}.VPNavBarHamburger:hover .top[data-v-e5dd9c1c]{top:0;left:0;transform:translate(4px)}.VPNavBarHamburger:hover .middle[data-v-e5dd9c1c]{top:6px;left:0;transform:translate(0)}.VPNavBarHamburger:hover .bottom[data-v-e5dd9c1c]{top:12px;left:0;transform:translate(8px)}.VPNavBarHamburger.active .top[data-v-e5dd9c1c]{top:6px;transform:translate(0) rotate(225deg)}.VPNavBarHamburger.active .middle[data-v-e5dd9c1c]{top:6px;transform:translate(16px)}.VPNavBarHamburger.active .bottom[data-v-e5dd9c1c]{top:6px;transform:translate(0) rotate(135deg)}.VPNavBarHamburger.active:hover .top[data-v-e5dd9c1c],.VPNavBarHamburger.active:hover .middle[data-v-e5dd9c1c],.VPNavBarHamburger.active:hover .bottom[data-v-e5dd9c1c]{background-color:var(--vp-c-text-2);transition:top .25s,background-color .25s,transform .25s}.top[data-v-e5dd9c1c],.middle[data-v-e5dd9c1c],.bottom[data-v-e5dd9c1c]{position:absolute;width:16px;height:2px;background-color:var(--vp-c-text-1);transition:top .25s,background-color .5s,transform .25s}.top[data-v-e5dd9c1c]{top:0;left:0;transform:translate(0)}.middle[data-v-e5dd9c1c]{top:6px;left:0;transform:translate(8px)}.bottom[data-v-e5dd9c1c]{top:12px;left:0;transform:translate(4px)}.VPNavBarMenuLink[data-v-9c663999]{display:flex;align-items:center;padding:0 12px;line-height:var(--vp-nav-height);font-size:14px;font-weight:500;color:var(--vp-c-text-1);transition:color .25s}.VPNavBarMenuLink.active[data-v-9c663999],.VPNavBarMenuLink[data-v-9c663999]:hover{color:var(--vp-c-brand-1)}.VPNavBarMenu[data-v-7f418b0f]{display:none}@media (min-width: 768px){.VPNavBarMenu[data-v-7f418b0f]{display:flex}}/*! @docsearch/css 3.6.0 | MIT License | © Algolia, Inc. and contributors | https://docsearch.algolia.com */:root{--docsearch-primary-color:#5468ff;--docsearch-text-color:#1c1e21;--docsearch-spacing:12px;--docsearch-icon-stroke-width:1.4;--docsearch-highlight-color:var(--docsearch-primary-color);--docsearch-muted-color:#969faf;--docsearch-container-background:rgba(101,108,133,.8);--docsearch-logo-color:#5468ff;--docsearch-modal-width:560px;--docsearch-modal-height:600px;--docsearch-modal-background:#f5f6f7;--docsearch-modal-shadow:inset 1px 1px 0 0 hsla(0,0%,100%,.5),0 3px 8px 0 #555a64;--docsearch-searchbox-height:56px;--docsearch-searchbox-background:#ebedf0;--docsearch-searchbox-focus-background:#fff;--docsearch-searchbox-shadow:inset 0 0 0 2px var(--docsearch-primary-color);--docsearch-hit-height:56px;--docsearch-hit-color:#444950;--docsearch-hit-active-color:#fff;--docsearch-hit-background:#fff;--docsearch-hit-shadow:0 1px 3px 0 #d4d9e1;--docsearch-key-gradient:linear-gradient(-225deg,#d5dbe4,#f8f8f8);--docsearch-key-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 2px 1px rgba(30,35,90,.4);--docsearch-key-pressed-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 1px 0 rgba(30,35,90,.4);--docsearch-footer-height:44px;--docsearch-footer-background:#fff;--docsearch-footer-shadow:0 -1px 0 0 #e0e3e8,0 -3px 6px 0 rgba(69,98,155,.12)}html[data-theme=dark]{--docsearch-text-color:#f5f6f7;--docsearch-container-background:rgba(9,10,17,.8);--docsearch-modal-background:#15172a;--docsearch-modal-shadow:inset 1px 1px 0 0 #2c2e40,0 3px 8px 0 #000309;--docsearch-searchbox-background:#090a11;--docsearch-searchbox-focus-background:#000;--docsearch-hit-color:#bec3c9;--docsearch-hit-shadow:none;--docsearch-hit-background:#090a11;--docsearch-key-gradient:linear-gradient(-26.5deg,#565872,#31355b);--docsearch-key-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 2px 2px 0 rgba(3,4,9,.3);--docsearch-key-pressed-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 1px 1px 0 rgba(3,4,9,.30196078431372547);--docsearch-footer-background:#1e2136;--docsearch-footer-shadow:inset 0 1px 0 0 rgba(73,76,106,.5),0 -4px 8px 0 rgba(0,0,0,.2);--docsearch-logo-color:#fff;--docsearch-muted-color:#7f8497}.DocSearch-Button{align-items:center;background:var(--docsearch-searchbox-background);border:0;border-radius:40px;color:var(--docsearch-muted-color);cursor:pointer;display:flex;font-weight:500;height:36px;justify-content:space-between;margin:0 0 0 16px;padding:0 8px;-webkit-user-select:none;user-select:none}.DocSearch-Button:active,.DocSearch-Button:focus,.DocSearch-Button:hover{background:var(--docsearch-searchbox-focus-background);box-shadow:var(--docsearch-searchbox-shadow);color:var(--docsearch-text-color);outline:none}.DocSearch-Button-Container{align-items:center;display:flex}.DocSearch-Search-Icon{stroke-width:1.6}.DocSearch-Button .DocSearch-Search-Icon{color:var(--docsearch-text-color)}.DocSearch-Button-Placeholder{font-size:1rem;padding:0 12px 0 6px}.DocSearch-Button-Keys{display:flex;min-width:calc(40px + .8em)}.DocSearch-Button-Key{align-items:center;background:var(--docsearch-key-gradient);border-radius:3px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);display:flex;height:18px;justify-content:center;margin-right:.4em;position:relative;padding:0 0 2px;border:0;top:-1px;width:20px}.DocSearch-Button-Key--pressed{transform:translate3d(0,1px,0);box-shadow:var(--docsearch-key-pressed-shadow)}@media (max-width:768px){.DocSearch-Button-Keys,.DocSearch-Button-Placeholder{display:none}}.DocSearch--active{overflow:hidden!important}.DocSearch-Container,.DocSearch-Container *{box-sizing:border-box}.DocSearch-Container{background-color:var(--docsearch-container-background);height:100vh;left:0;position:fixed;top:0;width:100vw;z-index:200}.DocSearch-Container a{text-decoration:none}.DocSearch-Link{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;font:inherit;margin:0;padding:0}.DocSearch-Modal{background:var(--docsearch-modal-background);border-radius:6px;box-shadow:var(--docsearch-modal-shadow);flex-direction:column;margin:60px auto auto;max-width:var(--docsearch-modal-width);position:relative}.DocSearch-SearchBar{display:flex;padding:var(--docsearch-spacing) var(--docsearch-spacing) 0}.DocSearch-Form{align-items:center;background:var(--docsearch-searchbox-focus-background);border-radius:4px;box-shadow:var(--docsearch-searchbox-shadow);display:flex;height:var(--docsearch-searchbox-height);margin:0;padding:0 var(--docsearch-spacing);position:relative;width:100%}.DocSearch-Input{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:0;color:var(--docsearch-text-color);flex:1;font:inherit;font-size:1.2em;height:100%;outline:none;padding:0 0 0 8px;width:80%}.DocSearch-Input::placeholder{color:var(--docsearch-muted-color);opacity:1}.DocSearch-Input::-webkit-search-cancel-button,.DocSearch-Input::-webkit-search-decoration,.DocSearch-Input::-webkit-search-results-button,.DocSearch-Input::-webkit-search-results-decoration{display:none}.DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset{margin:0;padding:0}.DocSearch-MagnifierLabel,.DocSearch-Reset{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}.DocSearch-Container--Stalled .DocSearch-MagnifierLabel,.DocSearch-LoadingIndicator{display:none}.DocSearch-Container--Stalled .DocSearch-LoadingIndicator{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Reset{animation:none;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;right:0;stroke-width:var(--docsearch-icon-stroke-width)}}.DocSearch-Reset{animation:fade-in .1s ease-in forwards;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;padding:2px;right:0;stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Reset[hidden]{display:none}.DocSearch-Reset:hover{color:var(--docsearch-highlight-color)}.DocSearch-LoadingIndicator svg,.DocSearch-MagnifierLabel svg{height:24px;width:24px}.DocSearch-Cancel{display:none}.DocSearch-Dropdown{max-height:calc(var(--docsearch-modal-height) - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height));min-height:var(--docsearch-spacing);overflow-y:auto;overflow-y:overlay;padding:0 var(--docsearch-spacing);scrollbar-color:var(--docsearch-muted-color) var(--docsearch-modal-background);scrollbar-width:thin}.DocSearch-Dropdown::-webkit-scrollbar{width:12px}.DocSearch-Dropdown::-webkit-scrollbar-track{background:transparent}.DocSearch-Dropdown::-webkit-scrollbar-thumb{background-color:var(--docsearch-muted-color);border:3px solid var(--docsearch-modal-background);border-radius:20px}.DocSearch-Dropdown ul{list-style:none;margin:0;padding:0}.DocSearch-Label{font-size:.75em;line-height:1.6em}.DocSearch-Help,.DocSearch-Label{color:var(--docsearch-muted-color)}.DocSearch-Help{font-size:.9em;margin:0;-webkit-user-select:none;user-select:none}.DocSearch-Title{font-size:1.2em}.DocSearch-Logo a{display:flex}.DocSearch-Logo svg{color:var(--docsearch-logo-color);margin-left:8px}.DocSearch-Hits:last-of-type{margin-bottom:24px}.DocSearch-Hits mark{background:none;color:var(--docsearch-highlight-color)}.DocSearch-HitsFooter{color:var(--docsearch-muted-color);display:flex;font-size:.85em;justify-content:center;margin-bottom:var(--docsearch-spacing);padding:var(--docsearch-spacing)}.DocSearch-HitsFooter a{border-bottom:1px solid;color:inherit}.DocSearch-Hit{border-radius:4px;display:flex;padding-bottom:4px;position:relative}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit--deleting{transition:none}}.DocSearch-Hit--deleting{opacity:0;transition:all .25s linear}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit--favoriting{transition:none}}.DocSearch-Hit--favoriting{transform:scale(0);transform-origin:top center;transition:all .25s linear;transition-delay:.25s}.DocSearch-Hit a{background:var(--docsearch-hit-background);border-radius:4px;box-shadow:var(--docsearch-hit-shadow);display:block;padding-left:var(--docsearch-spacing);width:100%}.DocSearch-Hit-source{background:var(--docsearch-modal-background);color:var(--docsearch-highlight-color);font-size:.85em;font-weight:600;line-height:32px;margin:0 -4px;padding:8px 4px 0;position:sticky;top:0;z-index:10}.DocSearch-Hit-Tree{color:var(--docsearch-muted-color);height:var(--docsearch-hit-height);opacity:.5;stroke-width:var(--docsearch-icon-stroke-width);width:24px}.DocSearch-Hit[aria-selected=true] a{background-color:var(--docsearch-highlight-color)}.DocSearch-Hit[aria-selected=true] mark{text-decoration:underline}.DocSearch-Hit-Container{align-items:center;color:var(--docsearch-hit-color);display:flex;flex-direction:row;height:var(--docsearch-hit-height);padding:0 var(--docsearch-spacing) 0 0}.DocSearch-Hit-icon{height:20px;width:20px}.DocSearch-Hit-action,.DocSearch-Hit-icon{color:var(--docsearch-muted-color);stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Hit-action{align-items:center;display:flex;height:22px;width:22px}.DocSearch-Hit-action svg{display:block;height:18px;width:18px}.DocSearch-Hit-action+.DocSearch-Hit-action{margin-left:6px}.DocSearch-Hit-action-button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:inherit;cursor:pointer;padding:2px}svg.DocSearch-Hit-Select-Icon{display:none}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Select-Icon{display:block}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:background-color .1s ease-in}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{transition:none}}.DocSearch-Hit-action-button:focus path,.DocSearch-Hit-action-button:hover path{fill:#fff}.DocSearch-Hit-content-wrapper{display:flex;flex:1 1 auto;flex-direction:column;font-weight:500;justify-content:center;line-height:1.2em;margin:0 8px;overflow-x:hidden;position:relative;text-overflow:ellipsis;white-space:nowrap;width:80%}.DocSearch-Hit-title{font-size:.9em}.DocSearch-Hit-path{color:var(--docsearch-muted-color);font-size:.75em}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-action,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-icon,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-path,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-text,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-title,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Tree,.DocSearch-Hit[aria-selected=true] mark{color:var(--docsearch-hit-active-color)!important}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:none}}.DocSearch-ErrorScreen,.DocSearch-NoResults,.DocSearch-StartScreen{font-size:.9em;margin:0 auto;padding:36px 0;text-align:center;width:80%}.DocSearch-Screen-Icon{color:var(--docsearch-muted-color);padding-bottom:12px}.DocSearch-NoResults-Prefill-List{display:inline-block;padding-bottom:24px;text-align:left}.DocSearch-NoResults-Prefill-List ul{display:inline-block;padding:8px 0 0}.DocSearch-NoResults-Prefill-List li{list-style-position:inside;list-style-type:"» "}.DocSearch-Prefill{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:1em;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;font-size:1em;font-weight:700;padding:0}.DocSearch-Prefill:focus,.DocSearch-Prefill:hover{outline:none;text-decoration:underline}.DocSearch-Footer{align-items:center;background:var(--docsearch-footer-background);border-radius:0 0 8px 8px;box-shadow:var(--docsearch-footer-shadow);display:flex;flex-direction:row-reverse;flex-shrink:0;height:var(--docsearch-footer-height);justify-content:space-between;padding:0 var(--docsearch-spacing);position:relative;-webkit-user-select:none;user-select:none;width:100%;z-index:300}.DocSearch-Commands{color:var(--docsearch-muted-color);display:flex;list-style:none;margin:0;padding:0}.DocSearch-Commands li{align-items:center;display:flex}.DocSearch-Commands li:not(:last-of-type){margin-right:.8em}.DocSearch-Commands-Key{align-items:center;background:var(--docsearch-key-gradient);border-radius:2px;box-shadow:var(--docsearch-key-shadow);display:flex;height:18px;justify-content:center;margin-right:.4em;padding:0 0 1px;color:var(--docsearch-muted-color);border:0;width:20px}.DocSearch-VisuallyHiddenForAccessibility{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}@media (max-width:768px){:root{--docsearch-spacing:10px;--docsearch-footer-height:40px}.DocSearch-Dropdown{height:100%}.DocSearch-Container{height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh, 1vh)*100);position:absolute}.DocSearch-Footer{border-radius:0;bottom:0;position:absolute}.DocSearch-Hit-content-wrapper{display:flex;position:relative;width:80%}.DocSearch-Modal{border-radius:0;box-shadow:none;height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh, 1vh)*100);margin:0;max-width:100%;width:100%}.DocSearch-Dropdown{max-height:calc(var(--docsearch-vh, 1vh)*100 - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height))}.DocSearch-Cancel{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;flex:none;font:inherit;font-size:1em;font-weight:500;margin-left:var(--docsearch-spacing);outline:none;overflow:hidden;padding:0;-webkit-user-select:none;user-select:none;white-space:nowrap}.DocSearch-Commands,.DocSearch-Hit-Tree{display:none}}@keyframes fade-in{0%{opacity:0}to{opacity:1}}[class*=DocSearch]{--docsearch-primary-color: var(--vp-c-brand-1);--docsearch-highlight-color: var(--docsearch-primary-color);--docsearch-text-color: var(--vp-c-text-1);--docsearch-muted-color: var(--vp-c-text-2);--docsearch-searchbox-shadow: none;--docsearch-searchbox-background: transparent;--docsearch-searchbox-focus-background: transparent;--docsearch-key-gradient: transparent;--docsearch-key-shadow: none;--docsearch-modal-background: var(--vp-c-bg-soft);--docsearch-footer-background: var(--vp-c-bg)}.dark [class*=DocSearch]{--docsearch-modal-shadow: none;--docsearch-footer-shadow: none;--docsearch-logo-color: var(--vp-c-text-2);--docsearch-hit-background: var(--vp-c-default-soft);--docsearch-hit-color: var(--vp-c-text-2);--docsearch-hit-shadow: none}.DocSearch-Button{display:flex;justify-content:center;align-items:center;margin:0;padding:0;width:48px;height:55px;background:transparent;transition:border-color .25s}.DocSearch-Button:hover{background:transparent}.DocSearch-Button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}.DocSearch-Button-Key--pressed{transform:none;box-shadow:none}.DocSearch-Button:focus:not(:focus-visible){outline:none!important}@media (min-width: 768px){.DocSearch-Button{justify-content:flex-start;border:1px solid transparent;border-radius:8px;padding:0 10px 0 12px;width:100%;height:40px;background-color:var(--vp-c-bg-alt)}.DocSearch-Button:hover{border-color:var(--vp-c-brand-1);background:var(--vp-c-bg-alt)}}.DocSearch-Button .DocSearch-Button-Container{display:flex;align-items:center}.DocSearch-Button .DocSearch-Search-Icon{position:relative;width:16px;height:16px;color:var(--vp-c-text-1);fill:currentColor;transition:color .5s}.DocSearch-Button:hover .DocSearch-Search-Icon{color:var(--vp-c-text-1)}@media (min-width: 768px){.DocSearch-Button .DocSearch-Search-Icon{top:1px;margin-right:8px;width:14px;height:14px;color:var(--vp-c-text-2)}}.DocSearch-Button .DocSearch-Button-Placeholder{display:none;margin-top:2px;padding:0 16px 0 0;font-size:13px;font-weight:500;color:var(--vp-c-text-2);transition:color .5s}.DocSearch-Button:hover .DocSearch-Button-Placeholder{color:var(--vp-c-text-1)}@media (min-width: 768px){.DocSearch-Button .DocSearch-Button-Placeholder{display:inline-block}}.DocSearch-Button .DocSearch-Button-Keys{direction:ltr;display:none;min-width:auto}@media (min-width: 768px){.DocSearch-Button .DocSearch-Button-Keys{display:flex;align-items:center}}.DocSearch-Button .DocSearch-Button-Key{display:block;margin:2px 0 0;border:1px solid var(--vp-c-divider);border-right:none;border-radius:4px 0 0 4px;padding-left:6px;min-width:0;width:auto;height:22px;line-height:22px;font-family:var(--vp-font-family-base);font-size:12px;font-weight:500;transition:color .5s,border-color .5s}.DocSearch-Button .DocSearch-Button-Key+.DocSearch-Button-Key{border-right:1px solid var(--vp-c-divider);border-left:none;border-radius:0 4px 4px 0;padding-left:2px;padding-right:6px}.DocSearch-Button .DocSearch-Button-Key:first-child{font-size:0!important}.DocSearch-Button .DocSearch-Button-Key:first-child:after{content:"Ctrl";font-size:12px;letter-spacing:normal;color:var(--docsearch-muted-color)}.mac .DocSearch-Button .DocSearch-Button-Key:first-child:after{content:"⌘"}.DocSearch-Button .DocSearch-Button-Key:first-child>*{display:none}.DocSearch-Search-Icon{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' stroke-width='1.6' viewBox='0 0 20 20'%3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' d='m14.386 14.386 4.088 4.088-4.088-4.088A7.533 7.533 0 1 1 3.733 3.733a7.533 7.533 0 0 1 10.653 10.653z'/%3E%3C/svg%3E")}.VPNavBarSearch{display:flex;align-items:center}@media (min-width: 768px){.VPNavBarSearch{flex-grow:1;padding-left:24px}}@media (min-width: 960px){.VPNavBarSearch{padding-left:32px}}.dark .DocSearch-Footer{border-top:1px solid var(--vp-c-divider)}.DocSearch-Form{border:1px solid var(--vp-c-brand-1);background-color:var(--vp-c-white)}.dark .DocSearch-Form{background-color:var(--vp-c-default-soft)}.DocSearch-Screen-Icon>svg{margin:auto}.VPNavBarSocialLinks[data-v-0394ad82]{display:none}@media (min-width: 1280px){.VPNavBarSocialLinks[data-v-0394ad82]{display:flex;align-items:center}}.title[data-v-ab179fa1]{display:flex;align-items:center;border-bottom:1px solid transparent;width:100%;height:var(--vp-nav-height);font-size:16px;font-weight:600;color:var(--vp-c-text-1);transition:opacity .25s}@media (min-width: 960px){.title[data-v-ab179fa1]{flex-shrink:0}.VPNavBarTitle.has-sidebar .title[data-v-ab179fa1]{border-bottom-color:var(--vp-c-divider)}}[data-v-ab179fa1] .logo{margin-right:8px;height:var(--vp-nav-logo-height)}.VPNavBarTranslations[data-v-88af2de4]{display:none}@media (min-width: 1280px){.VPNavBarTranslations[data-v-88af2de4]{display:flex;align-items:center}}.title[data-v-88af2de4]{padding:0 24px 0 12px;line-height:32px;font-size:14px;font-weight:700;color:var(--vp-c-text-1)}.VPNavBar[data-v-ccf7ddec]{position:relative;height:var(--vp-nav-height);pointer-events:none;white-space:nowrap;transition:background-color .5s}.VPNavBar[data-v-ccf7ddec]:not(.home){background-color:var(--vp-nav-bg-color)}@media (min-width: 960px){.VPNavBar[data-v-ccf7ddec]:not(.home){background-color:transparent}.VPNavBar[data-v-ccf7ddec]:not(.has-sidebar):not(.home.top){background-color:var(--vp-nav-bg-color)}}.wrapper[data-v-ccf7ddec]{padding:0 8px 0 24px}@media (min-width: 768px){.wrapper[data-v-ccf7ddec]{padding:0 32px}}@media (min-width: 960px){.VPNavBar.has-sidebar .wrapper[data-v-ccf7ddec]{padding:0}}.container[data-v-ccf7ddec]{display:flex;justify-content:space-between;margin:0 auto;max-width:calc(var(--vp-layout-max-width) - 64px);height:var(--vp-nav-height);pointer-events:none}.container>.title[data-v-ccf7ddec],.container>.content[data-v-ccf7ddec]{pointer-events:none}.container[data-v-ccf7ddec] *{pointer-events:auto}@media (min-width: 960px){.VPNavBar.has-sidebar .container[data-v-ccf7ddec]{max-width:100%}}.title[data-v-ccf7ddec]{flex-shrink:0;height:calc(var(--vp-nav-height) - 1px);transition:background-color .5s}@media (min-width: 960px){.VPNavBar.has-sidebar .title[data-v-ccf7ddec]{position:absolute;top:0;left:0;z-index:2;padding:0 32px;width:var(--vp-sidebar-width);height:var(--vp-nav-height);background-color:transparent}}@media (min-width: 1440px){.VPNavBar.has-sidebar .title[data-v-ccf7ddec]{padding-left:max(32px,calc((100% - (var(--vp-layout-max-width) - 64px)) / 2));width:calc((100% - (var(--vp-layout-max-width) - 64px)) / 2 + var(--vp-sidebar-width) - 32px)}}.content[data-v-ccf7ddec]{flex-grow:1}@media (min-width: 960px){.VPNavBar.has-sidebar .content[data-v-ccf7ddec]{position:relative;z-index:1;padding-right:32px;padding-left:var(--vp-sidebar-width)}}@media (min-width: 1440px){.VPNavBar.has-sidebar .content[data-v-ccf7ddec]{padding-right:calc((100vw - var(--vp-layout-max-width)) / 2 + 32px);padding-left:calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width))}}.content-body[data-v-ccf7ddec]{display:flex;justify-content:flex-end;align-items:center;height:var(--vp-nav-height);transition:background-color .5s}@media (min-width: 960px){.VPNavBar:not(.home.top) .content-body[data-v-ccf7ddec]{position:relative;background-color:var(--vp-nav-bg-color)}.VPNavBar:not(.has-sidebar):not(.home.top) .content-body[data-v-ccf7ddec]{background-color:transparent}}@media (max-width: 767px){.content-body[data-v-ccf7ddec]{column-gap:.5rem}}.menu+.translations[data-v-ccf7ddec]:before,.menu+.appearance[data-v-ccf7ddec]:before,.menu+.social-links[data-v-ccf7ddec]:before,.translations+.appearance[data-v-ccf7ddec]:before,.appearance+.social-links[data-v-ccf7ddec]:before{margin-right:8px;margin-left:8px;width:1px;height:24px;background-color:var(--vp-c-divider);content:""}.menu+.appearance[data-v-ccf7ddec]:before,.translations+.appearance[data-v-ccf7ddec]:before{margin-right:16px}.appearance+.social-links[data-v-ccf7ddec]:before{margin-left:16px}.social-links[data-v-ccf7ddec]{margin-right:-8px}.divider[data-v-ccf7ddec]{width:100%;height:1px}@media (min-width: 960px){.VPNavBar.has-sidebar .divider[data-v-ccf7ddec]{padding-left:var(--vp-sidebar-width)}}@media (min-width: 1440px){.VPNavBar.has-sidebar .divider[data-v-ccf7ddec]{padding-left:calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width))}}.divider-line[data-v-ccf7ddec]{width:100%;height:1px;transition:background-color .5s}.VPNavBar:not(.home) .divider-line[data-v-ccf7ddec]{background-color:var(--vp-c-gutter)}@media (min-width: 960px){.VPNavBar:not(.home.top) .divider-line[data-v-ccf7ddec]{background-color:var(--vp-c-gutter)}.VPNavBar:not(.has-sidebar):not(.home.top) .divider[data-v-ccf7ddec]{background-color:var(--vp-c-gutter)}}.VPNavScreenAppearance[data-v-2d7af913]{display:flex;justify-content:space-between;align-items:center;border-radius:8px;padding:12px 14px 12px 16px;background-color:var(--vp-c-bg-soft)}.text[data-v-2d7af913]{line-height:24px;font-size:12px;font-weight:500;color:var(--vp-c-text-2)}.VPNavScreenMenuLink[data-v-7f31e1f6]{display:block;border-bottom:1px solid var(--vp-c-divider);padding:12px 0 11px;line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-1);transition:border-color .25s,color .25s}.VPNavScreenMenuLink[data-v-7f31e1f6]:hover{color:var(--vp-c-brand-1)}.VPNavScreenMenuGroupLink[data-v-19976ae1]{display:block;margin-left:12px;line-height:32px;font-size:14px;font-weight:400;color:var(--vp-c-text-1);transition:color .25s}.VPNavScreenMenuGroupLink[data-v-19976ae1]:hover{color:var(--vp-c-brand-1)}.VPNavScreenMenuGroupSection[data-v-8133b170]{display:block}.title[data-v-8133b170]{line-height:32px;font-size:13px;font-weight:700;color:var(--vp-c-text-2);transition:color .25s}.VPNavScreenMenuGroup[data-v-ff6087d4]{border-bottom:1px solid var(--vp-c-divider);height:48px;overflow:hidden;transition:border-color .5s}.VPNavScreenMenuGroup .items[data-v-ff6087d4]{visibility:hidden}.VPNavScreenMenuGroup.open .items[data-v-ff6087d4]{visibility:visible}.VPNavScreenMenuGroup.open[data-v-ff6087d4]{padding-bottom:10px;height:auto}.VPNavScreenMenuGroup.open .button[data-v-ff6087d4]{padding-bottom:6px;color:var(--vp-c-brand-1)}.VPNavScreenMenuGroup.open .button-icon[data-v-ff6087d4]{transform:rotate(45deg)}.button[data-v-ff6087d4]{display:flex;justify-content:space-between;align-items:center;padding:12px 4px 11px 0;width:100%;line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-1);transition:color .25s}.button[data-v-ff6087d4]:hover{color:var(--vp-c-brand-1)}.button-icon[data-v-ff6087d4]{transition:transform .25s}.group[data-v-ff6087d4]:first-child{padding-top:0}.group+.group[data-v-ff6087d4],.group+.item[data-v-ff6087d4]{padding-top:4px}.VPNavScreenTranslations[data-v-858fe1a4]{height:24px;overflow:hidden}.VPNavScreenTranslations.open[data-v-858fe1a4]{height:auto}.title[data-v-858fe1a4]{display:flex;align-items:center;font-size:14px;font-weight:500;color:var(--vp-c-text-1)}.icon[data-v-858fe1a4]{font-size:16px}.icon.lang[data-v-858fe1a4]{margin-right:8px}.icon.chevron[data-v-858fe1a4]{margin-left:4px}.list[data-v-858fe1a4]{padding:4px 0 0 24px}.link[data-v-858fe1a4]{line-height:32px;font-size:13px;color:var(--vp-c-text-1)}.VPNavScreen[data-v-cc5739dd]{position:fixed;top:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 1px);right:0;bottom:0;left:0;padding:0 32px;width:100%;background-color:var(--vp-nav-screen-bg-color);overflow-y:auto;transition:background-color .5s;pointer-events:auto}.VPNavScreen.fade-enter-active[data-v-cc5739dd],.VPNavScreen.fade-leave-active[data-v-cc5739dd]{transition:opacity .25s}.VPNavScreen.fade-enter-active .container[data-v-cc5739dd],.VPNavScreen.fade-leave-active .container[data-v-cc5739dd]{transition:transform .25s ease}.VPNavScreen.fade-enter-from[data-v-cc5739dd],.VPNavScreen.fade-leave-to[data-v-cc5739dd]{opacity:0}.VPNavScreen.fade-enter-from .container[data-v-cc5739dd],.VPNavScreen.fade-leave-to .container[data-v-cc5739dd]{transform:translateY(-8px)}@media (min-width: 768px){.VPNavScreen[data-v-cc5739dd]{display:none}}.container[data-v-cc5739dd]{margin:0 auto;padding:24px 0 96px;max-width:288px}.menu+.translations[data-v-cc5739dd],.menu+.appearance[data-v-cc5739dd],.translations+.appearance[data-v-cc5739dd]{margin-top:24px}.menu+.social-links[data-v-cc5739dd]{margin-top:16px}.appearance+.social-links[data-v-cc5739dd]{margin-top:16px}.VPNav[data-v-ae24b3ad]{position:relative;top:var(--vp-layout-top-height, 0px);left:0;z-index:var(--vp-z-index-nav);width:100%;pointer-events:none;transition:background-color .5s}@media (min-width: 960px){.VPNav[data-v-ae24b3ad]{position:fixed}}.VPSidebarItem.level-0[data-v-b8d55f3b]{padding-bottom:24px}.VPSidebarItem.collapsed.level-0[data-v-b8d55f3b]{padding-bottom:10px}.item[data-v-b8d55f3b]{position:relative;display:flex;width:100%}.VPSidebarItem.collapsible>.item[data-v-b8d55f3b]{cursor:pointer}.indicator[data-v-b8d55f3b]{position:absolute;top:6px;bottom:6px;left:-17px;width:2px;border-radius:2px;transition:background-color .25s}.VPSidebarItem.level-2.is-active>.item>.indicator[data-v-b8d55f3b],.VPSidebarItem.level-3.is-active>.item>.indicator[data-v-b8d55f3b],.VPSidebarItem.level-4.is-active>.item>.indicator[data-v-b8d55f3b],.VPSidebarItem.level-5.is-active>.item>.indicator[data-v-b8d55f3b]{background-color:var(--vp-c-brand-1)}.link[data-v-b8d55f3b]{display:flex;align-items:center;flex-grow:1}.text[data-v-b8d55f3b]{flex-grow:1;padding:4px 0;line-height:24px;font-size:14px;transition:color .25s}.VPSidebarItem.level-0 .text[data-v-b8d55f3b]{font-weight:700;color:var(--vp-c-text-1)}.VPSidebarItem.level-1 .text[data-v-b8d55f3b],.VPSidebarItem.level-2 .text[data-v-b8d55f3b],.VPSidebarItem.level-3 .text[data-v-b8d55f3b],.VPSidebarItem.level-4 .text[data-v-b8d55f3b],.VPSidebarItem.level-5 .text[data-v-b8d55f3b]{font-weight:500;color:var(--vp-c-text-2)}.VPSidebarItem.level-0.is-link>.item>.link:hover .text[data-v-b8d55f3b],.VPSidebarItem.level-1.is-link>.item>.link:hover .text[data-v-b8d55f3b],.VPSidebarItem.level-2.is-link>.item>.link:hover .text[data-v-b8d55f3b],.VPSidebarItem.level-3.is-link>.item>.link:hover .text[data-v-b8d55f3b],.VPSidebarItem.level-4.is-link>.item>.link:hover .text[data-v-b8d55f3b],.VPSidebarItem.level-5.is-link>.item>.link:hover .text[data-v-b8d55f3b]{color:var(--vp-c-brand-1)}.VPSidebarItem.level-0.has-active>.item>.text[data-v-b8d55f3b],.VPSidebarItem.level-1.has-active>.item>.text[data-v-b8d55f3b],.VPSidebarItem.level-2.has-active>.item>.text[data-v-b8d55f3b],.VPSidebarItem.level-3.has-active>.item>.text[data-v-b8d55f3b],.VPSidebarItem.level-4.has-active>.item>.text[data-v-b8d55f3b],.VPSidebarItem.level-5.has-active>.item>.text[data-v-b8d55f3b],.VPSidebarItem.level-0.has-active>.item>.link>.text[data-v-b8d55f3b],.VPSidebarItem.level-1.has-active>.item>.link>.text[data-v-b8d55f3b],.VPSidebarItem.level-2.has-active>.item>.link>.text[data-v-b8d55f3b],.VPSidebarItem.level-3.has-active>.item>.link>.text[data-v-b8d55f3b],.VPSidebarItem.level-4.has-active>.item>.link>.text[data-v-b8d55f3b],.VPSidebarItem.level-5.has-active>.item>.link>.text[data-v-b8d55f3b]{color:var(--vp-c-text-1)}.VPSidebarItem.level-0.is-active>.item .link>.text[data-v-b8d55f3b],.VPSidebarItem.level-1.is-active>.item .link>.text[data-v-b8d55f3b],.VPSidebarItem.level-2.is-active>.item .link>.text[data-v-b8d55f3b],.VPSidebarItem.level-3.is-active>.item .link>.text[data-v-b8d55f3b],.VPSidebarItem.level-4.is-active>.item .link>.text[data-v-b8d55f3b],.VPSidebarItem.level-5.is-active>.item .link>.text[data-v-b8d55f3b]{color:var(--vp-c-brand-1)}.caret[data-v-b8d55f3b]{display:flex;justify-content:center;align-items:center;margin-right:-7px;width:32px;height:32px;color:var(--vp-c-text-3);cursor:pointer;transition:color .25s;flex-shrink:0}.item:hover .caret[data-v-b8d55f3b]{color:var(--vp-c-text-2)}.item:hover .caret[data-v-b8d55f3b]:hover{color:var(--vp-c-text-1)}.caret-icon[data-v-b8d55f3b]{font-size:18px;transform:rotate(90deg);transition:transform .25s}.VPSidebarItem.collapsed .caret-icon[data-v-b8d55f3b]{transform:rotate(0)}.VPSidebarItem.level-1 .items[data-v-b8d55f3b],.VPSidebarItem.level-2 .items[data-v-b8d55f3b],.VPSidebarItem.level-3 .items[data-v-b8d55f3b],.VPSidebarItem.level-4 .items[data-v-b8d55f3b],.VPSidebarItem.level-5 .items[data-v-b8d55f3b]{border-left:1px solid var(--vp-c-divider);padding-left:16px}.VPSidebarItem.collapsed .items[data-v-b8d55f3b]{display:none}.VPSidebar[data-v-575e6a36]{position:fixed;top:var(--vp-layout-top-height, 0px);bottom:0;left:0;z-index:var(--vp-z-index-sidebar);padding:32px 32px 96px;width:calc(100vw - 64px);max-width:320px;background-color:var(--vp-sidebar-bg-color);opacity:0;box-shadow:var(--vp-c-shadow-3);overflow-x:hidden;overflow-y:auto;transform:translate(-100%);transition:opacity .5s,transform .25s ease;overscroll-behavior:contain}.VPSidebar.open[data-v-575e6a36]{opacity:1;visibility:visible;transform:translate(0);transition:opacity .25s,transform .5s cubic-bezier(.19,1,.22,1)}.dark .VPSidebar[data-v-575e6a36]{box-shadow:var(--vp-shadow-1)}@media (min-width: 960px){.VPSidebar[data-v-575e6a36]{padding-top:var(--vp-nav-height);width:var(--vp-sidebar-width);max-width:100%;background-color:var(--vp-sidebar-bg-color);opacity:1;visibility:visible;box-shadow:none;transform:translate(0)}}@media (min-width: 1440px){.VPSidebar[data-v-575e6a36]{padding-left:max(32px,calc((100% - (var(--vp-layout-max-width) - 64px)) / 2));width:calc((100% - (var(--vp-layout-max-width) - 64px)) / 2 + var(--vp-sidebar-width) - 32px)}}@media (min-width: 960px){.curtain[data-v-575e6a36]{position:sticky;top:-64px;left:0;z-index:1;margin-top:calc(var(--vp-nav-height) * -1);margin-right:-32px;margin-left:-32px;height:var(--vp-nav-height);background-color:var(--vp-sidebar-bg-color)}}.nav[data-v-575e6a36]{outline:0}.group+.group[data-v-575e6a36]{border-top:1px solid var(--vp-c-divider);padding-top:10px}@media (min-width: 960px){.group[data-v-575e6a36]{padding-top:10px;width:calc(var(--vp-sidebar-width) - 64px)}}.VPSkipLink[data-v-0f60ec36]{top:8px;left:8px;padding:8px 16px;z-index:999;border-radius:8px;font-size:12px;font-weight:700;text-decoration:none;color:var(--vp-c-brand-1);box-shadow:var(--vp-shadow-3);background-color:var(--vp-c-bg)}.VPSkipLink[data-v-0f60ec36]:focus{height:auto;width:auto;clip:auto;clip-path:none}@media (min-width: 1280px){.VPSkipLink[data-v-0f60ec36]{top:14px;left:16px}}.Layout[data-v-5d98c3a5]{display:flex;flex-direction:column;min-height:100vh}.VPHomeSponsors[data-v-3d121b4a]{border-top:1px solid var(--vp-c-gutter);padding-top:88px!important}.VPHomeSponsors[data-v-3d121b4a]{margin:96px 0}@media (min-width: 768px){.VPHomeSponsors[data-v-3d121b4a]{margin:128px 0}}.VPHomeSponsors[data-v-3d121b4a]{padding:0 24px}@media (min-width: 768px){.VPHomeSponsors[data-v-3d121b4a]{padding:0 48px}}@media (min-width: 960px){.VPHomeSponsors[data-v-3d121b4a]{padding:0 64px}}.container[data-v-3d121b4a]{margin:0 auto;max-width:1152px}.love[data-v-3d121b4a]{margin:0 auto;width:fit-content;font-size:28px;color:var(--vp-c-text-3)}.icon[data-v-3d121b4a]{display:inline-block}.message[data-v-3d121b4a]{margin:0 auto;padding-top:10px;max-width:320px;text-align:center;line-height:24px;font-size:16px;font-weight:500;color:var(--vp-c-text-2)}.sponsors[data-v-3d121b4a]{padding-top:32px}.action[data-v-3d121b4a]{padding-top:40px;text-align:center}.VPTeamPage[data-v-7c57f839]{margin:96px 0}@media (min-width: 768px){.VPTeamPage[data-v-7c57f839]{margin:128px 0}}.VPHome .VPTeamPageTitle[data-v-7c57f839-s]{border-top:1px solid var(--vp-c-gutter);padding-top:88px!important}.VPTeamPageSection+.VPTeamPageSection[data-v-7c57f839-s],.VPTeamMembers+.VPTeamPageSection[data-v-7c57f839-s]{margin-top:64px}.VPTeamMembers+.VPTeamMembers[data-v-7c57f839-s]{margin-top:24px}@media (min-width: 768px){.VPTeamPageTitle+.VPTeamPageSection[data-v-7c57f839-s]{margin-top:16px}.VPTeamPageSection+.VPTeamPageSection[data-v-7c57f839-s],.VPTeamMembers+.VPTeamPageSection[data-v-7c57f839-s]{margin-top:96px}}.VPTeamMembers[data-v-7c57f839-s]{padding:0 24px}@media (min-width: 768px){.VPTeamMembers[data-v-7c57f839-s]{padding:0 48px}}@media (min-width: 960px){.VPTeamMembers[data-v-7c57f839-s]{padding:0 64px}}.VPTeamPageTitle[data-v-bf2cbdac]{padding:48px 32px;text-align:center}@media (min-width: 768px){.VPTeamPageTitle[data-v-bf2cbdac]{padding:64px 48px 48px}}@media (min-width: 960px){.VPTeamPageTitle[data-v-bf2cbdac]{padding:80px 64px 48px}}.title[data-v-bf2cbdac]{letter-spacing:0;line-height:44px;font-size:36px;font-weight:500}@media (min-width: 768px){.title[data-v-bf2cbdac]{letter-spacing:-.5px;line-height:56px;font-size:48px}}.lead[data-v-bf2cbdac]{margin:0 auto;max-width:512px;padding-top:12px;line-height:24px;font-size:16px;font-weight:500;color:var(--vp-c-text-2)}@media (min-width: 768px){.lead[data-v-bf2cbdac]{max-width:592px;letter-spacing:.15px;line-height:28px;font-size:20px}}.VPTeamPageSection[data-v-b1a88750]{padding:0 32px}@media (min-width: 768px){.VPTeamPageSection[data-v-b1a88750]{padding:0 48px}}@media (min-width: 960px){.VPTeamPageSection[data-v-b1a88750]{padding:0 64px}}.title[data-v-b1a88750]{position:relative;margin:0 auto;max-width:1152px;text-align:center;color:var(--vp-c-text-2)}.title-line[data-v-b1a88750]{position:absolute;top:16px;left:0;width:100%;height:1px;background-color:var(--vp-c-divider)}.title-text[data-v-b1a88750]{position:relative;display:inline-block;padding:0 24px;letter-spacing:0;line-height:32px;font-size:20px;font-weight:500;background-color:var(--vp-c-bg)}.lead[data-v-b1a88750]{margin:0 auto;max-width:480px;padding-top:12px;text-align:center;line-height:24px;font-size:16px;font-weight:500;color:var(--vp-c-text-2)}.members[data-v-b1a88750]{padding-top:40px}.VPTeamMembersItem[data-v-f3fa364a]{display:flex;flex-direction:column;gap:2px;border-radius:12px;width:100%;height:100%;overflow:hidden}.VPTeamMembersItem.small .profile[data-v-f3fa364a]{padding:32px}.VPTeamMembersItem.small .data[data-v-f3fa364a]{padding-top:20px}.VPTeamMembersItem.small .avatar[data-v-f3fa364a]{width:64px;height:64px}.VPTeamMembersItem.small .name[data-v-f3fa364a]{line-height:24px;font-size:16px}.VPTeamMembersItem.small .affiliation[data-v-f3fa364a]{padding-top:4px;line-height:20px;font-size:14px}.VPTeamMembersItem.small .desc[data-v-f3fa364a]{padding-top:12px;line-height:20px;font-size:14px}.VPTeamMembersItem.small .links[data-v-f3fa364a]{margin:0 -16px -20px;padding:10px 0 0}.VPTeamMembersItem.medium .profile[data-v-f3fa364a]{padding:48px 32px}.VPTeamMembersItem.medium .data[data-v-f3fa364a]{padding-top:24px;text-align:center}.VPTeamMembersItem.medium .avatar[data-v-f3fa364a]{width:96px;height:96px}.VPTeamMembersItem.medium .name[data-v-f3fa364a]{letter-spacing:.15px;line-height:28px;font-size:20px}.VPTeamMembersItem.medium .affiliation[data-v-f3fa364a]{padding-top:4px;font-size:16px}.VPTeamMembersItem.medium .desc[data-v-f3fa364a]{padding-top:16px;max-width:288px;font-size:16px}.VPTeamMembersItem.medium .links[data-v-f3fa364a]{margin:0 -16px -12px;padding:16px 12px 0}.profile[data-v-f3fa364a]{flex-grow:1;background-color:var(--vp-c-bg-soft)}.data[data-v-f3fa364a]{text-align:center}.avatar[data-v-f3fa364a]{position:relative;flex-shrink:0;margin:0 auto;border-radius:50%;box-shadow:var(--vp-shadow-3)}.avatar-img[data-v-f3fa364a]{position:absolute;top:0;right:0;bottom:0;left:0;border-radius:50%;object-fit:cover}.name[data-v-f3fa364a]{margin:0;font-weight:600}.affiliation[data-v-f3fa364a]{margin:0;font-weight:500;color:var(--vp-c-text-2)}.org.link[data-v-f3fa364a]{color:var(--vp-c-text-2);transition:color .25s}.org.link[data-v-f3fa364a]:hover{color:var(--vp-c-brand-1)}.desc[data-v-f3fa364a]{margin:0 auto}.desc[data-v-f3fa364a] a{font-weight:500;color:var(--vp-c-brand-1);text-decoration-style:dotted;transition:color .25s}.links[data-v-f3fa364a]{display:flex;justify-content:center;height:56px}.sp-link[data-v-f3fa364a]{display:flex;justify-content:center;align-items:center;text-align:center;padding:16px;font-size:14px;font-weight:500;color:var(--vp-c-sponsor);background-color:var(--vp-c-bg-soft);transition:color .25s,background-color .25s}.sp .sp-link.link[data-v-f3fa364a]:hover,.sp .sp-link.link[data-v-f3fa364a]:focus{outline:none;color:var(--vp-c-white);background-color:var(--vp-c-sponsor)}.sp-icon[data-v-f3fa364a]{margin-right:8px;font-size:16px}.VPTeamMembers.small .container[data-v-6cb0dbc4]{grid-template-columns:repeat(auto-fit,minmax(224px,1fr))}.VPTeamMembers.small.count-1 .container[data-v-6cb0dbc4]{max-width:276px}.VPTeamMembers.small.count-2 .container[data-v-6cb0dbc4]{max-width:576px}.VPTeamMembers.small.count-3 .container[data-v-6cb0dbc4]{max-width:876px}.VPTeamMembers.medium .container[data-v-6cb0dbc4]{grid-template-columns:repeat(auto-fit,minmax(256px,1fr))}@media (min-width: 375px){.VPTeamMembers.medium .container[data-v-6cb0dbc4]{grid-template-columns:repeat(auto-fit,minmax(288px,1fr))}}.VPTeamMembers.medium.count-1 .container[data-v-6cb0dbc4]{max-width:368px}.VPTeamMembers.medium.count-2 .container[data-v-6cb0dbc4]{max-width:760px}.container[data-v-6cb0dbc4]{display:grid;gap:24px;margin:0 auto;max-width:1152px}:root{--vp-nolebase-highlight-targeted-heading-color: var(--vp-custom-block-tip-text);--vp-nolebase-highlight-targeted-heading-bg: var(--vp-custom-block-tip-bg)}@keyframes vp-nolebase-highlight-targeted-heading-animation{0%{background-color:transparent;box-shadow:0 0 0 8px transparent}10%,35%{color:var(--vp-nolebase-highlight-targeted-heading-color);border-color:transparent;border-radius:4px;background-color:var(--vp-nolebase-highlight-targeted-heading-bg);box-shadow:0 0 0 8px var(--vp-nolebase-highlight-targeted-heading-bg)}99%{background-color:transparent;border-radius:4px;box-shadow:0 0 0 8px transparent}to{border-radius:0;background-color:transparent;box-shadow:none}}.VPNolebaseHighlightTargetedHeadingAnimated{animation:vp-nolebase-highlight-targeted-heading-animation 1.5s ease-in-out}*,:before,:after{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset: ;--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / .5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: }::backdrop{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset: ;--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / .5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: }@font-face{font-family:"Baloo 2";font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/baloo2/v21/wXK0E3kTposypRydzVT08TS3JnAmtdgazZpp_led7Q.woff2) format("woff2");unicode-range:U+0900-097F,U+1CD0-1CF9,U+200C-200D,U+20A8,U+20B9,U+20F0,U+25CC,U+A830-A839,U+A8E0-A8FF,U+11B00-11B09}@font-face{font-family:"Baloo 2";font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/baloo2/v21/wXK0E3kTposypRydzVT08TS3JnAmtdgazZpn_led7Q.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:"Baloo 2";font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/baloo2/v21/wXK0E3kTposypRydzVT08TS3JnAmtdgazZpm_led7Q.woff2) format("woff2");unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:"Baloo 2";font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/baloo2/v21/wXK0E3kTposypRydzVT08TS3JnAmtdgazZpo_lc.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Chakra Petch;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/chakrapetch/v11/cIf6MapbsEk7TDLdtEz1BwkWi6pgeL4.woff2) format("woff2");unicode-range:U+0E01-0E5B,U+200C-200D,U+25CC}@font-face{font-family:Chakra Petch;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/chakrapetch/v11/cIf6MapbsEk7TDLdtEz1BwkWkKpgeL4.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Chakra Petch;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/chakrapetch/v11/cIf6MapbsEk7TDLdtEz1BwkWkapgeL4.woff2) format("woff2");unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Chakra Petch;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/chakrapetch/v11/cIf6MapbsEk7TDLdtEz1BwkWn6pg.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Jura;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/jura/v31/z7NOdRfiaC4Vd8hhoPzfb5vBTP1d7ZurR_ibHw.woff2) format("woff2");unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Jura;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/jura/v31/z7NOdRfiaC4Vd8hhoPzfb5vBTP1d7ZuiR_ibHw.woff2) format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Jura;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/jura/v31/z7NOdRfiaC4Vd8hhoPzfb5vBTP1d7ZuqR_ibHw.woff2) format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Jura;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/jura/v31/z7NOdRfiaC4Vd8hhoPzfb5vBTP1d7ZulR_ibHw.woff2) format("woff2");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Jura;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/jura/v31/z7NOdRfiaC4Vd8hhoPzfb5vBTP1d7ZvuR_ibHw.woff2) format("woff2");unicode-range:U+200C-200D,U+2010,U+25CC,U+A900-A92F}@font-face{font-family:Jura;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/jura/v31/z7NOdRfiaC4Vd8hhoPzfb5vBTP1d7ZupR_ibHw.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Jura;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/jura/v31/z7NOdRfiaC4Vd8hhoPzfb5vBTP1d7ZuoR_ibHw.woff2) format("woff2");unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Jura;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/jura/v31/z7NOdRfiaC4Vd8hhoPzfb5vBTP1d7ZumR_g.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Noto Sans;font-style:normal;font-weight:400;font-stretch:normal;font-display:swap;src:url(https://fonts.gstatic.com/s/notosans/v36/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9X6VLKzA.woff2) format("woff2");unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Noto Sans;font-style:normal;font-weight:400;font-stretch:normal;font-display:swap;src:url(https://fonts.gstatic.com/s/notosans/v36/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9e6VLKzA.woff2) format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Noto Sans;font-style:normal;font-weight:400;font-stretch:normal;font-display:swap;src:url(https://fonts.gstatic.com/s/notosans/v36/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9b6VLKzA.woff2) format("woff2");unicode-range:U+0900-097F,U+1CD0-1CF9,U+200C-200D,U+20A8,U+20B9,U+20F0,U+25CC,U+A830-A839,U+A8E0-A8FF,U+11B00-11B09}@font-face{font-family:Noto Sans;font-style:normal;font-weight:400;font-stretch:normal;font-display:swap;src:url(https://fonts.gstatic.com/s/notosans/v36/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9W6VLKzA.woff2) format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Noto Sans;font-style:normal;font-weight:400;font-stretch:normal;font-display:swap;src:url(https://fonts.gstatic.com/s/notosans/v36/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9Z6VLKzA.woff2) format("woff2");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Noto Sans;font-style:normal;font-weight:400;font-stretch:normal;font-display:swap;src:url(https://fonts.gstatic.com/s/notosans/v36/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9V6VLKzA.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Noto Sans;font-style:normal;font-weight:400;font-stretch:normal;font-display:swap;src:url(https://fonts.gstatic.com/s/notosans/v36/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9U6VLKzA.woff2) format("woff2");unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Noto Sans;font-style:normal;font-weight:400;font-stretch:normal;font-display:swap;src:url(https://fonts.gstatic.com/s/notosans/v36/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9a6VI.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu72xKOzY.woff2) format("woff2");unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu5mxKOzY.woff2) format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu7mxKOzY.woff2) format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu4WxKOzY.woff2) format("woff2");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu7WxKOzY.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu7GxKOzY.woff2) format("woff2");unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu4mxK.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2) format("woff2");unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/assets/inter-roman-cyrillic.C5lxZ8CY.woff2) format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/assets/inter-roman-greek-ext.CqjqNYQ-.woff2) format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/assets/inter-roman-greek.BBVDIX6e.woff2) format("woff2");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/assets/inter-roman-vietnamese.BjW4sHH5.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/assets/inter-roman-latin-ext.4ZJIpNVo.woff2) format("woff2");unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/assets/inter-roman-latin.Di8DUHzh.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/assets/inter-italic-cyrillic-ext.r48I6akx.woff2) format("woff2");unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/assets/inter-italic-cyrillic.By2_1cv3.woff2) format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/assets/inter-italic-greek-ext.1u6EdAuj.woff2) format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/assets/inter-italic-greek.DJ8dCoTZ.woff2) format("woff2");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/assets/inter-italic-vietnamese.BSbpV94h.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/assets/inter-italic-latin-ext.CN1xVJS-.woff2) format("woff2");unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/assets/inter-italic-latin.C2AdPX0b.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Punctuation SC;font-weight:400;src:local("PingFang SC Regular"),local("Noto Sans CJK SC"),local("Microsoft YaHei");unicode-range:U+201C,U+201D,U+2018,U+2019,U+2E3A,U+2014,U+2013,U+2026,U+00B7,U+007E,U+002F}@font-face{font-family:Punctuation SC;font-weight:500;src:local("PingFang SC Medium"),local("Noto Sans CJK SC"),local("Microsoft YaHei");unicode-range:U+201C,U+201D,U+2018,U+2019,U+2E3A,U+2014,U+2013,U+2026,U+00B7,U+007E,U+002F}@font-face{font-family:Punctuation SC;font-weight:600;src:local("PingFang SC Semibold"),local("Noto Sans CJK SC Bold"),local("Microsoft YaHei Bold");unicode-range:U+201C,U+201D,U+2018,U+2019,U+2E3A,U+2014,U+2013,U+2026,U+00B7,U+007E,U+002F}@font-face{font-family:Punctuation SC;font-weight:700;src:local("PingFang SC Semibold"),local("Noto Sans CJK SC Bold"),local("Microsoft YaHei Bold");unicode-range:U+201C,U+201D,U+2018,U+2019,U+2E3A,U+2014,U+2013,U+2026,U+00B7,U+007E,U+002F}html{overflow-x:hidden}:root{--vp-c-bg: #3B4252;--vp-c-bg-elv: #434C5E;--vp-font-family-base: Itim;--vp-font-family-mono: Roboto Mono;--vp-layout-max-width: 1080px;--vp-nav-height: 48px;--vp-local-search-bg: var(--vp-c-bg-alt)}footer{color:var(--vp-c-default-1)}footer a[href^=http]:after{color:var(--vp-c-border)!important}.title{justify-content:center;border:none!important;position:unset!important;padding:0!important;width:unset!important}.title span{font-size:x-large}.search{padding-left:0;display:flex;flex-grow:0!important;padding-left:unset!important}.DocSearch-Button{margin:auto;width:unset;border:none!important}.DocSearch-Button-Placeholder{margin-top:unset!important;padding:unset!important;font-size:unset!important;font-weight:unset!important;color:unset!important;margin-right:8px}.VPNavBarMenu{align-items:flex-end}.VPNavBarMenuLink{line-height:unset!important;font-size:unset!important;font-weight:unset!important;color:unset!important}ul>li>ul{position:relative}ul>li>ul:before{position:absolute;content:"";width:2px;background:var(--vp-c-text-1);opacity:.3;left:-16px;top:8px;bottom:8px}.aside{display:none!important}.img-container{padding:15px;position:relative;height:11lh;width:fit-content;margin:auto}.img-container img{clip-path:polygon(18px 0%,100% 0,100% calc(100% - 18px),calc(100% - 18px) 100%,0 100%,0% 18px);height:100%;object-fit:contain;background:#fff}.img-container:after,.img-container:before{content:"";display:block;position:absolute;border:50px solid transparent;transform:rotate(135deg)}.img-container:after{bottom:-60px;right:-65px;box-shadow:0 7px 6px -9px #000}.img-container:before{top:-60px;left:-65px;box-shadow:0 -7px 6px -9px #000}.VPDoc{padding:0 32px!important}.vp-doc a{color:unset;text-decoration:unset;font-weight:unset;text-underline-offset:unset;margin:0 -.4em;padding:.1em .4em;border-radius:.8em .3em;background:transparent;background-image:linear-gradient(to right,#ffe1000d,#ffe10059 4%,#ffe10026);-webkit-box-decoration-break:clone;box-decoration-break:clone}.vp-doc a:hover{color:unset;background-image:linear-gradient(to right,#ffe1001a,#ffe100b3 4%,#ffe1004d)}.vp-doc a[href^=http]:after{content:"";display:inline-block;margin-top:-1px;margin-left:4px;width:11px;height:11px;background:currentColor;color:var(--vp-c-text-3);flex-shrink:0;--icon: url("data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' %3E%3Cpath d='M0 0h24v24H0V0z' fill='none' /%3E%3Cpath d='M9 5v2h6.59L4 18.59 5.41 20 17 8.41V15h2V5H9z' /%3E%3C/svg%3E");-webkit-mask-image:var(--icon);mask-image:var(--icon)}.VPNav{left:96px!important;right:32px!important;width:unset!important;position:absolute!important;overflow:hidden}.wrapper{padding:0!important}.VPNavBar{background-color:unset!important}.VPNav .container{align-items:flex-end}.VPNav .content{padding:0!important}.VPNav .content-body{height:unset!important;align-items:flex-end!important;column-gap:unset!important}.VPNavBarHamburger{width:unset!important}.title{height:unset!important}a.title,.VPNavBarMenuLink,.VPNavBarSocialLinks a,.DocSearch-Button,.VPNav button{height:36px!important;border-radius:10px 10px 0 0;padding:8px 8px 16px!important;margin-bottom:-8px!important}.VPNav a:hover,.DocSearch-Button:hover,.VPNav button:hover{margin-bottom:unset!important}a.title{background-color:#0ff}.DocSearch-Button{background-color:#ff0!important}.VPNav .VPNavBarMenuLink[href="https://moddingtree.com"]{background-color:#0f0}.VPNav .VPNavBarMenuLink[href="https://incremental.social"]{background:#f0f}.VPNav button{background:red}.VPNav .VPNavBarSocialLinks [href="https://code.incremental.social/thepaperpilot"]{background:#f70}.VPNav .VPNavBarSocialLinks [href="https://matrix.to/#/@thepaperpilot:incremental.social"]{background:#3c9a3c}.VPNav .VPNavBarSocialLinks [href="https://incremental.social/u/thepaperpilot"]{background:#a75aff}.VPNav .divider{display:none!important}.VPSocialLinks{align-items:flex-end!important;margin-right:0!important}.VPSocialLinks:before{display:none}.VPNavBarExtra{display:none!important}.VPNavBarSocialLinks{display:flex!important}.VPNavScreenSocialLinks a,.VPNavScreenMenuLink,.VPNavScreenMenuLink:after{color:var(--vp-c-bg-alt)!important}@media (max-width: 500px){.VPNavBarSocialLinks{display:none!important}}@media (min-width: 501px){.VPNavScreenSocialLinks{display:none!important}}@media (max-width: 400px){.title span{width:60px}.title span:before{content:"Home ."}}.VPContent{padding-top:0!important;margin-top:var(--vp-nav-height)!important;padding-right:calc((100vw - var(--vp-layout-max-width)) / 2)!important;padding-left:calc((100vw - var(--vp-layout-max-width)) / 2)!important}@media (min-width: 960px){.VPNav{right:calc(max(0px,(100vw - var(--vp-layout-max-width)) / 2) + 32px)!important;left:calc(max(-15px,(100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width)) + 32px)!important}.VPContent{padding-left:calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width))!important}}.vp-doc .header-anchor{margin-left:calc(-1em - 23px)}.vp-doc .header-anchor{top:0!important}.VPSidebar{opacity:1!important;transition:.5s ease-out!important;box-shadow:0 0 10px 1px #0003!important}.VPLocalNav{position:fixed!important;border-bottom:none!important;background-color:unset!important;pointer-events:none}.VPLocalNav .container{align-items:flex-start!important;flex-direction:column!important}.VPLocalNav>.container>*{pointer-events:all}.VPLocalNav .menu{background:#7afcff;box-shadow:0 0 5px 1px #0003;margin-top:10px;height:30px;width:90px;padding:0 0 0 8px!important}.VPLocalNav button:not(.menu){background:#ff7eb9;padding:4px 30px 4px 8px;box-shadow:0 0 5px 1px #0003}.outline-marker{left:16px!important}.VPLocalNavOutlineDropdown{padding:0!important;margin-top:10px}.VPLocalNavOutlineDropdown button{padding:0!important;width:90px;height:30px}.curtain{display:none}@media (max-width: 840px){.DocSearch-Button-Keys{display:none!important}}@media (max-width: 959px){.VPSidebar{margin-left:-1000px!important;padding:30px 30px 30px 1030px!important;box-sizing:content-box;background:linear-gradient(to bottom,var(--vp-sidebar-bg-color) 29px,var(--vp-c-divider) 1px);background-size:100% 30px;line-height:30px;width:calc(100vw - 128px)}}.VPLocalNavOutlineDropdown .items{background:linear-gradient(to bottom,var(--vp-sidebar-bg-color) 29px,var(--vp-c-divider) 1px);background-size:100% 30px;top:85px;border-radius:0}.VPLocalNavOutlineDropdown ul>li>ul:before{left:0}.VPLocalNavOutlineDropdown .header,.VPLocalNavOutlineDropdown .outline{background:none!important;padding:0!important}.VPLocalNavOutlineDropdown .top-link,.VPLocalNavOutlineDropdown .outline-link{line-height:30px!important;font-size:unset!important;font-weight:unset!important}.aside-curtain{display:none!important}@media (min-width: 960px){.VPSidebar{transform:rotate(1.4deg)!important;top:1em!important;bottom:unset!important;--vp-sidebar-width: 250px !important;background:#feff9c!important;padding:30px!important;width:var(--vp-sidebar-width)!important;margin-left:max(-15px,calc((100% - (var(--vp-layout-max-width) - 60px)) / 2))!important;max-height:40vh;transition-duration:0s!important}.VPLocalNavOutlineDropdown{display:none}.VPDoc .aside{display:block!important;transform:rotate(1.4deg)!important;position:fixed;top:calc(40vh + 2em);left:0;--vp-sidebar-width: 250px !important;background:#feff9c!important;width:var(--vp-sidebar-width)!important;padding:0!important;margin-left:max(-15px,calc((100% - (var(--vp-layout-max-width) - 60px)) / 2))!important;max-height:40vh;overflow-y:auto}.VPDoc .aside-container{position:unset!important;height:unset!important;overflow:unset!important;padding-top:unset!important;width:unset!important}.VPDoc .aside-content{min-height:unset!important;padding:0!important}.VPDoc .aside-content .content{padding:30px!important}.outline-title{font-size:14px;font-weight:700!important;line-height:30px!important}.VPDoc .aside ul>li>ul:before{display:none}}.VPContent .container{background:linear-gradient(to bottom,var(--vp-sidebar-bg-color) 29px,var(--vp-c-divider) 1px);background-size:100% 30px;line-height:30px;box-shadow:0 0 10px 1px #0003!important}.VPContent .content{padding:0 30px!important}.content-container{border-left:double 7px var(--vp-c-divider);padding:30px 0 30px 8px;max-width:unset!important}article{padding-top:30px}.vp-doc .h-feed article{padding-top:0!important}.vp-doc h2+.e-content{margin-top:0!important}.VPDoc h1,.VPDoc h2,.VPDoc h3,.VPDoc h4,.VPDoc h5,.VPDoc h6{margin:0!important;padding:0!important;line-height:30px!important}.VPDoc h1+p{margin-top:0!important}.VPDoc h2,.VPDoc h3,.VPDoc h4,.VPDoc h5,.VPDoc h6{margin-top:30px!important;margin-bottom:-30px!important;border:none!important}ul{margin:0!important}li+li{margin:0!important}.VPDoc p{padding:0!important;margin:30px 0!important;line-height:30px!important}blockquote{margin:30px 0!important}blockquote:first-child,blockquote:first-child p{margin-top:0!important}.VPDoc :has(+hr),.VPDoc :has(+h2),.VPDoc :has(+h3),.VPDoc :has(+h4),.VPDoc :has(+h5),.VPDoc :has(+h6),.VPDoc :has(+ul){margin-bottom:0!important}hr{margin-top:-3px!important;margin-bottom:-7px!important;border-top-style:solid!important;border-top-width:10px!important;border-image:url(/button.svg) 10 10 10 10 stretch stretch!important;height:0px!important}.text{line-height:30px!important;padding:0!important;margin:0!important}.group{padding-top:0!important}.group+.group{border-top-style:solid!important;border-top-width:10px!important;border-image:url(/button.svg) 10 10 10 10 stretch stretch!important;padding-top:23px!important;margin-top:-3px!important}table{margin:30px 0!important}#app .vp-doc tr{background-color:var(--vp-c-gray-2)}#app .vp-doc tr:nth-child(2n){background-color:var(--vp-c-bg-soft)}#app .vp-doc th,#app .vp-doc td{font-size:unset!important;font-weight:unset!important;color:unset!important;padding:0 8px!important;line-height:29px}.VPSidebarItem{padding-bottom:0!important}p:last-child{margin-bottom:0!important}.hero{width:60%;margin:auto}footer img{height:1lh;display:inline;border-radius:50%;margin:0 .25em;vertical-align:bottom}@property --anim-bg{syntax: ""; initial-value: transparent; inherits: false;}@keyframes vp-nolebase-highlight-targeted-heading-animation{0%{--anim-bg: transparent}10%,35%{--anim-bg: var(--vp-c-brand-soft)}99%{--anim-bg: transparent}to{--anim-bg: transparent}}.VPNolebaseHighlightTargetedHeadingAnimated{animation:vp-nolebase-highlight-targeted-heading-animation 1.5s ease-in-out;background:linear-gradient(0deg,var(--anim-bg) 55%,transparent 45%) repeat-x}.title-icon{line-height:30px}.excerpt{margin:8px 0!important;background:var(--docsearch-searchbox-background)}.excerpt-gradient-top{background:var(--docsearch-searchbox-background)!important;opacity:.5;clip-path:polygon(0% 0%,5% 100%,10% 0%,15% 100%,20% 0%,25% 100%,30% 0%,35% 100%,40% 0%,45% 100%,50% 0%,55% 100%,60% 0%,65% 100%,70% 0%,75% 100%,80% 0%,85% 100%,90% 0%,95% 100%,100% 0%);transform:translateY(-7px) rotate(180deg)}.excerpt-gradient-bottom{background:var(--docsearch-searchbox-background)!important;opacity:.5;clip-path:polygon(0% 0%,5% 100%,10% 0%,15% 100%,20% 0%,25% 100%,30% 0%,35% 100%,40% 0%,45% 100%,50% 0%,55% 100%,60% 0%,65% 100%,70% 0%,75% 100%,80% 0%,85% 100%,90% 0%,95% 100%,100% 0%);transform:translateY(7px)}.selected .excerpt-gradient-top,.selected .excerpt-gradient-bottom{opacity:1}.vp-doc details{border-bottom:solid 1px var(--vp-c-border)!important;margin-bottom:-1px!important}.vp-doc details a{margin-right:8px!important}.vp-doc summary{margin:29px 0 0!important;border-top:solid 1px var(--vp-c-border)!important;cursor:pointer!important}.background[data-v-1f4bd229]{position:fixed;top:0;left:0;right:0;bottom:0;z-index:-1;overflow:hidden}footer[data-v-1f4bd229]{padding:2em;z-index:26;position:relative;font-size:small;background:var(--vp-c-bg-elv)}.hero-wrapper[data-v-136be424]{height:16lh;position:relative}@media (max-width: 700px){.hero-wrapper[data-v-136be424]{height:12lh}}@media (max-width: 500px){.hero-wrapper[data-v-136be424]{height:10lh}}@media (max-width: 400px){.hero-wrapper[data-v-136be424]{height:9lh}}.hole[data-v-136be424]{height:80%;aspect-ratio:1;border:solid 10px lightgrey;border-radius:50%;background:#3b4252;position:absolute;left:33%;transform:translate(-50%);filter:url(#displacementFilter)}.hero[data-v-136be424]{height:80%;width:unset;margin:auto;position:absolute;right:50%;bottom:0;transform:translate(calc(50% + var(--x-offset)));animation:bob-136be424 5s ease-in-out infinite}svg[data-v-136be424]{display:none}@keyframes bob-136be424{0%{transform:translate(calc(50% + var(--x-offset)),-10%)}50%{transform:translate(calc(50% + var(--x-offset)),10%)}to{transform:translate(calc(50% + var(--x-offset)),-10%)}}.VPLocalSearchBox[data-v-639d7ab9]{position:fixed;z-index:100;top:0;right:0;bottom:0;left:0;display:flex}.backdrop[data-v-639d7ab9]{position:absolute;top:0;right:0;bottom:0;left:0;background:var(--vp-backdrop-bg-color);transition:opacity .5s}.shell[data-v-639d7ab9]{position:relative;padding:12px;margin:64px auto;display:flex;flex-direction:column;gap:16px;background:var(--vp-local-search-bg);width:min(100vw - 60px,900px);height:min-content;max-height:min(100vh - 128px,900px);border-radius:6px}@media (max-width: 767px){.shell[data-v-639d7ab9]{margin:0;width:100vw;height:100vh;max-height:none;border-radius:0}}.search-bar[data-v-639d7ab9]{border:1px solid var(--vp-c-divider);border-radius:4px;display:flex;align-items:center;padding:0 12px;cursor:text}@media (max-width: 767px){.search-bar[data-v-639d7ab9]{padding:0 8px}}.search-bar[data-v-639d7ab9]:focus-within{border-color:var(--vp-c-brand-1)}.local-search-icon[data-v-639d7ab9]{display:block;font-size:18px}.navigate-icon[data-v-639d7ab9]{display:block;font-size:14px}.search-icon[data-v-639d7ab9]{margin:8px}@media (max-width: 767px){.search-icon[data-v-639d7ab9]{display:none}}.search-input[data-v-639d7ab9]{padding:6px 12px;font-size:inherit;width:100%}@media (max-width: 767px){.search-input[data-v-639d7ab9]{padding:6px 4px}}.search-actions[data-v-639d7ab9]{display:flex;gap:4px}@media (any-pointer: coarse){.search-actions[data-v-639d7ab9]{gap:8px}}@media (min-width: 769px){.search-actions.before[data-v-639d7ab9]{display:none}}.search-actions button[data-v-639d7ab9]{padding:8px}.search-actions button[data-v-639d7ab9]:not([disabled]):hover,.toggle-layout-button.detailed-list[data-v-639d7ab9]{color:var(--vp-c-brand-1)}.search-actions button.clear-button[data-v-639d7ab9]:disabled{opacity:.37}.search-keyboard-shortcuts[data-v-639d7ab9]{font-size:.8rem;opacity:75%;display:flex;flex-wrap:wrap;gap:16px;line-height:14px}.search-keyboard-shortcuts span[data-v-639d7ab9]{display:flex;align-items:center;gap:4px}@media (max-width: 767px){.search-keyboard-shortcuts[data-v-639d7ab9]{display:none}}.search-keyboard-shortcuts kbd[data-v-639d7ab9]{background:#8080801a;border-radius:4px;padding:3px 6px;min-width:24px;display:inline-block;text-align:center;vertical-align:middle;border:1px solid rgba(128,128,128,.15);box-shadow:0 2px 2px #0000001a}.results[data-v-639d7ab9]{display:flex;flex-direction:column;gap:6px;overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain}.result[data-v-639d7ab9]{display:flex;align-items:center;gap:8px;border-radius:4px;transition:none;line-height:1rem;border:solid 2px var(--vp-local-search-result-border);outline:none}.result>div[data-v-639d7ab9]{margin:12px;width:100%;overflow:hidden}@media (max-width: 767px){.result>div[data-v-639d7ab9]{margin:8px}}.titles[data-v-639d7ab9]{display:flex;flex-wrap:wrap;gap:4px;position:relative;z-index:1001;padding:2px 0}.title[data-v-639d7ab9]{display:flex;align-items:center;gap:4px}.title.main[data-v-639d7ab9]{font-weight:500}.title-icon[data-v-639d7ab9]{opacity:.5;font-weight:500;color:var(--vp-c-brand-1)}.title svg[data-v-639d7ab9]{opacity:.5}.result.selected[data-v-639d7ab9]{--vp-local-search-result-bg: var(--vp-local-search-result-selected-bg);border-color:var(--vp-local-search-result-selected-border)}.excerpt-wrapper[data-v-639d7ab9]{position:relative}.excerpt[data-v-639d7ab9]{opacity:75%;pointer-events:none;max-height:140px;overflow:hidden;position:relative;opacity:.5;margin-top:4px}.result.selected .excerpt[data-v-639d7ab9]{opacity:1}.excerpt[data-v-639d7ab9] *{font-size:.8rem!important;line-height:130%!important}.titles[data-v-639d7ab9] mark,.excerpt[data-v-639d7ab9] mark{background-color:var(--vp-local-search-highlight-bg);color:var(--vp-local-search-highlight-text);border-radius:2px;padding:0 2px}.excerpt[data-v-639d7ab9] .vp-code-group .tabs{display:none}.excerpt[data-v-639d7ab9] .vp-code-group div[class*=language-]{border-radius:8px!important}.excerpt-gradient-bottom[data-v-639d7ab9]{position:absolute;bottom:-1px;left:0;width:100%;height:8px;background:linear-gradient(transparent,var(--vp-local-search-result-bg));z-index:1000}.excerpt-gradient-top[data-v-639d7ab9]{position:absolute;top:-1px;left:0;width:100%;height:8px;background:linear-gradient(var(--vp-local-search-result-bg),transparent);z-index:1000}.result.selected .titles[data-v-639d7ab9],.result.selected .title-icon[data-v-639d7ab9]{color:var(--vp-c-brand-1)!important}.no-results[data-v-639d7ab9]{font-size:.9rem;text-align:center;padding:12px}svg[data-v-639d7ab9]{flex:none}
              +:root{--vp-c-white: #ffffff;--vp-c-black: #000000;--vp-c-neutral: var(--vp-c-black);--vp-c-neutral-inverse: var(--vp-c-white)}.dark{--vp-c-neutral: var(--vp-c-white);--vp-c-neutral-inverse: var(--vp-c-black)}:root{--vp-c-gray-1: #dddde3;--vp-c-gray-2: #e4e4e9;--vp-c-gray-3: #ebebef;--vp-c-gray-soft: rgba(142, 150, 170, .14);--vp-c-indigo-1: #3451b2;--vp-c-indigo-2: #3a5ccc;--vp-c-indigo-3: #5672cd;--vp-c-indigo-soft: rgba(100, 108, 255, .14);--vp-c-purple-1: #6f42c1;--vp-c-purple-2: #7e4cc9;--vp-c-purple-3: #8e5cd9;--vp-c-purple-soft: rgba(159, 122, 234, .14);--vp-c-green-1: #18794e;--vp-c-green-2: #299764;--vp-c-green-3: #30a46c;--vp-c-green-soft: rgba(16, 185, 129, .14);--vp-c-yellow-1: #915930;--vp-c-yellow-2: #946300;--vp-c-yellow-3: #9f6a00;--vp-c-yellow-soft: rgba(234, 179, 8, .14);--vp-c-red-1: #b8272c;--vp-c-red-2: #d5393e;--vp-c-red-3: #e0575b;--vp-c-red-soft: rgba(244, 63, 94, .14);--vp-c-sponsor: #db2777}.dark{--vp-c-gray-1: #515c67;--vp-c-gray-2: #414853;--vp-c-gray-3: #32363f;--vp-c-gray-soft: rgba(101, 117, 133, .16);--vp-c-indigo-1: #a8b1ff;--vp-c-indigo-2: #5c73e7;--vp-c-indigo-3: #3e63dd;--vp-c-indigo-soft: rgba(100, 108, 255, .16);--vp-c-purple-1: #c8abfa;--vp-c-purple-2: #a879e6;--vp-c-purple-3: #8e5cd9;--vp-c-purple-soft: rgba(159, 122, 234, .16);--vp-c-green-1: #3dd68c;--vp-c-green-2: #30a46c;--vp-c-green-3: #298459;--vp-c-green-soft: rgba(16, 185, 129, .16);--vp-c-yellow-1: #f9b44e;--vp-c-yellow-2: #da8b17;--vp-c-yellow-3: #a46a0a;--vp-c-yellow-soft: rgba(234, 179, 8, .16);--vp-c-red-1: #f66f81;--vp-c-red-2: #f14158;--vp-c-red-3: #b62a3c;--vp-c-red-soft: rgba(244, 63, 94, .16)}:root{--vp-c-bg: #ffffff;--vp-c-bg-alt: #f6f6f7;--vp-c-bg-elv: #ffffff;--vp-c-bg-soft: #f6f6f7}.dark{--vp-c-bg: #1b1b1f;--vp-c-bg-alt: #161618;--vp-c-bg-elv: #202127;--vp-c-bg-soft: #202127}:root{--vp-c-border: #c2c2c4;--vp-c-divider: #e2e2e3;--vp-c-gutter: #e2e2e3}.dark{--vp-c-border: #3c3f44;--vp-c-divider: #2e2e32;--vp-c-gutter: #000000}:root{--vp-c-text-1: rgba(60, 60, 67);--vp-c-text-2: rgba(60, 60, 67, .78);--vp-c-text-3: rgba(60, 60, 67, .56)}.dark{--vp-c-text-1: rgba(255, 255, 245, .86);--vp-c-text-2: rgba(235, 235, 245, .6);--vp-c-text-3: rgba(235, 235, 245, .38)}:root{--vp-c-default-1: var(--vp-c-gray-1);--vp-c-default-2: var(--vp-c-gray-2);--vp-c-default-3: var(--vp-c-gray-3);--vp-c-default-soft: var(--vp-c-gray-soft);--vp-c-brand-1: var(--vp-c-indigo-1);--vp-c-brand-2: var(--vp-c-indigo-2);--vp-c-brand-3: var(--vp-c-indigo-3);--vp-c-brand-soft: var(--vp-c-indigo-soft);--vp-c-brand: var(--vp-c-brand-1);--vp-c-tip-1: var(--vp-c-brand-1);--vp-c-tip-2: var(--vp-c-brand-2);--vp-c-tip-3: var(--vp-c-brand-3);--vp-c-tip-soft: var(--vp-c-brand-soft);--vp-c-note-1: var(--vp-c-brand-1);--vp-c-note-2: var(--vp-c-brand-2);--vp-c-note-3: var(--vp-c-brand-3);--vp-c-note-soft: var(--vp-c-brand-soft);--vp-c-success-1: var(--vp-c-green-1);--vp-c-success-2: var(--vp-c-green-2);--vp-c-success-3: var(--vp-c-green-3);--vp-c-success-soft: var(--vp-c-green-soft);--vp-c-important-1: var(--vp-c-purple-1);--vp-c-important-2: var(--vp-c-purple-2);--vp-c-important-3: var(--vp-c-purple-3);--vp-c-important-soft: var(--vp-c-purple-soft);--vp-c-warning-1: var(--vp-c-yellow-1);--vp-c-warning-2: var(--vp-c-yellow-2);--vp-c-warning-3: var(--vp-c-yellow-3);--vp-c-warning-soft: var(--vp-c-yellow-soft);--vp-c-danger-1: var(--vp-c-red-1);--vp-c-danger-2: var(--vp-c-red-2);--vp-c-danger-3: var(--vp-c-red-3);--vp-c-danger-soft: var(--vp-c-red-soft);--vp-c-caution-1: var(--vp-c-red-1);--vp-c-caution-2: var(--vp-c-red-2);--vp-c-caution-3: var(--vp-c-red-3);--vp-c-caution-soft: var(--vp-c-red-soft)}:root{--vp-font-family-base: "Inter", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--vp-font-family-mono: ui-monospace, "Menlo", "Monaco", "Consolas", "Liberation Mono", "Courier New", monospace;font-optical-sizing:auto}:root:where(:lang(zh)){--vp-font-family-base: "Punctuation SC", "Inter", ui-sans-serif, system-ui, "PingFang SC", "Noto Sans CJK SC", "Noto Sans SC", "Heiti SC", "Microsoft YaHei", "DengXian", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"}:root{--vp-shadow-1: 0 1px 2px rgba(0, 0, 0, .04), 0 1px 2px rgba(0, 0, 0, .06);--vp-shadow-2: 0 3px 12px rgba(0, 0, 0, .07), 0 1px 4px rgba(0, 0, 0, .07);--vp-shadow-3: 0 12px 32px rgba(0, 0, 0, .1), 0 2px 6px rgba(0, 0, 0, .08);--vp-shadow-4: 0 14px 44px rgba(0, 0, 0, .12), 0 3px 9px rgba(0, 0, 0, .12);--vp-shadow-5: 0 18px 56px rgba(0, 0, 0, .16), 0 4px 12px rgba(0, 0, 0, .16)}:root{--vp-z-index-footer: 10;--vp-z-index-local-nav: 20;--vp-z-index-nav: 30;--vp-z-index-layout-top: 40;--vp-z-index-backdrop: 50;--vp-z-index-sidebar: 60}@media (min-width: 960px){:root{--vp-z-index-sidebar: 25}}:root{--vp-layout-max-width: 1440px}:root{--vp-header-anchor-symbol: "#"}:root{--vp-code-line-height: 1.7;--vp-code-font-size: .875em;--vp-code-color: var(--vp-c-brand-1);--vp-code-link-color: var(--vp-c-brand-1);--vp-code-link-hover-color: var(--vp-c-brand-2);--vp-code-bg: var(--vp-c-default-soft);--vp-code-block-color: var(--vp-c-text-2);--vp-code-block-bg: var(--vp-c-bg-alt);--vp-code-block-divider-color: var(--vp-c-gutter);--vp-code-lang-color: var(--vp-c-text-3);--vp-code-line-highlight-color: var(--vp-c-default-soft);--vp-code-line-number-color: var(--vp-c-text-3);--vp-code-line-diff-add-color: var(--vp-c-success-soft);--vp-code-line-diff-add-symbol-color: var(--vp-c-success-1);--vp-code-line-diff-remove-color: var(--vp-c-danger-soft);--vp-code-line-diff-remove-symbol-color: var(--vp-c-danger-1);--vp-code-line-warning-color: var(--vp-c-warning-soft);--vp-code-line-error-color: var(--vp-c-danger-soft);--vp-code-copy-code-border-color: var(--vp-c-divider);--vp-code-copy-code-bg: var(--vp-c-bg-soft);--vp-code-copy-code-hover-border-color: var(--vp-c-divider);--vp-code-copy-code-hover-bg: var(--vp-c-bg);--vp-code-copy-code-active-text: var(--vp-c-text-2);--vp-code-copy-copied-text-content: "Copied";--vp-code-tab-divider: var(--vp-code-block-divider-color);--vp-code-tab-text-color: var(--vp-c-text-2);--vp-code-tab-bg: var(--vp-code-block-bg);--vp-code-tab-hover-text-color: var(--vp-c-text-1);--vp-code-tab-active-text-color: var(--vp-c-text-1);--vp-code-tab-active-bar-color: var(--vp-c-brand-1)}:root{--vp-button-brand-border: transparent;--vp-button-brand-text: var(--vp-c-white);--vp-button-brand-bg: var(--vp-c-brand-3);--vp-button-brand-hover-border: transparent;--vp-button-brand-hover-text: var(--vp-c-white);--vp-button-brand-hover-bg: var(--vp-c-brand-2);--vp-button-brand-active-border: transparent;--vp-button-brand-active-text: var(--vp-c-white);--vp-button-brand-active-bg: var(--vp-c-brand-1);--vp-button-alt-border: transparent;--vp-button-alt-text: var(--vp-c-text-1);--vp-button-alt-bg: var(--vp-c-default-3);--vp-button-alt-hover-border: transparent;--vp-button-alt-hover-text: var(--vp-c-text-1);--vp-button-alt-hover-bg: var(--vp-c-default-2);--vp-button-alt-active-border: transparent;--vp-button-alt-active-text: var(--vp-c-text-1);--vp-button-alt-active-bg: var(--vp-c-default-1);--vp-button-sponsor-border: var(--vp-c-text-2);--vp-button-sponsor-text: var(--vp-c-text-2);--vp-button-sponsor-bg: transparent;--vp-button-sponsor-hover-border: var(--vp-c-sponsor);--vp-button-sponsor-hover-text: var(--vp-c-sponsor);--vp-button-sponsor-hover-bg: transparent;--vp-button-sponsor-active-border: var(--vp-c-sponsor);--vp-button-sponsor-active-text: var(--vp-c-sponsor);--vp-button-sponsor-active-bg: transparent}:root{--vp-custom-block-font-size: 14px;--vp-custom-block-code-font-size: 13px;--vp-custom-block-info-border: transparent;--vp-custom-block-info-text: var(--vp-c-text-1);--vp-custom-block-info-bg: var(--vp-c-default-soft);--vp-custom-block-info-code-bg: var(--vp-c-default-soft);--vp-custom-block-note-border: transparent;--vp-custom-block-note-text: var(--vp-c-text-1);--vp-custom-block-note-bg: var(--vp-c-default-soft);--vp-custom-block-note-code-bg: var(--vp-c-default-soft);--vp-custom-block-tip-border: transparent;--vp-custom-block-tip-text: var(--vp-c-text-1);--vp-custom-block-tip-bg: var(--vp-c-tip-soft);--vp-custom-block-tip-code-bg: var(--vp-c-tip-soft);--vp-custom-block-important-border: transparent;--vp-custom-block-important-text: var(--vp-c-text-1);--vp-custom-block-important-bg: var(--vp-c-important-soft);--vp-custom-block-important-code-bg: var(--vp-c-important-soft);--vp-custom-block-warning-border: transparent;--vp-custom-block-warning-text: var(--vp-c-text-1);--vp-custom-block-warning-bg: var(--vp-c-warning-soft);--vp-custom-block-warning-code-bg: var(--vp-c-warning-soft);--vp-custom-block-danger-border: transparent;--vp-custom-block-danger-text: var(--vp-c-text-1);--vp-custom-block-danger-bg: var(--vp-c-danger-soft);--vp-custom-block-danger-code-bg: var(--vp-c-danger-soft);--vp-custom-block-caution-border: transparent;--vp-custom-block-caution-text: var(--vp-c-text-1);--vp-custom-block-caution-bg: var(--vp-c-caution-soft);--vp-custom-block-caution-code-bg: var(--vp-c-caution-soft);--vp-custom-block-details-border: var(--vp-custom-block-info-border);--vp-custom-block-details-text: var(--vp-custom-block-info-text);--vp-custom-block-details-bg: var(--vp-custom-block-info-bg);--vp-custom-block-details-code-bg: var(--vp-custom-block-info-code-bg)}:root{--vp-input-border-color: var(--vp-c-border);--vp-input-bg-color: var(--vp-c-bg-alt);--vp-input-switch-bg-color: var(--vp-c-default-soft)}:root{--vp-nav-height: 64px;--vp-nav-bg-color: var(--vp-c-bg);--vp-nav-screen-bg-color: var(--vp-c-bg);--vp-nav-logo-height: 24px}.hide-nav{--vp-nav-height: 0px}.hide-nav .VPSidebar{--vp-nav-height: 22px}:root{--vp-local-nav-bg-color: var(--vp-c-bg)}:root{--vp-sidebar-width: 272px;--vp-sidebar-bg-color: var(--vp-c-bg-alt)}:root{--vp-backdrop-bg-color: rgba(0, 0, 0, .6)}:root{--vp-home-hero-name-color: var(--vp-c-brand-1);--vp-home-hero-name-background: transparent;--vp-home-hero-image-background-image: none;--vp-home-hero-image-filter: none}:root{--vp-badge-info-border: transparent;--vp-badge-info-text: var(--vp-c-text-2);--vp-badge-info-bg: var(--vp-c-default-soft);--vp-badge-tip-border: transparent;--vp-badge-tip-text: var(--vp-c-tip-1);--vp-badge-tip-bg: var(--vp-c-tip-soft);--vp-badge-warning-border: transparent;--vp-badge-warning-text: var(--vp-c-warning-1);--vp-badge-warning-bg: var(--vp-c-warning-soft);--vp-badge-danger-border: transparent;--vp-badge-danger-text: var(--vp-c-danger-1);--vp-badge-danger-bg: var(--vp-c-danger-soft)}:root{--vp-carbon-ads-text-color: var(--vp-c-text-1);--vp-carbon-ads-poweredby-color: var(--vp-c-text-2);--vp-carbon-ads-bg-color: var(--vp-c-bg-soft);--vp-carbon-ads-hover-text-color: var(--vp-c-brand-1);--vp-carbon-ads-hover-poweredby-color: var(--vp-c-text-1)}:root{--vp-local-search-bg: var(--vp-c-bg);--vp-local-search-result-bg: var(--vp-c-bg);--vp-local-search-result-border: var(--vp-c-divider);--vp-local-search-result-selected-bg: var(--vp-c-bg);--vp-local-search-result-selected-border: var(--vp-c-brand-1);--vp-local-search-highlight-bg: var(--vp-c-brand-1);--vp-local-search-highlight-text: var(--vp-c-neutral-inverse)}@media (prefers-reduced-motion: reduce){*,:before,:after{animation-delay:-1ms!important;animation-duration:1ms!important;animation-iteration-count:1!important;background-attachment:initial!important;scroll-behavior:auto!important;transition-duration:0s!important;transition-delay:0s!important}}*,:before,:after{box-sizing:border-box}html{line-height:1.4;font-size:16px;-webkit-text-size-adjust:100%}html.dark{color-scheme:dark}body{margin:0;width:100%;min-width:320px;min-height:100vh;line-height:24px;font-family:var(--vp-font-family-base);font-size:16px;font-weight:400;color:var(--vp-c-text-1);background-color:var(--vp-c-bg);font-synthesis:style;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}main{display:block}h1,h2,h3,h4,h5,h6{margin:0;line-height:24px;font-size:16px;font-weight:400}p{margin:0}strong,b{font-weight:600}a,area,button,[role=button],input,label,select,summary,textarea{touch-action:manipulation}a{color:inherit;text-decoration:inherit}ol,ul{list-style:none;margin:0;padding:0}blockquote{margin:0}pre,code,kbd,samp{font-family:var(--vp-font-family-mono)}img,svg,video,canvas,audio,iframe,embed,object{display:block}figure{margin:0}img,video{max-width:100%;height:auto}button,input,optgroup,select,textarea{border:0;padding:0;line-height:inherit;color:inherit}button{padding:0;font-family:inherit;background-color:transparent;background-image:none}button:enabled,[role=button]:enabled{cursor:pointer}button:focus,button:focus-visible{outline:1px dotted;outline:4px auto -webkit-focus-ring-color}button:focus:not(:focus-visible){outline:none!important}input:focus,textarea:focus,select:focus{outline:none}table{border-collapse:collapse}input{background-color:transparent}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:var(--vp-c-text-3)}input::-ms-input-placeholder,textarea::-ms-input-placeholder{color:var(--vp-c-text-3)}input::placeholder,textarea::placeholder{color:var(--vp-c-text-3)}input::-webkit-outer-spin-button,input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}input[type=number]{-moz-appearance:textfield}textarea{resize:vertical}select{-webkit-appearance:none}fieldset{margin:0;padding:0}h1,h2,h3,h4,h5,h6,li,p{overflow-wrap:break-word}vite-error-overlay{z-index:9999}mjx-container{display:inline-block;margin:auto 2px -2px}mjx-container>svg{display:inline-block;margin:auto}[class^=vpi-],[class*=" vpi-"],.vp-icon{width:1em;height:1em}[class^=vpi-].bg,[class*=" vpi-"].bg,.vp-icon.bg{background-size:100% 100%;background-color:transparent}[class^=vpi-]:not(.bg),[class*=" vpi-"]:not(.bg),.vp-icon:not(.bg){-webkit-mask:var(--icon) no-repeat;mask:var(--icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit}.vpi-align-left{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M21 6H3M15 12H3M17 18H3'/%3E%3C/svg%3E")}.vpi-arrow-right,.vpi-arrow-down,.vpi-arrow-left,.vpi-arrow-up{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M5 12h14M12 5l7 7-7 7'/%3E%3C/svg%3E")}.vpi-chevron-right,.vpi-chevron-down,.vpi-chevron-left,.vpi-chevron-up{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='m9 18 6-6-6-6'/%3E%3C/svg%3E")}.vpi-chevron-down,.vpi-arrow-down{transform:rotate(90deg)}.vpi-chevron-left,.vpi-arrow-left{transform:rotate(180deg)}.vpi-chevron-up,.vpi-arrow-up{transform:rotate(-90deg)}.vpi-square-pen{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7'/%3E%3Cpath d='M18.375 2.625a2.121 2.121 0 1 1 3 3L12 15l-4 1 1-4Z'/%3E%3C/svg%3E")}.vpi-plus{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M5 12h14M12 5v14'/%3E%3C/svg%3E")}.vpi-sun{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='4'/%3E%3Cpath d='M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41'/%3E%3C/svg%3E")}.vpi-moon{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z'/%3E%3C/svg%3E")}.vpi-more-horizontal{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='1'/%3E%3Ccircle cx='19' cy='12' r='1'/%3E%3Ccircle cx='5' cy='12' r='1'/%3E%3C/svg%3E")}.vpi-languages{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='m5 8 6 6M4 14l6-6 2-3M2 5h12M7 2h1M22 22l-5-10-5 10M14 18h6'/%3E%3C/svg%3E")}.vpi-heart{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z'/%3E%3C/svg%3E")}.vpi-search{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E")}.vpi-layout-list{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Crect width='7' height='7' x='3' y='3' rx='1'/%3E%3Crect width='7' height='7' x='3' y='14' rx='1'/%3E%3Cpath d='M14 4h7M14 9h7M14 15h7M14 20h7'/%3E%3C/svg%3E")}.vpi-delete{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M20 5H9l-7 7 7 7h11a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2ZM18 9l-6 6M12 9l6 6'/%3E%3C/svg%3E")}.vpi-corner-down-left{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='m9 10-5 5 5 5'/%3E%3Cpath d='M20 4v7a4 4 0 0 1-4 4H4'/%3E%3C/svg%3E")}:root{--vp-icon-copy: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3C/svg%3E");--vp-icon-copied: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3Cpath d='m9 14 2 2 4-4'/%3E%3C/svg%3E")}.vpi-social-discord{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418Z'/%3E%3C/svg%3E")}.vpi-social-facebook{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z'/%3E%3C/svg%3E")}.vpi-social-github{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E")}.vpi-social-instagram{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M7.03.084c-1.277.06-2.149.264-2.91.563a5.874 5.874 0 0 0-2.124 1.388 5.878 5.878 0 0 0-1.38 2.127C.321 4.926.12 5.8.064 7.076.008 8.354-.005 8.764.001 12.023c.007 3.259.021 3.667.083 4.947.061 1.277.264 2.149.563 2.911.308.789.72 1.457 1.388 2.123a5.872 5.872 0 0 0 2.129 1.38c.763.295 1.636.496 2.913.552 1.278.056 1.689.069 4.947.063 3.257-.007 3.668-.021 4.947-.082 1.28-.06 2.147-.265 2.91-.563a5.881 5.881 0 0 0 2.123-1.388 5.881 5.881 0 0 0 1.38-2.129c.295-.763.496-1.636.551-2.912.056-1.28.07-1.69.063-4.948-.006-3.258-.02-3.667-.081-4.947-.06-1.28-.264-2.148-.564-2.911a5.892 5.892 0 0 0-1.387-2.123 5.857 5.857 0 0 0-2.128-1.38C19.074.322 18.202.12 16.924.066 15.647.009 15.236-.006 11.977 0 8.718.008 8.31.021 7.03.084m.14 21.693c-1.17-.05-1.805-.245-2.228-.408a3.736 3.736 0 0 1-1.382-.895 3.695 3.695 0 0 1-.9-1.378c-.165-.423-.363-1.058-.417-2.228-.06-1.264-.072-1.644-.08-4.848-.006-3.204.006-3.583.061-4.848.05-1.169.246-1.805.408-2.228.216-.561.477-.96.895-1.382a3.705 3.705 0 0 1 1.379-.9c.423-.165 1.057-.361 2.227-.417 1.265-.06 1.644-.072 4.848-.08 3.203-.006 3.583.006 4.85.062 1.168.05 1.804.244 2.227.408.56.216.96.475 1.382.895.421.42.681.817.9 1.378.165.422.362 1.056.417 2.227.06 1.265.074 1.645.08 4.848.005 3.203-.006 3.583-.061 4.848-.051 1.17-.245 1.805-.408 2.23-.216.56-.477.96-.896 1.38a3.705 3.705 0 0 1-1.378.9c-.422.165-1.058.362-2.226.418-1.266.06-1.645.072-4.85.079-3.204.007-3.582-.006-4.848-.06m9.783-16.192a1.44 1.44 0 1 0 1.437-1.442 1.44 1.44 0 0 0-1.437 1.442M5.839 12.012a6.161 6.161 0 1 0 12.323-.024 6.162 6.162 0 0 0-12.323.024M8 12.008A4 4 0 1 1 12.008 16 4 4 0 0 1 8 12.008'/%3E%3C/svg%3E")}.vpi-social-linkedin{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.064 2.064 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z'/%3E%3C/svg%3E")}.vpi-social-mastodon{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z'/%3E%3C/svg%3E")}.vpi-social-npm{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M1.763 0C.786 0 0 .786 0 1.763v20.474C0 23.214.786 24 1.763 24h20.474c.977 0 1.763-.786 1.763-1.763V1.763C24 .786 23.214 0 22.237 0zM5.13 5.323l13.837.019-.009 13.836h-3.464l.01-10.382h-3.456L12.04 19.17H5.113z'/%3E%3C/svg%3E")}.vpi-social-slack{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zm1.271 0a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zm0 1.271a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zm10.122 2.521a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zm-1.268 0a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zm-2.523 10.122a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zm0-1.268a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z'/%3E%3C/svg%3E")}.vpi-social-twitter,.vpi-social-x{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z'/%3E%3C/svg%3E")}.vpi-social-youtube{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z'/%3E%3C/svg%3E")}.visually-hidden{position:absolute;width:1px;height:1px;white-space:nowrap;clip:rect(0 0 0 0);clip-path:inset(50%);overflow:hidden}.custom-block{border:1px solid transparent;border-radius:8px;padding:16px 16px 8px;line-height:24px;font-size:var(--vp-custom-block-font-size);color:var(--vp-c-text-2)}.custom-block.info{border-color:var(--vp-custom-block-info-border);color:var(--vp-custom-block-info-text);background-color:var(--vp-custom-block-info-bg)}.custom-block.info a,.custom-block.info code{color:var(--vp-c-brand-1)}.custom-block.info a:hover,.custom-block.info a:hover>code{color:var(--vp-c-brand-2)}.custom-block.info code{background-color:var(--vp-custom-block-info-code-bg)}.custom-block.note{border-color:var(--vp-custom-block-note-border);color:var(--vp-custom-block-note-text);background-color:var(--vp-custom-block-note-bg)}.custom-block.note a,.custom-block.note code{color:var(--vp-c-brand-1)}.custom-block.note a:hover,.custom-block.note a:hover>code{color:var(--vp-c-brand-2)}.custom-block.note code{background-color:var(--vp-custom-block-note-code-bg)}.custom-block.tip{border-color:var(--vp-custom-block-tip-border);color:var(--vp-custom-block-tip-text);background-color:var(--vp-custom-block-tip-bg)}.custom-block.tip a,.custom-block.tip code{color:var(--vp-c-tip-1)}.custom-block.tip a:hover,.custom-block.tip a:hover>code{color:var(--vp-c-tip-2)}.custom-block.tip code{background-color:var(--vp-custom-block-tip-code-bg)}.custom-block.important{border-color:var(--vp-custom-block-important-border);color:var(--vp-custom-block-important-text);background-color:var(--vp-custom-block-important-bg)}.custom-block.important a,.custom-block.important code{color:var(--vp-c-important-1)}.custom-block.important a:hover,.custom-block.important a:hover>code{color:var(--vp-c-important-2)}.custom-block.important code{background-color:var(--vp-custom-block-important-code-bg)}.custom-block.warning{border-color:var(--vp-custom-block-warning-border);color:var(--vp-custom-block-warning-text);background-color:var(--vp-custom-block-warning-bg)}.custom-block.warning a,.custom-block.warning code{color:var(--vp-c-warning-1)}.custom-block.warning a:hover,.custom-block.warning a:hover>code{color:var(--vp-c-warning-2)}.custom-block.warning code{background-color:var(--vp-custom-block-warning-code-bg)}.custom-block.danger{border-color:var(--vp-custom-block-danger-border);color:var(--vp-custom-block-danger-text);background-color:var(--vp-custom-block-danger-bg)}.custom-block.danger a,.custom-block.danger code{color:var(--vp-c-danger-1)}.custom-block.danger a:hover,.custom-block.danger a:hover>code{color:var(--vp-c-danger-2)}.custom-block.danger code{background-color:var(--vp-custom-block-danger-code-bg)}.custom-block.caution{border-color:var(--vp-custom-block-caution-border);color:var(--vp-custom-block-caution-text);background-color:var(--vp-custom-block-caution-bg)}.custom-block.caution a,.custom-block.caution code{color:var(--vp-c-caution-1)}.custom-block.caution a:hover,.custom-block.caution a:hover>code{color:var(--vp-c-caution-2)}.custom-block.caution code{background-color:var(--vp-custom-block-caution-code-bg)}.custom-block.details{border-color:var(--vp-custom-block-details-border);color:var(--vp-custom-block-details-text);background-color:var(--vp-custom-block-details-bg)}.custom-block.details a{color:var(--vp-c-brand-1)}.custom-block.details a:hover,.custom-block.details a:hover>code{color:var(--vp-c-brand-2)}.custom-block.details code{background-color:var(--vp-custom-block-details-code-bg)}.custom-block-title{font-weight:600}.custom-block p+p{margin:8px 0}.custom-block.details summary{margin:0 0 8px;font-weight:700;cursor:pointer;-webkit-user-select:none;user-select:none}.custom-block.details summary+p{margin:8px 0}.custom-block a{color:inherit;font-weight:600;text-decoration:underline;text-underline-offset:2px;transition:opacity .25s}.custom-block a:hover{opacity:.75}.custom-block code{font-size:var(--vp-custom-block-code-font-size)}.custom-block.custom-block th,.custom-block.custom-block blockquote>p{font-size:var(--vp-custom-block-font-size);color:inherit}.dark .vp-code span{color:var(--shiki-dark, inherit)}html:not(.dark) .vp-code span{color:var(--shiki-light, inherit)}.vp-code-group{margin-top:16px}.vp-code-group .tabs{position:relative;display:flex;margin-right:-24px;margin-left:-24px;padding:0 12px;background-color:var(--vp-code-tab-bg);overflow-x:auto;overflow-y:hidden;box-shadow:inset 0 -1px var(--vp-code-tab-divider)}@media (min-width: 640px){.vp-code-group .tabs{margin-right:0;margin-left:0;border-radius:8px 8px 0 0}}.vp-code-group .tabs input{position:fixed;opacity:0;pointer-events:none}.vp-code-group .tabs label{position:relative;display:inline-block;border-bottom:1px solid transparent;padding:0 12px;line-height:48px;font-size:14px;font-weight:500;color:var(--vp-code-tab-text-color);white-space:nowrap;cursor:pointer;transition:color .25s}.vp-code-group .tabs label:after{position:absolute;right:8px;bottom:-1px;left:8px;z-index:1;height:2px;border-radius:2px;content:"";background-color:transparent;transition:background-color .25s}.vp-code-group label:hover{color:var(--vp-code-tab-hover-text-color)}.vp-code-group input:checked+label{color:var(--vp-code-tab-active-text-color)}.vp-code-group input:checked+label:after{background-color:var(--vp-code-tab-active-bar-color)}.vp-code-group div[class*=language-],.vp-block{display:none;margin-top:0!important;border-top-left-radius:0!important;border-top-right-radius:0!important}.vp-code-group div[class*=language-].active,.vp-block.active{display:block}.vp-block{padding:20px 24px}.vp-doc h1,.vp-doc h2,.vp-doc h3,.vp-doc h4,.vp-doc h5,.vp-doc h6{position:relative;font-weight:600;outline:none}.vp-doc h1{letter-spacing:-.02em;line-height:40px;font-size:28px}.vp-doc h2{margin:48px 0 16px;border-top:1px solid var(--vp-c-divider);padding-top:24px;letter-spacing:-.02em;line-height:32px;font-size:24px}.vp-doc h3{margin:32px 0 0;letter-spacing:-.01em;line-height:28px;font-size:20px}.vp-doc .header-anchor{position:absolute;top:0;left:0;margin-left:-.87em;font-weight:500;-webkit-user-select:none;user-select:none;opacity:0;text-decoration:none;transition:color .25s,opacity .25s}.vp-doc .header-anchor:before{content:var(--vp-header-anchor-symbol)}.vp-doc h1:hover .header-anchor,.vp-doc h1 .header-anchor:focus,.vp-doc h2:hover .header-anchor,.vp-doc h2 .header-anchor:focus,.vp-doc h3:hover .header-anchor,.vp-doc h3 .header-anchor:focus,.vp-doc h4:hover .header-anchor,.vp-doc h4 .header-anchor:focus,.vp-doc h5:hover .header-anchor,.vp-doc h5 .header-anchor:focus,.vp-doc h6:hover .header-anchor,.vp-doc h6 .header-anchor:focus{opacity:1}@media (min-width: 768px){.vp-doc h1{letter-spacing:-.02em;line-height:40px;font-size:32px}}.vp-doc h2 .header-anchor{top:24px}.vp-doc p,.vp-doc summary{margin:16px 0}.vp-doc p{line-height:28px}.vp-doc blockquote{margin:16px 0;border-left:2px solid var(--vp-c-divider);padding-left:16px;transition:border-color .5s}.vp-doc blockquote>p{margin:0;font-size:16px;color:var(--vp-c-text-2);transition:color .5s}.vp-doc a{font-weight:500;color:var(--vp-c-brand-1);text-decoration:underline;text-underline-offset:2px;transition:color .25s,opacity .25s}.vp-doc a:hover{color:var(--vp-c-brand-2)}.vp-doc strong{font-weight:600}.vp-doc ul,.vp-doc ol{padding-left:1.25rem;margin:16px 0}.vp-doc ul{list-style:disc}.vp-doc ol{list-style:decimal}.vp-doc li+li{margin-top:8px}.vp-doc li>ol,.vp-doc li>ul{margin:8px 0 0}.vp-doc table{display:block;border-collapse:collapse;margin:20px 0;overflow-x:auto}.vp-doc tr{background-color:var(--vp-c-bg);border-top:1px solid var(--vp-c-divider);transition:background-color .5s}.vp-doc tr:nth-child(2n){background-color:var(--vp-c-bg-soft)}.vp-doc th,.vp-doc td{border:1px solid var(--vp-c-divider);padding:8px 16px}.vp-doc th{text-align:left;font-size:14px;font-weight:600;color:var(--vp-c-text-2);background-color:var(--vp-c-bg-soft)}.vp-doc td{font-size:14px}.vp-doc hr{margin:16px 0;border:none;border-top:1px solid var(--vp-c-divider)}.vp-doc .custom-block{margin:16px 0}.vp-doc .custom-block p{margin:8px 0;line-height:24px}.vp-doc .custom-block p:first-child{margin:0}.vp-doc .custom-block div[class*=language-]{margin:8px 0;border-radius:8px}.vp-doc .custom-block div[class*=language-] code{font-weight:400;background-color:transparent}.vp-doc .custom-block .vp-code-group .tabs{margin:0;border-radius:8px 8px 0 0}.vp-doc :not(pre,h1,h2,h3,h4,h5,h6)>code{font-size:var(--vp-code-font-size);color:var(--vp-code-color)}.vp-doc :not(pre)>code{border-radius:4px;padding:3px 6px;background-color:var(--vp-code-bg);transition:color .25s,background-color .5s}.vp-doc a>code{color:var(--vp-code-link-color)}.vp-doc a:hover>code{color:var(--vp-code-link-hover-color)}.vp-doc h1>code,.vp-doc h2>code,.vp-doc h3>code{font-size:.9em}.vp-doc div[class*=language-],.vp-block{position:relative;margin:16px -24px;background-color:var(--vp-code-block-bg);overflow-x:auto;transition:background-color .5s}@media (min-width: 640px){.vp-doc div[class*=language-],.vp-block{border-radius:8px;margin:16px 0}}@media (max-width: 639px){.vp-doc li div[class*=language-]{border-radius:8px 0 0 8px}}.vp-doc div[class*=language-]+div[class*=language-],.vp-doc div[class$=-api]+div[class*=language-],.vp-doc div[class*=language-]+div[class$=-api]>div[class*=language-]{margin-top:-8px}.vp-doc [class*=language-] pre,.vp-doc [class*=language-] code{direction:ltr;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}.vp-doc [class*=language-] pre{position:relative;z-index:1;margin:0;padding:20px 0;background:transparent;overflow-x:auto}.vp-doc [class*=language-] code{display:block;padding:0 24px;width:fit-content;min-width:100%;line-height:var(--vp-code-line-height);font-size:var(--vp-code-font-size);color:var(--vp-code-block-color);transition:color .5s}.vp-doc [class*=language-] code .highlighted{background-color:var(--vp-code-line-highlight-color);transition:background-color .5s;margin:0 -24px;padding:0 24px;width:calc(100% + 48px);display:inline-block}.vp-doc [class*=language-] code .highlighted.error{background-color:var(--vp-code-line-error-color)}.vp-doc [class*=language-] code .highlighted.warning{background-color:var(--vp-code-line-warning-color)}.vp-doc [class*=language-] code .diff{transition:background-color .5s;margin:0 -24px;padding:0 24px;width:calc(100% + 48px);display:inline-block}.vp-doc [class*=language-] code .diff:before{position:absolute;left:10px}.vp-doc [class*=language-] .has-focused-lines .line:not(.has-focus){filter:blur(.095rem);opacity:.4;transition:filter .35s,opacity .35s}.vp-doc [class*=language-] .has-focused-lines .line:not(.has-focus){opacity:.7;transition:filter .35s,opacity .35s}.vp-doc [class*=language-]:hover .has-focused-lines .line:not(.has-focus){filter:blur(0);opacity:1}.vp-doc [class*=language-] code .diff.remove{background-color:var(--vp-code-line-diff-remove-color);opacity:.7}.vp-doc [class*=language-] code .diff.remove:before{content:"-";color:var(--vp-code-line-diff-remove-symbol-color)}.vp-doc [class*=language-] code .diff.add{background-color:var(--vp-code-line-diff-add-color)}.vp-doc [class*=language-] code .diff.add:before{content:"+";color:var(--vp-code-line-diff-add-symbol-color)}.vp-doc div[class*=language-].line-numbers-mode{padding-left:32px}.vp-doc .line-numbers-wrapper{position:absolute;top:0;bottom:0;left:0;z-index:3;border-right:1px solid var(--vp-code-block-divider-color);padding-top:20px;width:32px;text-align:center;font-family:var(--vp-font-family-mono);line-height:var(--vp-code-line-height);font-size:var(--vp-code-font-size);color:var(--vp-code-line-number-color);transition:border-color .5s,color .5s}.vp-doc [class*=language-]>button.copy{direction:ltr;position:absolute;top:12px;right:12px;z-index:3;border:1px solid var(--vp-code-copy-code-border-color);border-radius:4px;width:40px;height:40px;background-color:var(--vp-code-copy-code-bg);opacity:0;cursor:pointer;background-image:var(--vp-icon-copy);background-position:50%;background-size:20px;background-repeat:no-repeat;transition:border-color .25s,background-color .25s,opacity .25s}.vp-doc [class*=language-]:hover>button.copy,.vp-doc [class*=language-]>button.copy:focus{opacity:1}.vp-doc [class*=language-]>button.copy:hover,.vp-doc [class*=language-]>button.copy.copied{border-color:var(--vp-code-copy-code-hover-border-color);background-color:var(--vp-code-copy-code-hover-bg)}.vp-doc [class*=language-]>button.copy.copied,.vp-doc [class*=language-]>button.copy:hover.copied{border-radius:0 4px 4px 0;background-color:var(--vp-code-copy-code-hover-bg);background-image:var(--vp-icon-copied)}.vp-doc [class*=language-]>button.copy.copied:before,.vp-doc [class*=language-]>button.copy:hover.copied:before{position:relative;top:-1px;transform:translate(calc(-100% - 1px));display:flex;justify-content:center;align-items:center;border:1px solid var(--vp-code-copy-code-hover-border-color);border-right:0;border-radius:4px 0 0 4px;padding:0 10px;width:fit-content;height:40px;text-align:center;font-size:12px;font-weight:500;color:var(--vp-code-copy-code-active-text);background-color:var(--vp-code-copy-code-hover-bg);white-space:nowrap;content:var(--vp-code-copy-copied-text-content)}.vp-doc [class*=language-]>span.lang{position:absolute;top:2px;right:8px;z-index:2;font-size:12px;font-weight:500;color:var(--vp-code-lang-color);transition:color .4s,opacity .4s}.vp-doc [class*=language-]:hover>button.copy+span.lang,.vp-doc [class*=language-]>button.copy:focus+span.lang{opacity:0}.vp-doc .VPTeamMembers{margin-top:24px}.vp-doc .VPTeamMembers.small.count-1 .container{margin:0!important;max-width:calc((100% - 24px)/2)!important}.vp-doc .VPTeamMembers.small.count-2 .container,.vp-doc .VPTeamMembers.small.count-3 .container{max-width:100%!important}.vp-doc .VPTeamMembers.medium.count-1 .container{margin:0!important;max-width:calc((100% - 24px)/2)!important}:is(.vp-external-link-icon,.vp-doc a[href*="://"],.vp-doc a[target=_blank]):not(.no-icon):after{display:inline-block;margin-top:-1px;margin-left:4px;width:11px;height:11px;background:currentColor;color:var(--vp-c-text-3);flex-shrink:0;--icon: url("data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' %3E%3Cpath d='M0 0h24v24H0V0z' fill='none' /%3E%3Cpath d='M9 5v2h6.59L4 18.59 5.41 20 17 8.41V15h2V5H9z' /%3E%3C/svg%3E");-webkit-mask-image:var(--icon);mask-image:var(--icon)}.vp-external-link-icon:after{content:""}.external-link-icon-enabled :is(.vp-doc a[href*="://"],.vp-doc a[target=_blank]):after{content:"";color:currentColor}.vp-sponsor{border-radius:16px;overflow:hidden}.vp-sponsor.aside{border-radius:12px}.vp-sponsor-section+.vp-sponsor-section{margin-top:4px}.vp-sponsor-tier{margin:0 0 4px!important;text-align:center;letter-spacing:1px!important;line-height:24px;width:100%;font-weight:600;color:var(--vp-c-text-2);background-color:var(--vp-c-bg-soft)}.vp-sponsor.normal .vp-sponsor-tier{padding:13px 0 11px;font-size:14px}.vp-sponsor.aside .vp-sponsor-tier{padding:9px 0 7px;font-size:12px}.vp-sponsor-grid+.vp-sponsor-tier{margin-top:4px}.vp-sponsor-grid{display:flex;flex-wrap:wrap;gap:4px}.vp-sponsor-grid.xmini .vp-sponsor-grid-link{height:64px}.vp-sponsor-grid.xmini .vp-sponsor-grid-image{max-width:64px;max-height:22px}.vp-sponsor-grid.mini .vp-sponsor-grid-link{height:72px}.vp-sponsor-grid.mini .vp-sponsor-grid-image{max-width:96px;max-height:24px}.vp-sponsor-grid.small .vp-sponsor-grid-link{height:96px}.vp-sponsor-grid.small .vp-sponsor-grid-image{max-width:96px;max-height:24px}.vp-sponsor-grid.medium .vp-sponsor-grid-link{height:112px}.vp-sponsor-grid.medium .vp-sponsor-grid-image{max-width:120px;max-height:36px}.vp-sponsor-grid.big .vp-sponsor-grid-link{height:184px}.vp-sponsor-grid.big .vp-sponsor-grid-image{max-width:192px;max-height:56px}.vp-sponsor-grid[data-vp-grid="2"] .vp-sponsor-grid-item{width:calc((100% - 4px)/2)}.vp-sponsor-grid[data-vp-grid="3"] .vp-sponsor-grid-item{width:calc((100% - 4px * 2) / 3)}.vp-sponsor-grid[data-vp-grid="4"] .vp-sponsor-grid-item{width:calc((100% - 12px)/4)}.vp-sponsor-grid[data-vp-grid="5"] .vp-sponsor-grid-item{width:calc((100% - 16px)/5)}.vp-sponsor-grid[data-vp-grid="6"] .vp-sponsor-grid-item{width:calc((100% - 4px * 5) / 6)}.vp-sponsor-grid-item{flex-shrink:0;width:100%;background-color:var(--vp-c-bg-soft);transition:background-color .25s}.vp-sponsor-grid-item:hover{background-color:var(--vp-c-default-soft)}.vp-sponsor-grid-item:hover .vp-sponsor-grid-image{filter:grayscale(0) invert(0)}.vp-sponsor-grid-item.empty:hover{background-color:var(--vp-c-bg-soft)}.dark .vp-sponsor-grid-item:hover{background-color:var(--vp-c-white)}.dark .vp-sponsor-grid-item.empty:hover{background-color:var(--vp-c-bg-soft)}.vp-sponsor-grid-link{display:flex}.vp-sponsor-grid-box{display:flex;justify-content:center;align-items:center;width:100%}.vp-sponsor-grid-image{max-width:100%;filter:grayscale(1);transition:filter .25s}.dark .vp-sponsor-grid-image{filter:grayscale(1) invert(1)}.VPBadge{display:inline-block;margin-left:2px;border:1px solid transparent;border-radius:12px;padding:0 10px;line-height:22px;font-size:12px;font-weight:500;transform:translateY(-2px)}.VPBadge.small{padding:0 6px;line-height:18px;font-size:10px;transform:translateY(-8px)}.VPDocFooter .VPBadge{display:none}.vp-doc h1>.VPBadge{margin-top:4px;vertical-align:top}.vp-doc h2>.VPBadge{margin-top:3px;padding:0 8px;vertical-align:top}.vp-doc h3>.VPBadge{vertical-align:middle}.vp-doc h4>.VPBadge,.vp-doc h5>.VPBadge,.vp-doc h6>.VPBadge{vertical-align:middle;line-height:18px}.VPBadge.info{border-color:var(--vp-badge-info-border);color:var(--vp-badge-info-text);background-color:var(--vp-badge-info-bg)}.VPBadge.tip{border-color:var(--vp-badge-tip-border);color:var(--vp-badge-tip-text);background-color:var(--vp-badge-tip-bg)}.VPBadge.warning{border-color:var(--vp-badge-warning-border);color:var(--vp-badge-warning-text);background-color:var(--vp-badge-warning-bg)}.VPBadge.danger{border-color:var(--vp-badge-danger-border);color:var(--vp-badge-danger-text);background-color:var(--vp-badge-danger-bg)}.VPBackdrop[data-v-c79a1216]{position:fixed;top:0;right:0;bottom:0;left:0;z-index:var(--vp-z-index-backdrop);background:var(--vp-backdrop-bg-color);transition:opacity .5s}.VPBackdrop.fade-enter-from[data-v-c79a1216],.VPBackdrop.fade-leave-to[data-v-c79a1216]{opacity:0}.VPBackdrop.fade-leave-active[data-v-c79a1216]{transition-duration:.25s}@media (min-width: 1280px){.VPBackdrop[data-v-c79a1216]{display:none}}.NotFound[data-v-d6be1790]{padding:64px 24px 96px;text-align:center}@media (min-width: 768px){.NotFound[data-v-d6be1790]{padding:96px 32px 168px}}.code[data-v-d6be1790]{line-height:64px;font-size:64px;font-weight:600}.title[data-v-d6be1790]{padding-top:12px;letter-spacing:2px;line-height:20px;font-size:20px;font-weight:700}.divider[data-v-d6be1790]{margin:24px auto 18px;width:64px;height:1px;background-color:var(--vp-c-divider)}.quote[data-v-d6be1790]{margin:0 auto;max-width:256px;font-size:14px;font-weight:500;color:var(--vp-c-text-2)}.action[data-v-d6be1790]{padding-top:20px}.link[data-v-d6be1790]{display:inline-block;border:1px solid var(--vp-c-brand-1);border-radius:16px;padding:3px 16px;font-size:14px;font-weight:500;color:var(--vp-c-brand-1);transition:border-color .25s,color .25s}.link[data-v-d6be1790]:hover{border-color:var(--vp-c-brand-2);color:var(--vp-c-brand-2)}.root[data-v-b933a997]{position:relative;z-index:1}.nested[data-v-b933a997]{padding-right:16px;padding-left:16px}.outline-link[data-v-b933a997]{display:block;line-height:32px;font-size:14px;font-weight:400;color:var(--vp-c-text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;transition:color .5s}.outline-link[data-v-b933a997]:hover,.outline-link.active[data-v-b933a997]{color:var(--vp-c-text-1);transition:color .25s}.outline-link.nested[data-v-b933a997]{padding-left:13px}.VPDocAsideOutline[data-v-a5bbad30]{display:none}.VPDocAsideOutline.has-outline[data-v-a5bbad30]{display:block}.content[data-v-a5bbad30]{position:relative;border-left:1px solid var(--vp-c-divider);padding-left:16px;font-size:13px;font-weight:500}.outline-marker[data-v-a5bbad30]{position:absolute;top:32px;left:-1px;z-index:0;opacity:0;width:2px;border-radius:2px;height:18px;background-color:var(--vp-c-brand-1);transition:top .25s cubic-bezier(0,1,.5,1),background-color .5s,opacity .25s}.outline-title[data-v-a5bbad30]{line-height:32px;font-size:14px;font-weight:600}.VPDocAside[data-v-3f215769]{display:flex;flex-direction:column;flex-grow:1}.spacer[data-v-3f215769]{flex-grow:1}.VPDocAside[data-v-3f215769] .spacer+.VPDocAsideSponsors,.VPDocAside[data-v-3f215769] .spacer+.VPDocAsideCarbonAds{margin-top:24px}.VPDocAside[data-v-3f215769] .VPDocAsideSponsors+.VPDocAsideCarbonAds{margin-top:16px}.VPLastUpdated[data-v-7e05ebdb]{line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-2)}@media (min-width: 640px){.VPLastUpdated[data-v-7e05ebdb]{line-height:32px;font-size:14px;font-weight:500}}.VPDocFooter[data-v-d4a0bba5]{margin-top:64px}.edit-info[data-v-d4a0bba5]{padding-bottom:18px}@media (min-width: 640px){.edit-info[data-v-d4a0bba5]{display:flex;justify-content:space-between;align-items:center;padding-bottom:14px}}.edit-link-button[data-v-d4a0bba5]{display:flex;align-items:center;border:0;line-height:32px;font-size:14px;font-weight:500;color:var(--vp-c-brand-1);transition:color .25s}.edit-link-button[data-v-d4a0bba5]:hover{color:var(--vp-c-brand-2)}.edit-link-icon[data-v-d4a0bba5]{margin-right:8px}.prev-next[data-v-d4a0bba5]{border-top:1px solid var(--vp-c-divider);padding-top:24px;display:grid;grid-row-gap:8px}@media (min-width: 640px){.prev-next[data-v-d4a0bba5]{grid-template-columns:repeat(2,1fr);grid-column-gap:16px}}.pager-link[data-v-d4a0bba5]{display:block;border:1px solid var(--vp-c-divider);border-radius:8px;padding:11px 16px 13px;width:100%;height:100%;transition:border-color .25s}.pager-link[data-v-d4a0bba5]:hover{border-color:var(--vp-c-brand-1)}.pager-link.next[data-v-d4a0bba5]{margin-left:auto;text-align:right}.desc[data-v-d4a0bba5]{display:block;line-height:20px;font-size:12px;font-weight:500;color:var(--vp-c-text-2)}.title[data-v-d4a0bba5]{display:block;line-height:20px;font-size:14px;font-weight:500;color:var(--vp-c-brand-1);transition:color .25s}.VPDoc[data-v-39a288b8]{padding:32px 24px 96px;width:100%}@media (min-width: 768px){.VPDoc[data-v-39a288b8]{padding:48px 32px 128px}}@media (min-width: 960px){.VPDoc[data-v-39a288b8]{padding:48px 32px 0}.VPDoc:not(.has-sidebar) .container[data-v-39a288b8]{display:flex;justify-content:center;max-width:992px}.VPDoc:not(.has-sidebar) .content[data-v-39a288b8]{max-width:752px}}@media (min-width: 1280px){.VPDoc .container[data-v-39a288b8]{display:flex;justify-content:center}.VPDoc .aside[data-v-39a288b8]{display:block}}@media (min-width: 1440px){.VPDoc:not(.has-sidebar) .content[data-v-39a288b8]{max-width:784px}.VPDoc:not(.has-sidebar) .container[data-v-39a288b8]{max-width:1104px}}.container[data-v-39a288b8]{margin:0 auto;width:100%}.aside[data-v-39a288b8]{position:relative;display:none;order:2;flex-grow:1;padding-left:32px;width:100%;max-width:256px}.left-aside[data-v-39a288b8]{order:1;padding-left:unset;padding-right:32px}.aside-container[data-v-39a288b8]{position:fixed;top:0;padding-top:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + var(--vp-doc-top-height, 0px) + 48px);width:224px;height:100vh;overflow-x:hidden;overflow-y:auto;scrollbar-width:none}.aside-container[data-v-39a288b8]::-webkit-scrollbar{display:none}.aside-curtain[data-v-39a288b8]{position:fixed;bottom:0;z-index:10;width:224px;height:32px;background:linear-gradient(transparent,var(--vp-c-bg) 70%)}.aside-content[data-v-39a288b8]{display:flex;flex-direction:column;min-height:calc(100vh - (var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 48px));padding-bottom:32px}.content[data-v-39a288b8]{position:relative;margin:0 auto;width:100%}@media (min-width: 960px){.content[data-v-39a288b8]{padding:0 32px 128px}}@media (min-width: 1280px){.content[data-v-39a288b8]{order:1;margin:0;min-width:640px}}.content-container[data-v-39a288b8]{margin:0 auto}.VPDoc.has-aside .content-container[data-v-39a288b8]{max-width:688px}.VPButton[data-v-cad61b99]{display:inline-block;border:1px solid transparent;text-align:center;font-weight:600;white-space:nowrap;transition:color .25s,border-color .25s,background-color .25s}.VPButton[data-v-cad61b99]:active{transition:color .1s,border-color .1s,background-color .1s}.VPButton.medium[data-v-cad61b99]{border-radius:20px;padding:0 20px;line-height:38px;font-size:14px}.VPButton.big[data-v-cad61b99]{border-radius:24px;padding:0 24px;line-height:46px;font-size:16px}.VPButton.brand[data-v-cad61b99]{border-color:var(--vp-button-brand-border);color:var(--vp-button-brand-text);background-color:var(--vp-button-brand-bg)}.VPButton.brand[data-v-cad61b99]:hover{border-color:var(--vp-button-brand-hover-border);color:var(--vp-button-brand-hover-text);background-color:var(--vp-button-brand-hover-bg)}.VPButton.brand[data-v-cad61b99]:active{border-color:var(--vp-button-brand-active-border);color:var(--vp-button-brand-active-text);background-color:var(--vp-button-brand-active-bg)}.VPButton.alt[data-v-cad61b99]{border-color:var(--vp-button-alt-border);color:var(--vp-button-alt-text);background-color:var(--vp-button-alt-bg)}.VPButton.alt[data-v-cad61b99]:hover{border-color:var(--vp-button-alt-hover-border);color:var(--vp-button-alt-hover-text);background-color:var(--vp-button-alt-hover-bg)}.VPButton.alt[data-v-cad61b99]:active{border-color:var(--vp-button-alt-active-border);color:var(--vp-button-alt-active-text);background-color:var(--vp-button-alt-active-bg)}.VPButton.sponsor[data-v-cad61b99]{border-color:var(--vp-button-sponsor-border);color:var(--vp-button-sponsor-text);background-color:var(--vp-button-sponsor-bg)}.VPButton.sponsor[data-v-cad61b99]:hover{border-color:var(--vp-button-sponsor-hover-border);color:var(--vp-button-sponsor-hover-text);background-color:var(--vp-button-sponsor-hover-bg)}.VPButton.sponsor[data-v-cad61b99]:active{border-color:var(--vp-button-sponsor-active-border);color:var(--vp-button-sponsor-active-text);background-color:var(--vp-button-sponsor-active-bg)}html:not(.dark) .VPImage.dark[data-v-8426fc1a]{display:none}.dark .VPImage.light[data-v-8426fc1a]{display:none}.VPHero[data-v-303bb580]{margin-top:calc((var(--vp-nav-height) + var(--vp-layout-top-height, 0px)) * -1);padding:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 48px) 24px 48px}@media (min-width: 640px){.VPHero[data-v-303bb580]{padding:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 80px) 48px 64px}}@media (min-width: 960px){.VPHero[data-v-303bb580]{padding:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 80px) 64px 64px}}.container[data-v-303bb580]{display:flex;flex-direction:column;margin:0 auto;max-width:1152px}@media (min-width: 960px){.container[data-v-303bb580]{flex-direction:row}}.main[data-v-303bb580]{position:relative;z-index:10;order:2;flex-grow:1;flex-shrink:0}.VPHero.has-image .container[data-v-303bb580]{text-align:center}@media (min-width: 960px){.VPHero.has-image .container[data-v-303bb580]{text-align:left}}@media (min-width: 960px){.main[data-v-303bb580]{order:1;width:calc((100% / 3) * 2)}.VPHero.has-image .main[data-v-303bb580]{max-width:592px}}.name[data-v-303bb580],.text[data-v-303bb580]{max-width:392px;letter-spacing:-.4px;line-height:40px;font-size:32px;font-weight:700;white-space:pre-wrap}.VPHero.has-image .name[data-v-303bb580],.VPHero.has-image .text[data-v-303bb580]{margin:0 auto}.name[data-v-303bb580]{color:var(--vp-home-hero-name-color)}.clip[data-v-303bb580]{background:var(--vp-home-hero-name-background);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:var(--vp-home-hero-name-color)}@media (min-width: 640px){.name[data-v-303bb580],.text[data-v-303bb580]{max-width:576px;line-height:56px;font-size:48px}}@media (min-width: 960px){.name[data-v-303bb580],.text[data-v-303bb580]{line-height:64px;font-size:56px}.VPHero.has-image .name[data-v-303bb580],.VPHero.has-image .text[data-v-303bb580]{margin:0}}.tagline[data-v-303bb580]{padding-top:8px;max-width:392px;line-height:28px;font-size:18px;font-weight:500;white-space:pre-wrap;color:var(--vp-c-text-2)}.VPHero.has-image .tagline[data-v-303bb580]{margin:0 auto}@media (min-width: 640px){.tagline[data-v-303bb580]{padding-top:12px;max-width:576px;line-height:32px;font-size:20px}}@media (min-width: 960px){.tagline[data-v-303bb580]{line-height:36px;font-size:24px}.VPHero.has-image .tagline[data-v-303bb580]{margin:0}}.actions[data-v-303bb580]{display:flex;flex-wrap:wrap;margin:-6px;padding-top:24px}.VPHero.has-image .actions[data-v-303bb580]{justify-content:center}@media (min-width: 640px){.actions[data-v-303bb580]{padding-top:32px}}@media (min-width: 960px){.VPHero.has-image .actions[data-v-303bb580]{justify-content:flex-start}}.action[data-v-303bb580]{flex-shrink:0;padding:6px}.image[data-v-303bb580]{order:1;margin:-76px -24px -48px}@media (min-width: 640px){.image[data-v-303bb580]{margin:-108px -24px -48px}}@media (min-width: 960px){.image[data-v-303bb580]{flex-grow:1;order:2;margin:0;min-height:100%}}.image-container[data-v-303bb580]{position:relative;margin:0 auto;width:320px;height:320px}@media (min-width: 640px){.image-container[data-v-303bb580]{width:392px;height:392px}}@media (min-width: 960px){.image-container[data-v-303bb580]{display:flex;justify-content:center;align-items:center;width:100%;height:100%;transform:translate(-32px,-32px)}}.image-bg[data-v-303bb580]{position:absolute;top:50%;left:50%;border-radius:50%;width:192px;height:192px;background-image:var(--vp-home-hero-image-background-image);filter:var(--vp-home-hero-image-filter);transform:translate(-50%,-50%)}@media (min-width: 640px){.image-bg[data-v-303bb580]{width:256px;height:256px}}@media (min-width: 960px){.image-bg[data-v-303bb580]{width:320px;height:320px}}[data-v-303bb580] .image-src{position:absolute;top:50%;left:50%;max-width:192px;max-height:192px;transform:translate(-50%,-50%)}@media (min-width: 640px){[data-v-303bb580] .image-src{max-width:256px;max-height:256px}}@media (min-width: 960px){[data-v-303bb580] .image-src{max-width:320px;max-height:320px}}.VPFeature[data-v-a3976bdc]{display:block;border:1px solid var(--vp-c-bg-soft);border-radius:12px;height:100%;background-color:var(--vp-c-bg-soft);transition:border-color .25s,background-color .25s}.VPFeature.link[data-v-a3976bdc]:hover{border-color:var(--vp-c-brand-1)}.box[data-v-a3976bdc]{display:flex;flex-direction:column;padding:24px;height:100%}.box[data-v-a3976bdc]>.VPImage{margin-bottom:20px}.icon[data-v-a3976bdc]{display:flex;justify-content:center;align-items:center;margin-bottom:20px;border-radius:6px;background-color:var(--vp-c-default-soft);width:48px;height:48px;font-size:24px;transition:background-color .25s}.title[data-v-a3976bdc]{line-height:24px;font-size:16px;font-weight:600}.details[data-v-a3976bdc]{flex-grow:1;padding-top:8px;line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-2)}.link-text[data-v-a3976bdc]{padding-top:8px}.link-text-value[data-v-a3976bdc]{display:flex;align-items:center;font-size:14px;font-weight:500;color:var(--vp-c-brand-1)}.link-text-icon[data-v-a3976bdc]{margin-left:6px}.VPFeatures[data-v-a6181336]{position:relative;padding:0 24px}@media (min-width: 640px){.VPFeatures[data-v-a6181336]{padding:0 48px}}@media (min-width: 960px){.VPFeatures[data-v-a6181336]{padding:0 64px}}.container[data-v-a6181336]{margin:0 auto;max-width:1152px}.items[data-v-a6181336]{display:flex;flex-wrap:wrap;margin:-8px}.item[data-v-a6181336]{padding:8px;width:100%}@media (min-width: 640px){.item.grid-2[data-v-a6181336],.item.grid-4[data-v-a6181336],.item.grid-6[data-v-a6181336]{width:50%}}@media (min-width: 768px){.item.grid-2[data-v-a6181336],.item.grid-4[data-v-a6181336]{width:50%}.item.grid-3[data-v-a6181336],.item.grid-6[data-v-a6181336]{width:calc(100% / 3)}}@media (min-width: 960px){.item.grid-4[data-v-a6181336]{width:25%}}.container[data-v-8e2d4988]{margin:auto;width:100%;max-width:1280px;padding:0 24px}@media (min-width: 640px){.container[data-v-8e2d4988]{padding:0 48px}}@media (min-width: 960px){.container[data-v-8e2d4988]{width:100%;padding:0 64px}}.vp-doc[data-v-8e2d4988] .VPHomeSponsors,.vp-doc[data-v-8e2d4988] .VPTeamPage{margin-left:var(--vp-offset, calc(50% - 50vw) );margin-right:var(--vp-offset, calc(50% - 50vw) )}.vp-doc[data-v-8e2d4988] .VPHomeSponsors h2{border-top:none;letter-spacing:normal}.vp-doc[data-v-8e2d4988] .VPHomeSponsors a,.vp-doc[data-v-8e2d4988] .VPTeamPage a{text-decoration:none}.VPHome[data-v-686f80a6]{margin-bottom:96px}@media (min-width: 768px){.VPHome[data-v-686f80a6]{margin-bottom:128px}}.VPContent[data-v-1428d186]{flex-grow:1;flex-shrink:0;margin:var(--vp-layout-top-height, 0px) auto 0;width:100%}.VPContent.is-home[data-v-1428d186]{width:100%;max-width:100%}.VPContent.has-sidebar[data-v-1428d186]{margin:0}@media (min-width: 960px){.VPContent[data-v-1428d186]{padding-top:var(--vp-nav-height)}.VPContent.has-sidebar[data-v-1428d186]{margin:var(--vp-layout-top-height, 0px) 0 0;padding-left:var(--vp-sidebar-width)}}@media (min-width: 1440px){.VPContent.has-sidebar[data-v-1428d186]{padding-right:calc((100vw - var(--vp-layout-max-width)) / 2);padding-left:calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width))}}.VPFooter[data-v-e315a0ad]{position:relative;z-index:var(--vp-z-index-footer);border-top:1px solid var(--vp-c-gutter);padding:32px 24px;background-color:var(--vp-c-bg)}.VPFooter.has-sidebar[data-v-e315a0ad]{display:none}.VPFooter[data-v-e315a0ad] a{text-decoration-line:underline;text-underline-offset:2px;transition:color .25s}.VPFooter[data-v-e315a0ad] a:hover{color:var(--vp-c-text-1)}@media (min-width: 768px){.VPFooter[data-v-e315a0ad]{padding:32px}}.container[data-v-e315a0ad]{margin:0 auto;max-width:var(--vp-layout-max-width);text-align:center}.message[data-v-e315a0ad],.copyright[data-v-e315a0ad]{line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-2)}.VPLocalNavOutlineDropdown[data-v-17a5e62e]{padding:12px 20px 11px}@media (min-width: 960px){.VPLocalNavOutlineDropdown[data-v-17a5e62e]{padding:12px 36px 11px}}.VPLocalNavOutlineDropdown button[data-v-17a5e62e]{display:block;font-size:12px;font-weight:500;line-height:24px;color:var(--vp-c-text-2);transition:color .5s;position:relative}.VPLocalNavOutlineDropdown button[data-v-17a5e62e]:hover{color:var(--vp-c-text-1);transition:color .25s}.VPLocalNavOutlineDropdown button.open[data-v-17a5e62e]{color:var(--vp-c-text-1)}.icon[data-v-17a5e62e]{display:inline-block;vertical-align:middle;margin-left:2px;font-size:14px;transform:rotate(0);transition:transform .25s}@media (min-width: 960px){.VPLocalNavOutlineDropdown button[data-v-17a5e62e]{font-size:14px}.icon[data-v-17a5e62e]{font-size:16px}}.open>.icon[data-v-17a5e62e]{transform:rotate(90deg)}.items[data-v-17a5e62e]{position:absolute;top:40px;right:16px;left:16px;display:grid;gap:1px;border:1px solid var(--vp-c-border);border-radius:8px;background-color:var(--vp-c-gutter);max-height:calc(var(--vp-vh, 100vh) - 86px);overflow:hidden auto;box-shadow:var(--vp-shadow-3)}@media (min-width: 960px){.items[data-v-17a5e62e]{right:auto;left:calc(var(--vp-sidebar-width) + 32px);width:320px}}.header[data-v-17a5e62e]{background-color:var(--vp-c-bg-soft)}.top-link[data-v-17a5e62e]{display:block;padding:0 16px;line-height:48px;font-size:14px;font-weight:500;color:var(--vp-c-brand-1)}.outline[data-v-17a5e62e]{padding:8px 0;background-color:var(--vp-c-bg-soft)}.flyout-enter-active[data-v-17a5e62e]{transition:all .2s ease-out}.flyout-leave-active[data-v-17a5e62e]{transition:all .15s ease-in}.flyout-enter-from[data-v-17a5e62e],.flyout-leave-to[data-v-17a5e62e]{opacity:0;transform:translateY(-16px)}.VPLocalNav[data-v-a6f0e41e]{position:sticky;top:0;left:0;z-index:var(--vp-z-index-local-nav);border-bottom:1px solid var(--vp-c-gutter);padding-top:var(--vp-layout-top-height, 0px);width:100%;background-color:var(--vp-local-nav-bg-color)}.VPLocalNav.fixed[data-v-a6f0e41e]{position:fixed}@media (min-width: 960px){.VPLocalNav[data-v-a6f0e41e]{top:var(--vp-nav-height)}.VPLocalNav.has-sidebar[data-v-a6f0e41e]{padding-left:var(--vp-sidebar-width)}.VPLocalNav.empty[data-v-a6f0e41e]{display:none}}@media (min-width: 1280px){.VPLocalNav[data-v-a6f0e41e]{display:none}}@media (min-width: 1440px){.VPLocalNav.has-sidebar[data-v-a6f0e41e]{padding-left:calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width))}}.container[data-v-a6f0e41e]{display:flex;justify-content:space-between;align-items:center}.menu[data-v-a6f0e41e]{display:flex;align-items:center;padding:12px 24px 11px;line-height:24px;font-size:12px;font-weight:500;color:var(--vp-c-text-2);transition:color .5s}.menu[data-v-a6f0e41e]:hover{color:var(--vp-c-text-1);transition:color .25s}@media (min-width: 768px){.menu[data-v-a6f0e41e]{padding:0 32px}}@media (min-width: 960px){.menu[data-v-a6f0e41e]{display:none}}.menu-icon[data-v-a6f0e41e]{margin-right:8px;font-size:14px}.VPOutlineDropdown[data-v-a6f0e41e]{padding:12px 24px 11px}@media (min-width: 768px){.VPOutlineDropdown[data-v-a6f0e41e]{padding:12px 32px 11px}}.VPSwitch[data-v-1d5665e3]{position:relative;border-radius:11px;display:block;width:40px;height:22px;flex-shrink:0;border:1px solid var(--vp-input-border-color);background-color:var(--vp-input-switch-bg-color);transition:border-color .25s!important}.VPSwitch[data-v-1d5665e3]:hover{border-color:var(--vp-c-brand-1)}.check[data-v-1d5665e3]{position:absolute;top:1px;left:1px;width:18px;height:18px;border-radius:50%;background-color:var(--vp-c-neutral-inverse);box-shadow:var(--vp-shadow-1);transition:transform .25s!important}.icon[data-v-1d5665e3]{position:relative;display:block;width:18px;height:18px;border-radius:50%;overflow:hidden}.icon[data-v-1d5665e3] [class^=vpi-]{position:absolute;top:3px;left:3px;width:12px;height:12px;color:var(--vp-c-text-2)}.dark .icon[data-v-1d5665e3] [class^=vpi-]{color:var(--vp-c-text-1);transition:opacity .25s!important}.sun[data-v-d1f28634]{opacity:1}.moon[data-v-d1f28634],.dark .sun[data-v-d1f28634]{opacity:0}.dark .moon[data-v-d1f28634]{opacity:1}.dark .VPSwitchAppearance[data-v-d1f28634] .check{transform:translate(18px)}.VPNavBarAppearance[data-v-e6aabb21]{display:none}@media (min-width: 1280px){.VPNavBarAppearance[data-v-e6aabb21]{display:flex;align-items:center}}.VPMenuGroup+.VPMenuLink[data-v-43f1e123]{margin:12px -12px 0;border-top:1px solid var(--vp-c-divider);padding:12px 12px 0}.link[data-v-43f1e123]{display:block;border-radius:6px;padding:0 12px;line-height:32px;font-size:14px;font-weight:500;color:var(--vp-c-text-1);white-space:nowrap;transition:background-color .25s,color .25s}.link[data-v-43f1e123]:hover{color:var(--vp-c-brand-1);background-color:var(--vp-c-default-soft)}.link.active[data-v-43f1e123]{color:var(--vp-c-brand-1)}.VPMenuGroup[data-v-69e747b5]{margin:12px -12px 0;border-top:1px solid var(--vp-c-divider);padding:12px 12px 0}.VPMenuGroup[data-v-69e747b5]:first-child{margin-top:0;border-top:0;padding-top:0}.VPMenuGroup+.VPMenuGroup[data-v-69e747b5]{margin-top:12px;border-top:1px solid var(--vp-c-divider)}.title[data-v-69e747b5]{padding:0 12px;line-height:32px;font-size:14px;font-weight:600;color:var(--vp-c-text-2);white-space:nowrap;transition:color .25s}.VPMenu[data-v-e7ea1737]{border-radius:12px;padding:12px;min-width:128px;border:1px solid var(--vp-c-divider);background-color:var(--vp-c-bg-elv);box-shadow:var(--vp-shadow-3);transition:background-color .5s;max-height:calc(100vh - var(--vp-nav-height));overflow-y:auto}.VPMenu[data-v-e7ea1737] .group{margin:0 -12px;padding:0 12px 12px}.VPMenu[data-v-e7ea1737] .group+.group{border-top:1px solid var(--vp-c-divider);padding:11px 12px 12px}.VPMenu[data-v-e7ea1737] .group:last-child{padding-bottom:0}.VPMenu[data-v-e7ea1737] .group+.item{border-top:1px solid var(--vp-c-divider);padding:11px 16px 0}.VPMenu[data-v-e7ea1737] .item{padding:0 16px;white-space:nowrap}.VPMenu[data-v-e7ea1737] .label{flex-grow:1;line-height:28px;font-size:12px;font-weight:500;color:var(--vp-c-text-2);transition:color .5s}.VPMenu[data-v-e7ea1737] .action{padding-left:24px}.VPFlyout[data-v-b6c34ac9]{position:relative}.VPFlyout[data-v-b6c34ac9]:hover{color:var(--vp-c-brand-1);transition:color .25s}.VPFlyout:hover .text[data-v-b6c34ac9]{color:var(--vp-c-text-2)}.VPFlyout:hover .icon[data-v-b6c34ac9]{fill:var(--vp-c-text-2)}.VPFlyout.active .text[data-v-b6c34ac9]{color:var(--vp-c-brand-1)}.VPFlyout.active:hover .text[data-v-b6c34ac9]{color:var(--vp-c-brand-2)}.VPFlyout:hover .menu[data-v-b6c34ac9],.button[aria-expanded=true]+.menu[data-v-b6c34ac9]{opacity:1;visibility:visible;transform:translateY(0)}.button[aria-expanded=false]+.menu[data-v-b6c34ac9]{opacity:0;visibility:hidden;transform:translateY(0)}.button[data-v-b6c34ac9]{display:flex;align-items:center;padding:0 12px;height:var(--vp-nav-height);color:var(--vp-c-text-1);transition:color .5s}.text[data-v-b6c34ac9]{display:flex;align-items:center;line-height:var(--vp-nav-height);font-size:14px;font-weight:500;color:var(--vp-c-text-1);transition:color .25s}.option-icon[data-v-b6c34ac9]{margin-right:0;font-size:16px}.text-icon[data-v-b6c34ac9]{margin-left:4px;font-size:14px}.icon[data-v-b6c34ac9]{font-size:20px;transition:fill .25s}.menu[data-v-b6c34ac9]{position:absolute;top:calc(var(--vp-nav-height) / 2 + 20px);right:0;opacity:0;visibility:hidden;transition:opacity .25s,visibility .25s,transform .25s}.VPSocialLink[data-v-eee4e7cb]{display:flex;justify-content:center;align-items:center;width:36px;height:36px;color:var(--vp-c-text-2);transition:color .5s}.VPSocialLink[data-v-eee4e7cb]:hover{color:var(--vp-c-text-1);transition:color .25s}.VPSocialLink[data-v-eee4e7cb]>svg,.VPSocialLink[data-v-eee4e7cb]>[class^=vpi-social-]{width:20px;height:20px;fill:currentColor}.VPSocialLinks[data-v-7bc22406]{display:flex;justify-content:center}.VPNavBarExtra[data-v-d0bd9dde]{display:none;margin-right:-12px}@media (min-width: 768px){.VPNavBarExtra[data-v-d0bd9dde]{display:block}}@media (min-width: 1280px){.VPNavBarExtra[data-v-d0bd9dde]{display:none}}.trans-title[data-v-d0bd9dde]{padding:0 24px 0 12px;line-height:32px;font-size:14px;font-weight:700;color:var(--vp-c-text-1)}.item.appearance[data-v-d0bd9dde],.item.social-links[data-v-d0bd9dde]{display:flex;align-items:center;padding:0 12px}.item.appearance[data-v-d0bd9dde]{min-width:176px}.appearance-action[data-v-d0bd9dde]{margin-right:-2px}.social-links-list[data-v-d0bd9dde]{margin:-4px -8px}.VPNavBarHamburger[data-v-e5dd9c1c]{display:flex;justify-content:center;align-items:center;width:48px;height:var(--vp-nav-height)}@media (min-width: 768px){.VPNavBarHamburger[data-v-e5dd9c1c]{display:none}}.container[data-v-e5dd9c1c]{position:relative;width:16px;height:14px;overflow:hidden}.VPNavBarHamburger:hover .top[data-v-e5dd9c1c]{top:0;left:0;transform:translate(4px)}.VPNavBarHamburger:hover .middle[data-v-e5dd9c1c]{top:6px;left:0;transform:translate(0)}.VPNavBarHamburger:hover .bottom[data-v-e5dd9c1c]{top:12px;left:0;transform:translate(8px)}.VPNavBarHamburger.active .top[data-v-e5dd9c1c]{top:6px;transform:translate(0) rotate(225deg)}.VPNavBarHamburger.active .middle[data-v-e5dd9c1c]{top:6px;transform:translate(16px)}.VPNavBarHamburger.active .bottom[data-v-e5dd9c1c]{top:6px;transform:translate(0) rotate(135deg)}.VPNavBarHamburger.active:hover .top[data-v-e5dd9c1c],.VPNavBarHamburger.active:hover .middle[data-v-e5dd9c1c],.VPNavBarHamburger.active:hover .bottom[data-v-e5dd9c1c]{background-color:var(--vp-c-text-2);transition:top .25s,background-color .25s,transform .25s}.top[data-v-e5dd9c1c],.middle[data-v-e5dd9c1c],.bottom[data-v-e5dd9c1c]{position:absolute;width:16px;height:2px;background-color:var(--vp-c-text-1);transition:top .25s,background-color .5s,transform .25s}.top[data-v-e5dd9c1c]{top:0;left:0;transform:translate(0)}.middle[data-v-e5dd9c1c]{top:6px;left:0;transform:translate(8px)}.bottom[data-v-e5dd9c1c]{top:12px;left:0;transform:translate(4px)}.VPNavBarMenuLink[data-v-9c663999]{display:flex;align-items:center;padding:0 12px;line-height:var(--vp-nav-height);font-size:14px;font-weight:500;color:var(--vp-c-text-1);transition:color .25s}.VPNavBarMenuLink.active[data-v-9c663999],.VPNavBarMenuLink[data-v-9c663999]:hover{color:var(--vp-c-brand-1)}.VPNavBarMenu[data-v-7f418b0f]{display:none}@media (min-width: 768px){.VPNavBarMenu[data-v-7f418b0f]{display:flex}}/*! @docsearch/css 3.6.0 | MIT License | © Algolia, Inc. and contributors | https://docsearch.algolia.com */:root{--docsearch-primary-color:#5468ff;--docsearch-text-color:#1c1e21;--docsearch-spacing:12px;--docsearch-icon-stroke-width:1.4;--docsearch-highlight-color:var(--docsearch-primary-color);--docsearch-muted-color:#969faf;--docsearch-container-background:rgba(101,108,133,.8);--docsearch-logo-color:#5468ff;--docsearch-modal-width:560px;--docsearch-modal-height:600px;--docsearch-modal-background:#f5f6f7;--docsearch-modal-shadow:inset 1px 1px 0 0 hsla(0,0%,100%,.5),0 3px 8px 0 #555a64;--docsearch-searchbox-height:56px;--docsearch-searchbox-background:#ebedf0;--docsearch-searchbox-focus-background:#fff;--docsearch-searchbox-shadow:inset 0 0 0 2px var(--docsearch-primary-color);--docsearch-hit-height:56px;--docsearch-hit-color:#444950;--docsearch-hit-active-color:#fff;--docsearch-hit-background:#fff;--docsearch-hit-shadow:0 1px 3px 0 #d4d9e1;--docsearch-key-gradient:linear-gradient(-225deg,#d5dbe4,#f8f8f8);--docsearch-key-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 2px 1px rgba(30,35,90,.4);--docsearch-key-pressed-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 1px 0 rgba(30,35,90,.4);--docsearch-footer-height:44px;--docsearch-footer-background:#fff;--docsearch-footer-shadow:0 -1px 0 0 #e0e3e8,0 -3px 6px 0 rgba(69,98,155,.12)}html[data-theme=dark]{--docsearch-text-color:#f5f6f7;--docsearch-container-background:rgba(9,10,17,.8);--docsearch-modal-background:#15172a;--docsearch-modal-shadow:inset 1px 1px 0 0 #2c2e40,0 3px 8px 0 #000309;--docsearch-searchbox-background:#090a11;--docsearch-searchbox-focus-background:#000;--docsearch-hit-color:#bec3c9;--docsearch-hit-shadow:none;--docsearch-hit-background:#090a11;--docsearch-key-gradient:linear-gradient(-26.5deg,#565872,#31355b);--docsearch-key-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 2px 2px 0 rgba(3,4,9,.3);--docsearch-key-pressed-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 1px 1px 0 rgba(3,4,9,.30196078431372547);--docsearch-footer-background:#1e2136;--docsearch-footer-shadow:inset 0 1px 0 0 rgba(73,76,106,.5),0 -4px 8px 0 rgba(0,0,0,.2);--docsearch-logo-color:#fff;--docsearch-muted-color:#7f8497}.DocSearch-Button{align-items:center;background:var(--docsearch-searchbox-background);border:0;border-radius:40px;color:var(--docsearch-muted-color);cursor:pointer;display:flex;font-weight:500;height:36px;justify-content:space-between;margin:0 0 0 16px;padding:0 8px;-webkit-user-select:none;user-select:none}.DocSearch-Button:active,.DocSearch-Button:focus,.DocSearch-Button:hover{background:var(--docsearch-searchbox-focus-background);box-shadow:var(--docsearch-searchbox-shadow);color:var(--docsearch-text-color);outline:none}.DocSearch-Button-Container{align-items:center;display:flex}.DocSearch-Search-Icon{stroke-width:1.6}.DocSearch-Button .DocSearch-Search-Icon{color:var(--docsearch-text-color)}.DocSearch-Button-Placeholder{font-size:1rem;padding:0 12px 0 6px}.DocSearch-Button-Keys{display:flex;min-width:calc(40px + .8em)}.DocSearch-Button-Key{align-items:center;background:var(--docsearch-key-gradient);border-radius:3px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);display:flex;height:18px;justify-content:center;margin-right:.4em;position:relative;padding:0 0 2px;border:0;top:-1px;width:20px}.DocSearch-Button-Key--pressed{transform:translate3d(0,1px,0);box-shadow:var(--docsearch-key-pressed-shadow)}@media (max-width:768px){.DocSearch-Button-Keys,.DocSearch-Button-Placeholder{display:none}}.DocSearch--active{overflow:hidden!important}.DocSearch-Container,.DocSearch-Container *{box-sizing:border-box}.DocSearch-Container{background-color:var(--docsearch-container-background);height:100vh;left:0;position:fixed;top:0;width:100vw;z-index:200}.DocSearch-Container a{text-decoration:none}.DocSearch-Link{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;font:inherit;margin:0;padding:0}.DocSearch-Modal{background:var(--docsearch-modal-background);border-radius:6px;box-shadow:var(--docsearch-modal-shadow);flex-direction:column;margin:60px auto auto;max-width:var(--docsearch-modal-width);position:relative}.DocSearch-SearchBar{display:flex;padding:var(--docsearch-spacing) var(--docsearch-spacing) 0}.DocSearch-Form{align-items:center;background:var(--docsearch-searchbox-focus-background);border-radius:4px;box-shadow:var(--docsearch-searchbox-shadow);display:flex;height:var(--docsearch-searchbox-height);margin:0;padding:0 var(--docsearch-spacing);position:relative;width:100%}.DocSearch-Input{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:0;color:var(--docsearch-text-color);flex:1;font:inherit;font-size:1.2em;height:100%;outline:none;padding:0 0 0 8px;width:80%}.DocSearch-Input::placeholder{color:var(--docsearch-muted-color);opacity:1}.DocSearch-Input::-webkit-search-cancel-button,.DocSearch-Input::-webkit-search-decoration,.DocSearch-Input::-webkit-search-results-button,.DocSearch-Input::-webkit-search-results-decoration{display:none}.DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset{margin:0;padding:0}.DocSearch-MagnifierLabel,.DocSearch-Reset{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}.DocSearch-Container--Stalled .DocSearch-MagnifierLabel,.DocSearch-LoadingIndicator{display:none}.DocSearch-Container--Stalled .DocSearch-LoadingIndicator{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Reset{animation:none;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;right:0;stroke-width:var(--docsearch-icon-stroke-width)}}.DocSearch-Reset{animation:fade-in .1s ease-in forwards;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;padding:2px;right:0;stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Reset[hidden]{display:none}.DocSearch-Reset:hover{color:var(--docsearch-highlight-color)}.DocSearch-LoadingIndicator svg,.DocSearch-MagnifierLabel svg{height:24px;width:24px}.DocSearch-Cancel{display:none}.DocSearch-Dropdown{max-height:calc(var(--docsearch-modal-height) - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height));min-height:var(--docsearch-spacing);overflow-y:auto;overflow-y:overlay;padding:0 var(--docsearch-spacing);scrollbar-color:var(--docsearch-muted-color) var(--docsearch-modal-background);scrollbar-width:thin}.DocSearch-Dropdown::-webkit-scrollbar{width:12px}.DocSearch-Dropdown::-webkit-scrollbar-track{background:transparent}.DocSearch-Dropdown::-webkit-scrollbar-thumb{background-color:var(--docsearch-muted-color);border:3px solid var(--docsearch-modal-background);border-radius:20px}.DocSearch-Dropdown ul{list-style:none;margin:0;padding:0}.DocSearch-Label{font-size:.75em;line-height:1.6em}.DocSearch-Help,.DocSearch-Label{color:var(--docsearch-muted-color)}.DocSearch-Help{font-size:.9em;margin:0;-webkit-user-select:none;user-select:none}.DocSearch-Title{font-size:1.2em}.DocSearch-Logo a{display:flex}.DocSearch-Logo svg{color:var(--docsearch-logo-color);margin-left:8px}.DocSearch-Hits:last-of-type{margin-bottom:24px}.DocSearch-Hits mark{background:none;color:var(--docsearch-highlight-color)}.DocSearch-HitsFooter{color:var(--docsearch-muted-color);display:flex;font-size:.85em;justify-content:center;margin-bottom:var(--docsearch-spacing);padding:var(--docsearch-spacing)}.DocSearch-HitsFooter a{border-bottom:1px solid;color:inherit}.DocSearch-Hit{border-radius:4px;display:flex;padding-bottom:4px;position:relative}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit--deleting{transition:none}}.DocSearch-Hit--deleting{opacity:0;transition:all .25s linear}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit--favoriting{transition:none}}.DocSearch-Hit--favoriting{transform:scale(0);transform-origin:top center;transition:all .25s linear;transition-delay:.25s}.DocSearch-Hit a{background:var(--docsearch-hit-background);border-radius:4px;box-shadow:var(--docsearch-hit-shadow);display:block;padding-left:var(--docsearch-spacing);width:100%}.DocSearch-Hit-source{background:var(--docsearch-modal-background);color:var(--docsearch-highlight-color);font-size:.85em;font-weight:600;line-height:32px;margin:0 -4px;padding:8px 4px 0;position:sticky;top:0;z-index:10}.DocSearch-Hit-Tree{color:var(--docsearch-muted-color);height:var(--docsearch-hit-height);opacity:.5;stroke-width:var(--docsearch-icon-stroke-width);width:24px}.DocSearch-Hit[aria-selected=true] a{background-color:var(--docsearch-highlight-color)}.DocSearch-Hit[aria-selected=true] mark{text-decoration:underline}.DocSearch-Hit-Container{align-items:center;color:var(--docsearch-hit-color);display:flex;flex-direction:row;height:var(--docsearch-hit-height);padding:0 var(--docsearch-spacing) 0 0}.DocSearch-Hit-icon{height:20px;width:20px}.DocSearch-Hit-action,.DocSearch-Hit-icon{color:var(--docsearch-muted-color);stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Hit-action{align-items:center;display:flex;height:22px;width:22px}.DocSearch-Hit-action svg{display:block;height:18px;width:18px}.DocSearch-Hit-action+.DocSearch-Hit-action{margin-left:6px}.DocSearch-Hit-action-button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:inherit;cursor:pointer;padding:2px}svg.DocSearch-Hit-Select-Icon{display:none}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Select-Icon{display:block}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:background-color .1s ease-in}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{transition:none}}.DocSearch-Hit-action-button:focus path,.DocSearch-Hit-action-button:hover path{fill:#fff}.DocSearch-Hit-content-wrapper{display:flex;flex:1 1 auto;flex-direction:column;font-weight:500;justify-content:center;line-height:1.2em;margin:0 8px;overflow-x:hidden;position:relative;text-overflow:ellipsis;white-space:nowrap;width:80%}.DocSearch-Hit-title{font-size:.9em}.DocSearch-Hit-path{color:var(--docsearch-muted-color);font-size:.75em}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-action,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-icon,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-path,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-text,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-title,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Tree,.DocSearch-Hit[aria-selected=true] mark{color:var(--docsearch-hit-active-color)!important}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:none}}.DocSearch-ErrorScreen,.DocSearch-NoResults,.DocSearch-StartScreen{font-size:.9em;margin:0 auto;padding:36px 0;text-align:center;width:80%}.DocSearch-Screen-Icon{color:var(--docsearch-muted-color);padding-bottom:12px}.DocSearch-NoResults-Prefill-List{display:inline-block;padding-bottom:24px;text-align:left}.DocSearch-NoResults-Prefill-List ul{display:inline-block;padding:8px 0 0}.DocSearch-NoResults-Prefill-List li{list-style-position:inside;list-style-type:"» "}.DocSearch-Prefill{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:1em;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;font-size:1em;font-weight:700;padding:0}.DocSearch-Prefill:focus,.DocSearch-Prefill:hover{outline:none;text-decoration:underline}.DocSearch-Footer{align-items:center;background:var(--docsearch-footer-background);border-radius:0 0 8px 8px;box-shadow:var(--docsearch-footer-shadow);display:flex;flex-direction:row-reverse;flex-shrink:0;height:var(--docsearch-footer-height);justify-content:space-between;padding:0 var(--docsearch-spacing);position:relative;-webkit-user-select:none;user-select:none;width:100%;z-index:300}.DocSearch-Commands{color:var(--docsearch-muted-color);display:flex;list-style:none;margin:0;padding:0}.DocSearch-Commands li{align-items:center;display:flex}.DocSearch-Commands li:not(:last-of-type){margin-right:.8em}.DocSearch-Commands-Key{align-items:center;background:var(--docsearch-key-gradient);border-radius:2px;box-shadow:var(--docsearch-key-shadow);display:flex;height:18px;justify-content:center;margin-right:.4em;padding:0 0 1px;color:var(--docsearch-muted-color);border:0;width:20px}.DocSearch-VisuallyHiddenForAccessibility{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}@media (max-width:768px){:root{--docsearch-spacing:10px;--docsearch-footer-height:40px}.DocSearch-Dropdown{height:100%}.DocSearch-Container{height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh, 1vh)*100);position:absolute}.DocSearch-Footer{border-radius:0;bottom:0;position:absolute}.DocSearch-Hit-content-wrapper{display:flex;position:relative;width:80%}.DocSearch-Modal{border-radius:0;box-shadow:none;height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh, 1vh)*100);margin:0;max-width:100%;width:100%}.DocSearch-Dropdown{max-height:calc(var(--docsearch-vh, 1vh)*100 - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height))}.DocSearch-Cancel{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;flex:none;font:inherit;font-size:1em;font-weight:500;margin-left:var(--docsearch-spacing);outline:none;overflow:hidden;padding:0;-webkit-user-select:none;user-select:none;white-space:nowrap}.DocSearch-Commands,.DocSearch-Hit-Tree{display:none}}@keyframes fade-in{0%{opacity:0}to{opacity:1}}[class*=DocSearch]{--docsearch-primary-color: var(--vp-c-brand-1);--docsearch-highlight-color: var(--docsearch-primary-color);--docsearch-text-color: var(--vp-c-text-1);--docsearch-muted-color: var(--vp-c-text-2);--docsearch-searchbox-shadow: none;--docsearch-searchbox-background: transparent;--docsearch-searchbox-focus-background: transparent;--docsearch-key-gradient: transparent;--docsearch-key-shadow: none;--docsearch-modal-background: var(--vp-c-bg-soft);--docsearch-footer-background: var(--vp-c-bg)}.dark [class*=DocSearch]{--docsearch-modal-shadow: none;--docsearch-footer-shadow: none;--docsearch-logo-color: var(--vp-c-text-2);--docsearch-hit-background: var(--vp-c-default-soft);--docsearch-hit-color: var(--vp-c-text-2);--docsearch-hit-shadow: none}.DocSearch-Button{display:flex;justify-content:center;align-items:center;margin:0;padding:0;width:48px;height:55px;background:transparent;transition:border-color .25s}.DocSearch-Button:hover{background:transparent}.DocSearch-Button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}.DocSearch-Button-Key--pressed{transform:none;box-shadow:none}.DocSearch-Button:focus:not(:focus-visible){outline:none!important}@media (min-width: 768px){.DocSearch-Button{justify-content:flex-start;border:1px solid transparent;border-radius:8px;padding:0 10px 0 12px;width:100%;height:40px;background-color:var(--vp-c-bg-alt)}.DocSearch-Button:hover{border-color:var(--vp-c-brand-1);background:var(--vp-c-bg-alt)}}.DocSearch-Button .DocSearch-Button-Container{display:flex;align-items:center}.DocSearch-Button .DocSearch-Search-Icon{position:relative;width:16px;height:16px;color:var(--vp-c-text-1);fill:currentColor;transition:color .5s}.DocSearch-Button:hover .DocSearch-Search-Icon{color:var(--vp-c-text-1)}@media (min-width: 768px){.DocSearch-Button .DocSearch-Search-Icon{top:1px;margin-right:8px;width:14px;height:14px;color:var(--vp-c-text-2)}}.DocSearch-Button .DocSearch-Button-Placeholder{display:none;margin-top:2px;padding:0 16px 0 0;font-size:13px;font-weight:500;color:var(--vp-c-text-2);transition:color .5s}.DocSearch-Button:hover .DocSearch-Button-Placeholder{color:var(--vp-c-text-1)}@media (min-width: 768px){.DocSearch-Button .DocSearch-Button-Placeholder{display:inline-block}}.DocSearch-Button .DocSearch-Button-Keys{direction:ltr;display:none;min-width:auto}@media (min-width: 768px){.DocSearch-Button .DocSearch-Button-Keys{display:flex;align-items:center}}.DocSearch-Button .DocSearch-Button-Key{display:block;margin:2px 0 0;border:1px solid var(--vp-c-divider);border-right:none;border-radius:4px 0 0 4px;padding-left:6px;min-width:0;width:auto;height:22px;line-height:22px;font-family:var(--vp-font-family-base);font-size:12px;font-weight:500;transition:color .5s,border-color .5s}.DocSearch-Button .DocSearch-Button-Key+.DocSearch-Button-Key{border-right:1px solid var(--vp-c-divider);border-left:none;border-radius:0 4px 4px 0;padding-left:2px;padding-right:6px}.DocSearch-Button .DocSearch-Button-Key:first-child{font-size:0!important}.DocSearch-Button .DocSearch-Button-Key:first-child:after{content:"Ctrl";font-size:12px;letter-spacing:normal;color:var(--docsearch-muted-color)}.mac .DocSearch-Button .DocSearch-Button-Key:first-child:after{content:"⌘"}.DocSearch-Button .DocSearch-Button-Key:first-child>*{display:none}.DocSearch-Search-Icon{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' stroke-width='1.6' viewBox='0 0 20 20'%3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' d='m14.386 14.386 4.088 4.088-4.088-4.088A7.533 7.533 0 1 1 3.733 3.733a7.533 7.533 0 0 1 10.653 10.653z'/%3E%3C/svg%3E")}.VPNavBarSearch{display:flex;align-items:center}@media (min-width: 768px){.VPNavBarSearch{flex-grow:1;padding-left:24px}}@media (min-width: 960px){.VPNavBarSearch{padding-left:32px}}.dark .DocSearch-Footer{border-top:1px solid var(--vp-c-divider)}.DocSearch-Form{border:1px solid var(--vp-c-brand-1);background-color:var(--vp-c-white)}.dark .DocSearch-Form{background-color:var(--vp-c-default-soft)}.DocSearch-Screen-Icon>svg{margin:auto}.VPNavBarSocialLinks[data-v-0394ad82]{display:none}@media (min-width: 1280px){.VPNavBarSocialLinks[data-v-0394ad82]{display:flex;align-items:center}}.title[data-v-ab179fa1]{display:flex;align-items:center;border-bottom:1px solid transparent;width:100%;height:var(--vp-nav-height);font-size:16px;font-weight:600;color:var(--vp-c-text-1);transition:opacity .25s}@media (min-width: 960px){.title[data-v-ab179fa1]{flex-shrink:0}.VPNavBarTitle.has-sidebar .title[data-v-ab179fa1]{border-bottom-color:var(--vp-c-divider)}}[data-v-ab179fa1] .logo{margin-right:8px;height:var(--vp-nav-logo-height)}.VPNavBarTranslations[data-v-88af2de4]{display:none}@media (min-width: 1280px){.VPNavBarTranslations[data-v-88af2de4]{display:flex;align-items:center}}.title[data-v-88af2de4]{padding:0 24px 0 12px;line-height:32px;font-size:14px;font-weight:700;color:var(--vp-c-text-1)}.VPNavBar[data-v-ccf7ddec]{position:relative;height:var(--vp-nav-height);pointer-events:none;white-space:nowrap;transition:background-color .5s}.VPNavBar[data-v-ccf7ddec]:not(.home){background-color:var(--vp-nav-bg-color)}@media (min-width: 960px){.VPNavBar[data-v-ccf7ddec]:not(.home){background-color:transparent}.VPNavBar[data-v-ccf7ddec]:not(.has-sidebar):not(.home.top){background-color:var(--vp-nav-bg-color)}}.wrapper[data-v-ccf7ddec]{padding:0 8px 0 24px}@media (min-width: 768px){.wrapper[data-v-ccf7ddec]{padding:0 32px}}@media (min-width: 960px){.VPNavBar.has-sidebar .wrapper[data-v-ccf7ddec]{padding:0}}.container[data-v-ccf7ddec]{display:flex;justify-content:space-between;margin:0 auto;max-width:calc(var(--vp-layout-max-width) - 64px);height:var(--vp-nav-height);pointer-events:none}.container>.title[data-v-ccf7ddec],.container>.content[data-v-ccf7ddec]{pointer-events:none}.container[data-v-ccf7ddec] *{pointer-events:auto}@media (min-width: 960px){.VPNavBar.has-sidebar .container[data-v-ccf7ddec]{max-width:100%}}.title[data-v-ccf7ddec]{flex-shrink:0;height:calc(var(--vp-nav-height) - 1px);transition:background-color .5s}@media (min-width: 960px){.VPNavBar.has-sidebar .title[data-v-ccf7ddec]{position:absolute;top:0;left:0;z-index:2;padding:0 32px;width:var(--vp-sidebar-width);height:var(--vp-nav-height);background-color:transparent}}@media (min-width: 1440px){.VPNavBar.has-sidebar .title[data-v-ccf7ddec]{padding-left:max(32px,calc((100% - (var(--vp-layout-max-width) - 64px)) / 2));width:calc((100% - (var(--vp-layout-max-width) - 64px)) / 2 + var(--vp-sidebar-width) - 32px)}}.content[data-v-ccf7ddec]{flex-grow:1}@media (min-width: 960px){.VPNavBar.has-sidebar .content[data-v-ccf7ddec]{position:relative;z-index:1;padding-right:32px;padding-left:var(--vp-sidebar-width)}}@media (min-width: 1440px){.VPNavBar.has-sidebar .content[data-v-ccf7ddec]{padding-right:calc((100vw - var(--vp-layout-max-width)) / 2 + 32px);padding-left:calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width))}}.content-body[data-v-ccf7ddec]{display:flex;justify-content:flex-end;align-items:center;height:var(--vp-nav-height);transition:background-color .5s}@media (min-width: 960px){.VPNavBar:not(.home.top) .content-body[data-v-ccf7ddec]{position:relative;background-color:var(--vp-nav-bg-color)}.VPNavBar:not(.has-sidebar):not(.home.top) .content-body[data-v-ccf7ddec]{background-color:transparent}}@media (max-width: 767px){.content-body[data-v-ccf7ddec]{column-gap:.5rem}}.menu+.translations[data-v-ccf7ddec]:before,.menu+.appearance[data-v-ccf7ddec]:before,.menu+.social-links[data-v-ccf7ddec]:before,.translations+.appearance[data-v-ccf7ddec]:before,.appearance+.social-links[data-v-ccf7ddec]:before{margin-right:8px;margin-left:8px;width:1px;height:24px;background-color:var(--vp-c-divider);content:""}.menu+.appearance[data-v-ccf7ddec]:before,.translations+.appearance[data-v-ccf7ddec]:before{margin-right:16px}.appearance+.social-links[data-v-ccf7ddec]:before{margin-left:16px}.social-links[data-v-ccf7ddec]{margin-right:-8px}.divider[data-v-ccf7ddec]{width:100%;height:1px}@media (min-width: 960px){.VPNavBar.has-sidebar .divider[data-v-ccf7ddec]{padding-left:var(--vp-sidebar-width)}}@media (min-width: 1440px){.VPNavBar.has-sidebar .divider[data-v-ccf7ddec]{padding-left:calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width))}}.divider-line[data-v-ccf7ddec]{width:100%;height:1px;transition:background-color .5s}.VPNavBar:not(.home) .divider-line[data-v-ccf7ddec]{background-color:var(--vp-c-gutter)}@media (min-width: 960px){.VPNavBar:not(.home.top) .divider-line[data-v-ccf7ddec]{background-color:var(--vp-c-gutter)}.VPNavBar:not(.has-sidebar):not(.home.top) .divider[data-v-ccf7ddec]{background-color:var(--vp-c-gutter)}}.VPNavScreenAppearance[data-v-2d7af913]{display:flex;justify-content:space-between;align-items:center;border-radius:8px;padding:12px 14px 12px 16px;background-color:var(--vp-c-bg-soft)}.text[data-v-2d7af913]{line-height:24px;font-size:12px;font-weight:500;color:var(--vp-c-text-2)}.VPNavScreenMenuLink[data-v-7f31e1f6]{display:block;border-bottom:1px solid var(--vp-c-divider);padding:12px 0 11px;line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-1);transition:border-color .25s,color .25s}.VPNavScreenMenuLink[data-v-7f31e1f6]:hover{color:var(--vp-c-brand-1)}.VPNavScreenMenuGroupLink[data-v-19976ae1]{display:block;margin-left:12px;line-height:32px;font-size:14px;font-weight:400;color:var(--vp-c-text-1);transition:color .25s}.VPNavScreenMenuGroupLink[data-v-19976ae1]:hover{color:var(--vp-c-brand-1)}.VPNavScreenMenuGroupSection[data-v-8133b170]{display:block}.title[data-v-8133b170]{line-height:32px;font-size:13px;font-weight:700;color:var(--vp-c-text-2);transition:color .25s}.VPNavScreenMenuGroup[data-v-ff6087d4]{border-bottom:1px solid var(--vp-c-divider);height:48px;overflow:hidden;transition:border-color .5s}.VPNavScreenMenuGroup .items[data-v-ff6087d4]{visibility:hidden}.VPNavScreenMenuGroup.open .items[data-v-ff6087d4]{visibility:visible}.VPNavScreenMenuGroup.open[data-v-ff6087d4]{padding-bottom:10px;height:auto}.VPNavScreenMenuGroup.open .button[data-v-ff6087d4]{padding-bottom:6px;color:var(--vp-c-brand-1)}.VPNavScreenMenuGroup.open .button-icon[data-v-ff6087d4]{transform:rotate(45deg)}.button[data-v-ff6087d4]{display:flex;justify-content:space-between;align-items:center;padding:12px 4px 11px 0;width:100%;line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-1);transition:color .25s}.button[data-v-ff6087d4]:hover{color:var(--vp-c-brand-1)}.button-icon[data-v-ff6087d4]{transition:transform .25s}.group[data-v-ff6087d4]:first-child{padding-top:0}.group+.group[data-v-ff6087d4],.group+.item[data-v-ff6087d4]{padding-top:4px}.VPNavScreenTranslations[data-v-858fe1a4]{height:24px;overflow:hidden}.VPNavScreenTranslations.open[data-v-858fe1a4]{height:auto}.title[data-v-858fe1a4]{display:flex;align-items:center;font-size:14px;font-weight:500;color:var(--vp-c-text-1)}.icon[data-v-858fe1a4]{font-size:16px}.icon.lang[data-v-858fe1a4]{margin-right:8px}.icon.chevron[data-v-858fe1a4]{margin-left:4px}.list[data-v-858fe1a4]{padding:4px 0 0 24px}.link[data-v-858fe1a4]{line-height:32px;font-size:13px;color:var(--vp-c-text-1)}.VPNavScreen[data-v-cc5739dd]{position:fixed;top:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 1px);right:0;bottom:0;left:0;padding:0 32px;width:100%;background-color:var(--vp-nav-screen-bg-color);overflow-y:auto;transition:background-color .5s;pointer-events:auto}.VPNavScreen.fade-enter-active[data-v-cc5739dd],.VPNavScreen.fade-leave-active[data-v-cc5739dd]{transition:opacity .25s}.VPNavScreen.fade-enter-active .container[data-v-cc5739dd],.VPNavScreen.fade-leave-active .container[data-v-cc5739dd]{transition:transform .25s ease}.VPNavScreen.fade-enter-from[data-v-cc5739dd],.VPNavScreen.fade-leave-to[data-v-cc5739dd]{opacity:0}.VPNavScreen.fade-enter-from .container[data-v-cc5739dd],.VPNavScreen.fade-leave-to .container[data-v-cc5739dd]{transform:translateY(-8px)}@media (min-width: 768px){.VPNavScreen[data-v-cc5739dd]{display:none}}.container[data-v-cc5739dd]{margin:0 auto;padding:24px 0 96px;max-width:288px}.menu+.translations[data-v-cc5739dd],.menu+.appearance[data-v-cc5739dd],.translations+.appearance[data-v-cc5739dd]{margin-top:24px}.menu+.social-links[data-v-cc5739dd]{margin-top:16px}.appearance+.social-links[data-v-cc5739dd]{margin-top:16px}.VPNav[data-v-ae24b3ad]{position:relative;top:var(--vp-layout-top-height, 0px);left:0;z-index:var(--vp-z-index-nav);width:100%;pointer-events:none;transition:background-color .5s}@media (min-width: 960px){.VPNav[data-v-ae24b3ad]{position:fixed}}.VPSidebarItem.level-0[data-v-b8d55f3b]{padding-bottom:24px}.VPSidebarItem.collapsed.level-0[data-v-b8d55f3b]{padding-bottom:10px}.item[data-v-b8d55f3b]{position:relative;display:flex;width:100%}.VPSidebarItem.collapsible>.item[data-v-b8d55f3b]{cursor:pointer}.indicator[data-v-b8d55f3b]{position:absolute;top:6px;bottom:6px;left:-17px;width:2px;border-radius:2px;transition:background-color .25s}.VPSidebarItem.level-2.is-active>.item>.indicator[data-v-b8d55f3b],.VPSidebarItem.level-3.is-active>.item>.indicator[data-v-b8d55f3b],.VPSidebarItem.level-4.is-active>.item>.indicator[data-v-b8d55f3b],.VPSidebarItem.level-5.is-active>.item>.indicator[data-v-b8d55f3b]{background-color:var(--vp-c-brand-1)}.link[data-v-b8d55f3b]{display:flex;align-items:center;flex-grow:1}.text[data-v-b8d55f3b]{flex-grow:1;padding:4px 0;line-height:24px;font-size:14px;transition:color .25s}.VPSidebarItem.level-0 .text[data-v-b8d55f3b]{font-weight:700;color:var(--vp-c-text-1)}.VPSidebarItem.level-1 .text[data-v-b8d55f3b],.VPSidebarItem.level-2 .text[data-v-b8d55f3b],.VPSidebarItem.level-3 .text[data-v-b8d55f3b],.VPSidebarItem.level-4 .text[data-v-b8d55f3b],.VPSidebarItem.level-5 .text[data-v-b8d55f3b]{font-weight:500;color:var(--vp-c-text-2)}.VPSidebarItem.level-0.is-link>.item>.link:hover .text[data-v-b8d55f3b],.VPSidebarItem.level-1.is-link>.item>.link:hover .text[data-v-b8d55f3b],.VPSidebarItem.level-2.is-link>.item>.link:hover .text[data-v-b8d55f3b],.VPSidebarItem.level-3.is-link>.item>.link:hover .text[data-v-b8d55f3b],.VPSidebarItem.level-4.is-link>.item>.link:hover .text[data-v-b8d55f3b],.VPSidebarItem.level-5.is-link>.item>.link:hover .text[data-v-b8d55f3b]{color:var(--vp-c-brand-1)}.VPSidebarItem.level-0.has-active>.item>.text[data-v-b8d55f3b],.VPSidebarItem.level-1.has-active>.item>.text[data-v-b8d55f3b],.VPSidebarItem.level-2.has-active>.item>.text[data-v-b8d55f3b],.VPSidebarItem.level-3.has-active>.item>.text[data-v-b8d55f3b],.VPSidebarItem.level-4.has-active>.item>.text[data-v-b8d55f3b],.VPSidebarItem.level-5.has-active>.item>.text[data-v-b8d55f3b],.VPSidebarItem.level-0.has-active>.item>.link>.text[data-v-b8d55f3b],.VPSidebarItem.level-1.has-active>.item>.link>.text[data-v-b8d55f3b],.VPSidebarItem.level-2.has-active>.item>.link>.text[data-v-b8d55f3b],.VPSidebarItem.level-3.has-active>.item>.link>.text[data-v-b8d55f3b],.VPSidebarItem.level-4.has-active>.item>.link>.text[data-v-b8d55f3b],.VPSidebarItem.level-5.has-active>.item>.link>.text[data-v-b8d55f3b]{color:var(--vp-c-text-1)}.VPSidebarItem.level-0.is-active>.item .link>.text[data-v-b8d55f3b],.VPSidebarItem.level-1.is-active>.item .link>.text[data-v-b8d55f3b],.VPSidebarItem.level-2.is-active>.item .link>.text[data-v-b8d55f3b],.VPSidebarItem.level-3.is-active>.item .link>.text[data-v-b8d55f3b],.VPSidebarItem.level-4.is-active>.item .link>.text[data-v-b8d55f3b],.VPSidebarItem.level-5.is-active>.item .link>.text[data-v-b8d55f3b]{color:var(--vp-c-brand-1)}.caret[data-v-b8d55f3b]{display:flex;justify-content:center;align-items:center;margin-right:-7px;width:32px;height:32px;color:var(--vp-c-text-3);cursor:pointer;transition:color .25s;flex-shrink:0}.item:hover .caret[data-v-b8d55f3b]{color:var(--vp-c-text-2)}.item:hover .caret[data-v-b8d55f3b]:hover{color:var(--vp-c-text-1)}.caret-icon[data-v-b8d55f3b]{font-size:18px;transform:rotate(90deg);transition:transform .25s}.VPSidebarItem.collapsed .caret-icon[data-v-b8d55f3b]{transform:rotate(0)}.VPSidebarItem.level-1 .items[data-v-b8d55f3b],.VPSidebarItem.level-2 .items[data-v-b8d55f3b],.VPSidebarItem.level-3 .items[data-v-b8d55f3b],.VPSidebarItem.level-4 .items[data-v-b8d55f3b],.VPSidebarItem.level-5 .items[data-v-b8d55f3b]{border-left:1px solid var(--vp-c-divider);padding-left:16px}.VPSidebarItem.collapsed .items[data-v-b8d55f3b]{display:none}.VPSidebar[data-v-575e6a36]{position:fixed;top:var(--vp-layout-top-height, 0px);bottom:0;left:0;z-index:var(--vp-z-index-sidebar);padding:32px 32px 96px;width:calc(100vw - 64px);max-width:320px;background-color:var(--vp-sidebar-bg-color);opacity:0;box-shadow:var(--vp-c-shadow-3);overflow-x:hidden;overflow-y:auto;transform:translate(-100%);transition:opacity .5s,transform .25s ease;overscroll-behavior:contain}.VPSidebar.open[data-v-575e6a36]{opacity:1;visibility:visible;transform:translate(0);transition:opacity .25s,transform .5s cubic-bezier(.19,1,.22,1)}.dark .VPSidebar[data-v-575e6a36]{box-shadow:var(--vp-shadow-1)}@media (min-width: 960px){.VPSidebar[data-v-575e6a36]{padding-top:var(--vp-nav-height);width:var(--vp-sidebar-width);max-width:100%;background-color:var(--vp-sidebar-bg-color);opacity:1;visibility:visible;box-shadow:none;transform:translate(0)}}@media (min-width: 1440px){.VPSidebar[data-v-575e6a36]{padding-left:max(32px,calc((100% - (var(--vp-layout-max-width) - 64px)) / 2));width:calc((100% - (var(--vp-layout-max-width) - 64px)) / 2 + var(--vp-sidebar-width) - 32px)}}@media (min-width: 960px){.curtain[data-v-575e6a36]{position:sticky;top:-64px;left:0;z-index:1;margin-top:calc(var(--vp-nav-height) * -1);margin-right:-32px;margin-left:-32px;height:var(--vp-nav-height);background-color:var(--vp-sidebar-bg-color)}}.nav[data-v-575e6a36]{outline:0}.group+.group[data-v-575e6a36]{border-top:1px solid var(--vp-c-divider);padding-top:10px}@media (min-width: 960px){.group[data-v-575e6a36]{padding-top:10px;width:calc(var(--vp-sidebar-width) - 64px)}}.VPSkipLink[data-v-0f60ec36]{top:8px;left:8px;padding:8px 16px;z-index:999;border-radius:8px;font-size:12px;font-weight:700;text-decoration:none;color:var(--vp-c-brand-1);box-shadow:var(--vp-shadow-3);background-color:var(--vp-c-bg)}.VPSkipLink[data-v-0f60ec36]:focus{height:auto;width:auto;clip:auto;clip-path:none}@media (min-width: 1280px){.VPSkipLink[data-v-0f60ec36]{top:14px;left:16px}}.Layout[data-v-5d98c3a5]{display:flex;flex-direction:column;min-height:100vh}.VPHomeSponsors[data-v-3d121b4a]{border-top:1px solid var(--vp-c-gutter);padding-top:88px!important}.VPHomeSponsors[data-v-3d121b4a]{margin:96px 0}@media (min-width: 768px){.VPHomeSponsors[data-v-3d121b4a]{margin:128px 0}}.VPHomeSponsors[data-v-3d121b4a]{padding:0 24px}@media (min-width: 768px){.VPHomeSponsors[data-v-3d121b4a]{padding:0 48px}}@media (min-width: 960px){.VPHomeSponsors[data-v-3d121b4a]{padding:0 64px}}.container[data-v-3d121b4a]{margin:0 auto;max-width:1152px}.love[data-v-3d121b4a]{margin:0 auto;width:fit-content;font-size:28px;color:var(--vp-c-text-3)}.icon[data-v-3d121b4a]{display:inline-block}.message[data-v-3d121b4a]{margin:0 auto;padding-top:10px;max-width:320px;text-align:center;line-height:24px;font-size:16px;font-weight:500;color:var(--vp-c-text-2)}.sponsors[data-v-3d121b4a]{padding-top:32px}.action[data-v-3d121b4a]{padding-top:40px;text-align:center}.VPTeamPage[data-v-7c57f839]{margin:96px 0}@media (min-width: 768px){.VPTeamPage[data-v-7c57f839]{margin:128px 0}}.VPHome .VPTeamPageTitle[data-v-7c57f839-s]{border-top:1px solid var(--vp-c-gutter);padding-top:88px!important}.VPTeamPageSection+.VPTeamPageSection[data-v-7c57f839-s],.VPTeamMembers+.VPTeamPageSection[data-v-7c57f839-s]{margin-top:64px}.VPTeamMembers+.VPTeamMembers[data-v-7c57f839-s]{margin-top:24px}@media (min-width: 768px){.VPTeamPageTitle+.VPTeamPageSection[data-v-7c57f839-s]{margin-top:16px}.VPTeamPageSection+.VPTeamPageSection[data-v-7c57f839-s],.VPTeamMembers+.VPTeamPageSection[data-v-7c57f839-s]{margin-top:96px}}.VPTeamMembers[data-v-7c57f839-s]{padding:0 24px}@media (min-width: 768px){.VPTeamMembers[data-v-7c57f839-s]{padding:0 48px}}@media (min-width: 960px){.VPTeamMembers[data-v-7c57f839-s]{padding:0 64px}}.VPTeamPageTitle[data-v-bf2cbdac]{padding:48px 32px;text-align:center}@media (min-width: 768px){.VPTeamPageTitle[data-v-bf2cbdac]{padding:64px 48px 48px}}@media (min-width: 960px){.VPTeamPageTitle[data-v-bf2cbdac]{padding:80px 64px 48px}}.title[data-v-bf2cbdac]{letter-spacing:0;line-height:44px;font-size:36px;font-weight:500}@media (min-width: 768px){.title[data-v-bf2cbdac]{letter-spacing:-.5px;line-height:56px;font-size:48px}}.lead[data-v-bf2cbdac]{margin:0 auto;max-width:512px;padding-top:12px;line-height:24px;font-size:16px;font-weight:500;color:var(--vp-c-text-2)}@media (min-width: 768px){.lead[data-v-bf2cbdac]{max-width:592px;letter-spacing:.15px;line-height:28px;font-size:20px}}.VPTeamPageSection[data-v-b1a88750]{padding:0 32px}@media (min-width: 768px){.VPTeamPageSection[data-v-b1a88750]{padding:0 48px}}@media (min-width: 960px){.VPTeamPageSection[data-v-b1a88750]{padding:0 64px}}.title[data-v-b1a88750]{position:relative;margin:0 auto;max-width:1152px;text-align:center;color:var(--vp-c-text-2)}.title-line[data-v-b1a88750]{position:absolute;top:16px;left:0;width:100%;height:1px;background-color:var(--vp-c-divider)}.title-text[data-v-b1a88750]{position:relative;display:inline-block;padding:0 24px;letter-spacing:0;line-height:32px;font-size:20px;font-weight:500;background-color:var(--vp-c-bg)}.lead[data-v-b1a88750]{margin:0 auto;max-width:480px;padding-top:12px;text-align:center;line-height:24px;font-size:16px;font-weight:500;color:var(--vp-c-text-2)}.members[data-v-b1a88750]{padding-top:40px}.VPTeamMembersItem[data-v-f3fa364a]{display:flex;flex-direction:column;gap:2px;border-radius:12px;width:100%;height:100%;overflow:hidden}.VPTeamMembersItem.small .profile[data-v-f3fa364a]{padding:32px}.VPTeamMembersItem.small .data[data-v-f3fa364a]{padding-top:20px}.VPTeamMembersItem.small .avatar[data-v-f3fa364a]{width:64px;height:64px}.VPTeamMembersItem.small .name[data-v-f3fa364a]{line-height:24px;font-size:16px}.VPTeamMembersItem.small .affiliation[data-v-f3fa364a]{padding-top:4px;line-height:20px;font-size:14px}.VPTeamMembersItem.small .desc[data-v-f3fa364a]{padding-top:12px;line-height:20px;font-size:14px}.VPTeamMembersItem.small .links[data-v-f3fa364a]{margin:0 -16px -20px;padding:10px 0 0}.VPTeamMembersItem.medium .profile[data-v-f3fa364a]{padding:48px 32px}.VPTeamMembersItem.medium .data[data-v-f3fa364a]{padding-top:24px;text-align:center}.VPTeamMembersItem.medium .avatar[data-v-f3fa364a]{width:96px;height:96px}.VPTeamMembersItem.medium .name[data-v-f3fa364a]{letter-spacing:.15px;line-height:28px;font-size:20px}.VPTeamMembersItem.medium .affiliation[data-v-f3fa364a]{padding-top:4px;font-size:16px}.VPTeamMembersItem.medium .desc[data-v-f3fa364a]{padding-top:16px;max-width:288px;font-size:16px}.VPTeamMembersItem.medium .links[data-v-f3fa364a]{margin:0 -16px -12px;padding:16px 12px 0}.profile[data-v-f3fa364a]{flex-grow:1;background-color:var(--vp-c-bg-soft)}.data[data-v-f3fa364a]{text-align:center}.avatar[data-v-f3fa364a]{position:relative;flex-shrink:0;margin:0 auto;border-radius:50%;box-shadow:var(--vp-shadow-3)}.avatar-img[data-v-f3fa364a]{position:absolute;top:0;right:0;bottom:0;left:0;border-radius:50%;object-fit:cover}.name[data-v-f3fa364a]{margin:0;font-weight:600}.affiliation[data-v-f3fa364a]{margin:0;font-weight:500;color:var(--vp-c-text-2)}.org.link[data-v-f3fa364a]{color:var(--vp-c-text-2);transition:color .25s}.org.link[data-v-f3fa364a]:hover{color:var(--vp-c-brand-1)}.desc[data-v-f3fa364a]{margin:0 auto}.desc[data-v-f3fa364a] a{font-weight:500;color:var(--vp-c-brand-1);text-decoration-style:dotted;transition:color .25s}.links[data-v-f3fa364a]{display:flex;justify-content:center;height:56px}.sp-link[data-v-f3fa364a]{display:flex;justify-content:center;align-items:center;text-align:center;padding:16px;font-size:14px;font-weight:500;color:var(--vp-c-sponsor);background-color:var(--vp-c-bg-soft);transition:color .25s,background-color .25s}.sp .sp-link.link[data-v-f3fa364a]:hover,.sp .sp-link.link[data-v-f3fa364a]:focus{outline:none;color:var(--vp-c-white);background-color:var(--vp-c-sponsor)}.sp-icon[data-v-f3fa364a]{margin-right:8px;font-size:16px}.VPTeamMembers.small .container[data-v-6cb0dbc4]{grid-template-columns:repeat(auto-fit,minmax(224px,1fr))}.VPTeamMembers.small.count-1 .container[data-v-6cb0dbc4]{max-width:276px}.VPTeamMembers.small.count-2 .container[data-v-6cb0dbc4]{max-width:576px}.VPTeamMembers.small.count-3 .container[data-v-6cb0dbc4]{max-width:876px}.VPTeamMembers.medium .container[data-v-6cb0dbc4]{grid-template-columns:repeat(auto-fit,minmax(256px,1fr))}@media (min-width: 375px){.VPTeamMembers.medium .container[data-v-6cb0dbc4]{grid-template-columns:repeat(auto-fit,minmax(288px,1fr))}}.VPTeamMembers.medium.count-1 .container[data-v-6cb0dbc4]{max-width:368px}.VPTeamMembers.medium.count-2 .container[data-v-6cb0dbc4]{max-width:760px}.container[data-v-6cb0dbc4]{display:grid;gap:24px;margin:0 auto;max-width:1152px}:root{--vp-nolebase-highlight-targeted-heading-color: var(--vp-custom-block-tip-text);--vp-nolebase-highlight-targeted-heading-bg: var(--vp-custom-block-tip-bg)}@keyframes vp-nolebase-highlight-targeted-heading-animation{0%{background-color:transparent;box-shadow:0 0 0 8px transparent}10%,35%{color:var(--vp-nolebase-highlight-targeted-heading-color);border-color:transparent;border-radius:4px;background-color:var(--vp-nolebase-highlight-targeted-heading-bg);box-shadow:0 0 0 8px var(--vp-nolebase-highlight-targeted-heading-bg)}99%{background-color:transparent;border-radius:4px;box-shadow:0 0 0 8px transparent}to{border-radius:0;background-color:transparent;box-shadow:none}}.VPNolebaseHighlightTargetedHeadingAnimated{animation:vp-nolebase-highlight-targeted-heading-animation 1.5s ease-in-out}*,:before,:after{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset: ;--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / .5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: }::backdrop{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset: ;--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / .5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: }@font-face{font-family:"Baloo 2";font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/baloo2/v21/wXK0E3kTposypRydzVT08TS3JnAmtdgazZpp_led7Q.woff2) format("woff2");unicode-range:U+0900-097F,U+1CD0-1CF9,U+200C-200D,U+20A8,U+20B9,U+20F0,U+25CC,U+A830-A839,U+A8E0-A8FF,U+11B00-11B09}@font-face{font-family:"Baloo 2";font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/baloo2/v21/wXK0E3kTposypRydzVT08TS3JnAmtdgazZpn_led7Q.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:"Baloo 2";font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/baloo2/v21/wXK0E3kTposypRydzVT08TS3JnAmtdgazZpm_led7Q.woff2) format("woff2");unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:"Baloo 2";font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/baloo2/v21/wXK0E3kTposypRydzVT08TS3JnAmtdgazZpo_lc.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Chakra Petch;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/chakrapetch/v11/cIf6MapbsEk7TDLdtEz1BwkWi6pgeL4.woff2) format("woff2");unicode-range:U+0E01-0E5B,U+200C-200D,U+25CC}@font-face{font-family:Chakra Petch;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/chakrapetch/v11/cIf6MapbsEk7TDLdtEz1BwkWkKpgeL4.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Chakra Petch;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/chakrapetch/v11/cIf6MapbsEk7TDLdtEz1BwkWkapgeL4.woff2) format("woff2");unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Chakra Petch;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/chakrapetch/v11/cIf6MapbsEk7TDLdtEz1BwkWn6pg.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Jura;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/jura/v31/z7NOdRfiaC4Vd8hhoPzfb5vBTP1d7ZurR_ibHw.woff2) format("woff2");unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Jura;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/jura/v31/z7NOdRfiaC4Vd8hhoPzfb5vBTP1d7ZuiR_ibHw.woff2) format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Jura;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/jura/v31/z7NOdRfiaC4Vd8hhoPzfb5vBTP1d7ZuqR_ibHw.woff2) format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Jura;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/jura/v31/z7NOdRfiaC4Vd8hhoPzfb5vBTP1d7ZulR_ibHw.woff2) format("woff2");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Jura;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/jura/v31/z7NOdRfiaC4Vd8hhoPzfb5vBTP1d7ZvuR_ibHw.woff2) format("woff2");unicode-range:U+200C-200D,U+2010,U+25CC,U+A900-A92F}@font-face{font-family:Jura;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/jura/v31/z7NOdRfiaC4Vd8hhoPzfb5vBTP1d7ZupR_ibHw.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Jura;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/jura/v31/z7NOdRfiaC4Vd8hhoPzfb5vBTP1d7ZuoR_ibHw.woff2) format("woff2");unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Jura;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/jura/v31/z7NOdRfiaC4Vd8hhoPzfb5vBTP1d7ZumR_g.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Noto Sans;font-style:normal;font-weight:400;font-stretch:normal;font-display:swap;src:url(https://fonts.gstatic.com/s/notosans/v36/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9X6VLKzA.woff2) format("woff2");unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Noto Sans;font-style:normal;font-weight:400;font-stretch:normal;font-display:swap;src:url(https://fonts.gstatic.com/s/notosans/v36/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9e6VLKzA.woff2) format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Noto Sans;font-style:normal;font-weight:400;font-stretch:normal;font-display:swap;src:url(https://fonts.gstatic.com/s/notosans/v36/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9b6VLKzA.woff2) format("woff2");unicode-range:U+0900-097F,U+1CD0-1CF9,U+200C-200D,U+20A8,U+20B9,U+20F0,U+25CC,U+A830-A839,U+A8E0-A8FF,U+11B00-11B09}@font-face{font-family:Noto Sans;font-style:normal;font-weight:400;font-stretch:normal;font-display:swap;src:url(https://fonts.gstatic.com/s/notosans/v36/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9W6VLKzA.woff2) format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Noto Sans;font-style:normal;font-weight:400;font-stretch:normal;font-display:swap;src:url(https://fonts.gstatic.com/s/notosans/v36/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9Z6VLKzA.woff2) format("woff2");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Noto Sans;font-style:normal;font-weight:400;font-stretch:normal;font-display:swap;src:url(https://fonts.gstatic.com/s/notosans/v36/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9V6VLKzA.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Noto Sans;font-style:normal;font-weight:400;font-stretch:normal;font-display:swap;src:url(https://fonts.gstatic.com/s/notosans/v36/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9U6VLKzA.woff2) format("woff2");unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Noto Sans;font-style:normal;font-weight:400;font-stretch:normal;font-display:swap;src:url(https://fonts.gstatic.com/s/notosans/v36/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9a6VI.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu72xKOzY.woff2) format("woff2");unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu5mxKOzY.woff2) format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu7mxKOzY.woff2) format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu4WxKOzY.woff2) format("woff2");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu7WxKOzY.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu7GxKOzY.woff2) format("woff2");unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu4mxK.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2) format("woff2");unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/assets/inter-roman-cyrillic.C5lxZ8CY.woff2) format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/assets/inter-roman-greek-ext.CqjqNYQ-.woff2) format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/assets/inter-roman-greek.BBVDIX6e.woff2) format("woff2");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/assets/inter-roman-vietnamese.BjW4sHH5.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/assets/inter-roman-latin-ext.4ZJIpNVo.woff2) format("woff2");unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/assets/inter-roman-latin.Di8DUHzh.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/assets/inter-italic-cyrillic-ext.r48I6akx.woff2) format("woff2");unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/assets/inter-italic-cyrillic.By2_1cv3.woff2) format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/assets/inter-italic-greek-ext.1u6EdAuj.woff2) format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/assets/inter-italic-greek.DJ8dCoTZ.woff2) format("woff2");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/assets/inter-italic-vietnamese.BSbpV94h.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/assets/inter-italic-latin-ext.CN1xVJS-.woff2) format("woff2");unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/assets/inter-italic-latin.C2AdPX0b.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Punctuation SC;font-weight:400;src:local("PingFang SC Regular"),local("Noto Sans CJK SC"),local("Microsoft YaHei");unicode-range:U+201C,U+201D,U+2018,U+2019,U+2E3A,U+2014,U+2013,U+2026,U+00B7,U+007E,U+002F}@font-face{font-family:Punctuation SC;font-weight:500;src:local("PingFang SC Medium"),local("Noto Sans CJK SC"),local("Microsoft YaHei");unicode-range:U+201C,U+201D,U+2018,U+2019,U+2E3A,U+2014,U+2013,U+2026,U+00B7,U+007E,U+002F}@font-face{font-family:Punctuation SC;font-weight:600;src:local("PingFang SC Semibold"),local("Noto Sans CJK SC Bold"),local("Microsoft YaHei Bold");unicode-range:U+201C,U+201D,U+2018,U+2019,U+2E3A,U+2014,U+2013,U+2026,U+00B7,U+007E,U+002F}@font-face{font-family:Punctuation SC;font-weight:700;src:local("PingFang SC Semibold"),local("Noto Sans CJK SC Bold"),local("Microsoft YaHei Bold");unicode-range:U+201C,U+201D,U+2018,U+2019,U+2E3A,U+2014,U+2013,U+2026,U+00B7,U+007E,U+002F}html{overflow-x:hidden}:root{--vp-c-bg: #3B4252;--vp-c-bg-elv: #434C5E;--vp-font-family-base: Itim;--vp-font-family-mono: Roboto Mono;--vp-layout-max-width: 1080px;--vp-nav-height: 48px;--vp-local-search-bg: var(--vp-c-bg-alt)}footer{color:var(--vp-c-default-1)}footer a[href^=http]:after{color:var(--vp-c-border)!important}.title{justify-content:center;border:none!important;position:unset!important;padding:0!important;width:unset!important}.title span{font-size:x-large}.search{padding-left:0;display:flex;flex-grow:0!important;padding-left:unset!important}.DocSearch-Button{margin:auto;width:unset;border:none!important}.DocSearch-Button-Placeholder{margin-top:unset!important;padding:unset!important;font-size:unset!important;font-weight:unset!important;color:unset!important;margin-right:8px}.VPNavBarMenu{align-items:flex-end}.VPNavBarMenuLink{line-height:unset!important;font-size:unset!important;font-weight:unset!important;color:unset!important}ul>li>ul{position:relative}ul>li>ul:before{position:absolute;content:"";width:2px;background:var(--vp-c-text-1);opacity:.3;left:-16px;top:8px;bottom:8px}.aside{display:none!important}.img-container{padding:15px;position:relative;height:11lh;width:fit-content;margin:auto}.img-container img{clip-path:polygon(18px 0%,100% 0,100% calc(100% - 18px),calc(100% - 18px) 100%,0 100%,0% 18px);height:100%;object-fit:contain;background:#fff}.img-container:after,.img-container:before{content:"";display:block;position:absolute;border:50px solid transparent;transform:rotate(135deg)}.img-container:after{bottom:-60px;right:-65px;box-shadow:0 7px 6px -9px #000}.img-container:before{top:-60px;left:-65px;box-shadow:0 -7px 6px -9px #000}.VPDoc{padding:0 32px!important}.vp-doc a{color:unset;text-decoration:unset;font-weight:unset;text-underline-offset:unset;margin:0 -.4em;padding:.1em .4em;border-radius:.8em .3em;background:transparent;background-image:linear-gradient(to right,#ffe1000d,#ffe10059 4%,#ffe10026);-webkit-box-decoration-break:clone;box-decoration-break:clone}.vp-doc a:hover{color:unset;background-image:linear-gradient(to right,#ffe1001a,#ffe100b3 4%,#ffe1004d)}.vp-doc a[href^=http]:after{content:"";display:inline-block;margin-top:-1px;margin-left:4px;width:11px;height:11px;background:currentColor;color:var(--vp-c-text-3);flex-shrink:0;--icon: url("data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' %3E%3Cpath d='M0 0h24v24H0V0z' fill='none' /%3E%3Cpath d='M9 5v2h6.59L4 18.59 5.41 20 17 8.41V15h2V5H9z' /%3E%3C/svg%3E");-webkit-mask-image:var(--icon);mask-image:var(--icon)}.VPNav{left:96px!important;right:32px!important;width:unset!important;position:absolute!important;overflow:hidden}.wrapper{padding:0!important}.VPNavBar{background-color:unset!important}.VPNav .container{align-items:flex-end}.VPNav .content{padding:0!important}.VPNav .content-body{height:unset!important;align-items:flex-end!important;column-gap:unset!important}.VPNavBarHamburger{width:unset!important}.title{height:unset!important}a.title,.VPNavBarMenuLink,.VPNavBarSocialLinks a,.DocSearch-Button,.VPNav button{height:36px!important;border-radius:10px 10px 0 0;padding:8px 8px 16px!important;margin-bottom:-8px!important}.VPNav a:hover,.DocSearch-Button:hover,.VPNav button:hover{margin-bottom:unset!important}a.title{background-color:#0ff}.DocSearch-Button{background-color:#ff0!important}.VPNav .VPNavBarMenuLink[href="https://moddingtree.com"]{background-color:#0f0}.VPNav .VPNavBarMenuLink[href="https://incremental.social"]{background:#f0f}.VPNav button{background:red}.VPNav .VPNavBarSocialLinks [href="https://code.incremental.social/thepaperpilot"]{background:#f70}.VPNav .VPNavBarSocialLinks [href="https://matrix.to/#/@thepaperpilot:incremental.social"]{background:#3c9a3c}.VPNav .VPNavBarSocialLinks [href="https://incremental.social/u/thepaperpilot"]{background:#a75aff}.VPNav .divider{display:none!important}.VPSocialLinks{align-items:flex-end!important;margin-right:0!important}.VPSocialLinks:before{display:none}.VPNavBarExtra{display:none!important}.VPNavBarSocialLinks{display:flex!important}.VPNavScreenSocialLinks a,.VPNavScreenMenuLink,.VPNavScreenMenuLink:after{color:var(--vp-c-bg-alt)!important}@media (max-width: 500px){.VPNavBarSocialLinks{display:none!important}}@media (min-width: 501px){.VPNavScreenSocialLinks{display:none!important}}@media (max-width: 400px){.title span{width:60px}.title span:before{content:"Home ."}}.VPContent{padding-top:0!important;margin-top:var(--vp-nav-height)!important;padding-right:calc((100vw - var(--vp-layout-max-width)) / 2)!important;padding-left:calc((100vw - var(--vp-layout-max-width)) / 2)!important}@media (min-width: 960px){.VPNav{right:calc(max(0px,(100vw - var(--vp-layout-max-width)) / 2) + 32px)!important;left:calc(max(-15px,(100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width)) + 32px)!important}.VPContent{padding-left:calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width))!important}}.vp-doc .header-anchor{margin-left:calc(-1em - 23px)}.vp-doc .header-anchor{top:0!important}.VPSidebar{opacity:1!important;transition:.5s ease-out!important;box-shadow:0 0 10px 1px #0003!important}.VPLocalNav{position:fixed!important;border-bottom:none!important;background-color:unset!important;pointer-events:none}.VPLocalNav .container{align-items:flex-start!important;flex-direction:column!important}.VPLocalNav>.container>*{pointer-events:all}.VPLocalNav .menu{background:#7afcff;box-shadow:0 0 5px 1px #0003;margin-top:10px;height:30px;width:90px;padding:0 0 0 8px!important}.VPLocalNav button:not(.menu){background:#ff7eb9;padding:4px 30px 4px 8px;box-shadow:0 0 5px 1px #0003}.outline-marker{left:16px!important}.VPLocalNavOutlineDropdown{padding:0!important;margin-top:10px}.VPLocalNavOutlineDropdown button{padding:0!important;width:90px;height:30px}.curtain{display:none}@media (max-width: 840px){.DocSearch-Button-Keys{display:none!important}}@media (max-width: 959px){.VPSidebar{margin-left:-1000px!important;padding:30px 30px 30px 1030px!important;box-sizing:content-box;background:linear-gradient(to bottom,var(--vp-sidebar-bg-color) 29px,var(--vp-c-divider) 1px);background-size:100% 30px;line-height:30px;width:calc(100vw - 128px)}}.VPLocalNavOutlineDropdown .items{background:linear-gradient(to bottom,var(--vp-sidebar-bg-color) 29px,var(--vp-c-divider) 1px);background-size:100% 30px;top:85px;border-radius:0}.VPLocalNavOutlineDropdown ul>li>ul:before{left:0}.VPLocalNavOutlineDropdown .header,.VPLocalNavOutlineDropdown .outline{background:none!important;padding:0!important}.VPLocalNavOutlineDropdown .top-link,.VPLocalNavOutlineDropdown .outline-link{line-height:30px!important;font-size:unset!important;font-weight:unset!important}.aside-curtain{display:none!important}@media (min-width: 960px){.VPSidebar{transform:rotate(1.4deg)!important;top:1em!important;bottom:unset!important;--vp-sidebar-width: 250px !important;background:#feff9c!important;padding:30px!important;width:var(--vp-sidebar-width)!important;margin-left:max(-15px,calc((100% - (var(--vp-layout-max-width) - 60px)) / 2))!important;max-height:40vh;transition-duration:0s!important}.VPLocalNavOutlineDropdown{display:none}.VPDoc .aside{display:block!important;transform:rotate(1.4deg)!important;position:fixed;top:calc(40vh + 2em);left:0;--vp-sidebar-width: 250px !important;background:#feff9c!important;width:var(--vp-sidebar-width)!important;padding:0!important;margin-left:max(-15px,calc((100% - (var(--vp-layout-max-width) - 60px)) / 2))!important;max-height:40vh;overflow-y:auto}.VPDoc .aside-container{position:unset!important;height:unset!important;overflow:unset!important;padding-top:unset!important;width:unset!important}.VPDoc .aside-content{min-height:unset!important;padding:0!important}.VPDoc .aside-content .content{padding:30px!important}.outline-title{font-size:14px;font-weight:700!important;line-height:30px!important}.VPDoc .aside ul>li>ul:before{display:none}}.VPContent .container{background:linear-gradient(to bottom,var(--vp-sidebar-bg-color) 29px,var(--vp-c-divider) 1px);background-size:100% 30px;line-height:30px;box-shadow:0 0 10px 1px #0003!important}.VPContent .content{padding:0 30px!important}.content-container{border-left:double 7px var(--vp-c-divider);padding:30px 0 30px 8px;max-width:unset!important}article{padding-top:30px}.vp-doc .h-feed article{padding-top:0!important}.vp-doc h2+.e-content{margin-top:0!important}.VPDoc h1,.VPDoc h2,.VPDoc h3,.VPDoc h4,.VPDoc h5,.VPDoc h6{margin:0!important;padding:0!important;line-height:30px!important}.VPDoc h1+p{margin-top:0!important}.VPDoc h2,.VPDoc h3,.VPDoc h4,.VPDoc h5,.VPDoc h6{margin-top:30px!important;margin-bottom:-30px!important;border:none!important}ul{margin:0!important}li+li{margin:0!important}.VPDoc p{padding:0!important;margin:30px 0!important;line-height:30px!important}blockquote{margin:30px 0!important}blockquote:first-child,blockquote:first-child p{margin-top:0!important}.VPDoc :has(+hr),.VPDoc :has(+h2),.VPDoc :has(+h3),.VPDoc :has(+h4),.VPDoc :has(+h5),.VPDoc :has(+h6),.VPDoc :has(+ul){margin-bottom:0!important}hr{margin-top:-3px!important;margin-bottom:-7px!important;border-top-style:solid!important;border-top-width:10px!important;border-image:url(/button.svg) 10 10 10 10 stretch stretch!important;height:0px!important}.text{line-height:30px!important;padding:0!important;margin:0!important}.group{padding-top:0!important}.group+.group{border-top-style:solid!important;border-top-width:10px!important;border-image:url(/button.svg) 10 10 10 10 stretch stretch!important;padding-top:23px!important;margin-top:-3px!important}table{margin:30px 0!important}#app .vp-doc tr{background-color:var(--vp-c-gray-2)}#app .vp-doc tr:nth-child(2n){background-color:var(--vp-c-bg-soft)}#app .vp-doc th,#app .vp-doc td{font-size:unset!important;font-weight:unset!important;color:unset!important;padding:0 8px!important;line-height:29px}.VPSidebarItem{padding-bottom:0!important}p:last-child{margin-bottom:0!important}.hero{width:60%;margin:auto}footer img{height:1lh;display:inline;border-radius:50%;margin:0 .25em;vertical-align:bottom}@property --anim-bg{syntax: ""; initial-value: transparent; inherits: false;}@keyframes vp-nolebase-highlight-targeted-heading-animation{0%{--anim-bg: transparent}10%,35%{--anim-bg: var(--vp-c-brand-soft)}99%{--anim-bg: transparent}to{--anim-bg: transparent}}.VPNolebaseHighlightTargetedHeadingAnimated{animation:vp-nolebase-highlight-targeted-heading-animation 1.5s ease-in-out;background:linear-gradient(0deg,var(--anim-bg) 55%,transparent 45%) repeat-x}.title-icon{line-height:30px}.excerpt{margin:8px 0!important;background:var(--docsearch-searchbox-background)}.excerpt-gradient-top{background:var(--docsearch-searchbox-background)!important;opacity:.5;clip-path:polygon(0% 0%,5% 100%,10% 0%,15% 100%,20% 0%,25% 100%,30% 0%,35% 100%,40% 0%,45% 100%,50% 0%,55% 100%,60% 0%,65% 100%,70% 0%,75% 100%,80% 0%,85% 100%,90% 0%,95% 100%,100% 0%);transform:translateY(-7px) rotate(180deg)}.excerpt-gradient-bottom{background:var(--docsearch-searchbox-background)!important;opacity:.5;clip-path:polygon(0% 0%,5% 100%,10% 0%,15% 100%,20% 0%,25% 100%,30% 0%,35% 100%,40% 0%,45% 100%,50% 0%,55% 100%,60% 0%,65% 100%,70% 0%,75% 100%,80% 0%,85% 100%,90% 0%,95% 100%,100% 0%);transform:translateY(7px)}.selected .excerpt-gradient-top,.selected .excerpt-gradient-bottom{opacity:1}.vp-doc details{border-bottom:solid 1px var(--vp-c-border)!important;margin-bottom:-1px!important}.vp-doc details a{margin-right:8px!important}.vp-doc summary{margin:29px 0 0!important;border-top:solid 1px var(--vp-c-border)!important;cursor:pointer!important}.background[data-v-d5ead69d]{position:fixed;top:0;left:0;right:0;bottom:0;z-index:-1;overflow:hidden}footer[data-v-d5ead69d]{padding:2em;z-index:26;position:relative;font-size:small;background:var(--vp-c-bg-elv)}.hero-wrapper[data-v-01cfbdb8]{height:16lh;position:relative}@media (max-width: 700px){.hero-wrapper[data-v-01cfbdb8]{height:12lh}}@media (max-width: 500px){.hero-wrapper[data-v-01cfbdb8]{height:10lh}}@media (max-width: 400px){.hero-wrapper[data-v-01cfbdb8]{height:9lh}}.hero[data-v-01cfbdb8]{height:80%;width:unset;margin:auto;position:absolute;right:50%;bottom:0;transform:translate(calc(50% + var(--x-offset)));animation:bob-01cfbdb8 5s ease-in-out infinite}svg[data-v-01cfbdb8]{display:none}@keyframes bob-01cfbdb8{0%{transform:translate(calc(50% + var(--x-offset)),-10%)}50%{transform:translate(calc(50% + var(--x-offset)),10%)}to{transform:translate(calc(50% + var(--x-offset)),-10%)}}.VPLocalSearchBox[data-v-639d7ab9]{position:fixed;z-index:100;top:0;right:0;bottom:0;left:0;display:flex}.backdrop[data-v-639d7ab9]{position:absolute;top:0;right:0;bottom:0;left:0;background:var(--vp-backdrop-bg-color);transition:opacity .5s}.shell[data-v-639d7ab9]{position:relative;padding:12px;margin:64px auto;display:flex;flex-direction:column;gap:16px;background:var(--vp-local-search-bg);width:min(100vw - 60px,900px);height:min-content;max-height:min(100vh - 128px,900px);border-radius:6px}@media (max-width: 767px){.shell[data-v-639d7ab9]{margin:0;width:100vw;height:100vh;max-height:none;border-radius:0}}.search-bar[data-v-639d7ab9]{border:1px solid var(--vp-c-divider);border-radius:4px;display:flex;align-items:center;padding:0 12px;cursor:text}@media (max-width: 767px){.search-bar[data-v-639d7ab9]{padding:0 8px}}.search-bar[data-v-639d7ab9]:focus-within{border-color:var(--vp-c-brand-1)}.local-search-icon[data-v-639d7ab9]{display:block;font-size:18px}.navigate-icon[data-v-639d7ab9]{display:block;font-size:14px}.search-icon[data-v-639d7ab9]{margin:8px}@media (max-width: 767px){.search-icon[data-v-639d7ab9]{display:none}}.search-input[data-v-639d7ab9]{padding:6px 12px;font-size:inherit;width:100%}@media (max-width: 767px){.search-input[data-v-639d7ab9]{padding:6px 4px}}.search-actions[data-v-639d7ab9]{display:flex;gap:4px}@media (any-pointer: coarse){.search-actions[data-v-639d7ab9]{gap:8px}}@media (min-width: 769px){.search-actions.before[data-v-639d7ab9]{display:none}}.search-actions button[data-v-639d7ab9]{padding:8px}.search-actions button[data-v-639d7ab9]:not([disabled]):hover,.toggle-layout-button.detailed-list[data-v-639d7ab9]{color:var(--vp-c-brand-1)}.search-actions button.clear-button[data-v-639d7ab9]:disabled{opacity:.37}.search-keyboard-shortcuts[data-v-639d7ab9]{font-size:.8rem;opacity:75%;display:flex;flex-wrap:wrap;gap:16px;line-height:14px}.search-keyboard-shortcuts span[data-v-639d7ab9]{display:flex;align-items:center;gap:4px}@media (max-width: 767px){.search-keyboard-shortcuts[data-v-639d7ab9]{display:none}}.search-keyboard-shortcuts kbd[data-v-639d7ab9]{background:#8080801a;border-radius:4px;padding:3px 6px;min-width:24px;display:inline-block;text-align:center;vertical-align:middle;border:1px solid rgba(128,128,128,.15);box-shadow:0 2px 2px #0000001a}.results[data-v-639d7ab9]{display:flex;flex-direction:column;gap:6px;overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain}.result[data-v-639d7ab9]{display:flex;align-items:center;gap:8px;border-radius:4px;transition:none;line-height:1rem;border:solid 2px var(--vp-local-search-result-border);outline:none}.result>div[data-v-639d7ab9]{margin:12px;width:100%;overflow:hidden}@media (max-width: 767px){.result>div[data-v-639d7ab9]{margin:8px}}.titles[data-v-639d7ab9]{display:flex;flex-wrap:wrap;gap:4px;position:relative;z-index:1001;padding:2px 0}.title[data-v-639d7ab9]{display:flex;align-items:center;gap:4px}.title.main[data-v-639d7ab9]{font-weight:500}.title-icon[data-v-639d7ab9]{opacity:.5;font-weight:500;color:var(--vp-c-brand-1)}.title svg[data-v-639d7ab9]{opacity:.5}.result.selected[data-v-639d7ab9]{--vp-local-search-result-bg: var(--vp-local-search-result-selected-bg);border-color:var(--vp-local-search-result-selected-border)}.excerpt-wrapper[data-v-639d7ab9]{position:relative}.excerpt[data-v-639d7ab9]{opacity:75%;pointer-events:none;max-height:140px;overflow:hidden;position:relative;opacity:.5;margin-top:4px}.result.selected .excerpt[data-v-639d7ab9]{opacity:1}.excerpt[data-v-639d7ab9] *{font-size:.8rem!important;line-height:130%!important}.titles[data-v-639d7ab9] mark,.excerpt[data-v-639d7ab9] mark{background-color:var(--vp-local-search-highlight-bg);color:var(--vp-local-search-highlight-text);border-radius:2px;padding:0 2px}.excerpt[data-v-639d7ab9] .vp-code-group .tabs{display:none}.excerpt[data-v-639d7ab9] .vp-code-group div[class*=language-]{border-radius:8px!important}.excerpt-gradient-bottom[data-v-639d7ab9]{position:absolute;bottom:-1px;left:0;width:100%;height:8px;background:linear-gradient(transparent,var(--vp-local-search-result-bg));z-index:1000}.excerpt-gradient-top[data-v-639d7ab9]{position:absolute;top:-1px;left:0;width:100%;height:8px;background:linear-gradient(var(--vp-local-search-result-bg),transparent);z-index:1000}.result.selected .titles[data-v-639d7ab9],.result.selected .title-icon[data-v-639d7ab9]{color:var(--vp-c-brand-1)!important}.no-results[data-v-639d7ab9]{font-size:.9rem;text-align:center;padding:12px}svg[data-v-639d7ab9]{flex:none}
              diff --git a/changelog/atom b/changelog/atom
              index 332ae0c8..461656ce 100644
              --- a/changelog/atom
              +++ b/changelog/atom
              @@ -2,7 +2,7 @@
               
                   https://www.thepaperpilot.org/changelog/
                   The Paper Pilot's Digital Garden Changelog
              -    2024-06-27T13:30:09.532Z
              +    2024-06-28T04:15:28.749Z
                   https://github.com/jpmonette/feed
                   
                       The Paper Pilot
              @@ -13,6 +13,26 @@
                   
                   A feed of updates made to my digital garden!
                   All rights reserved 2024, The Paper Pilot
              +    
              +        <![CDATA[ 3 files changed, 49 insertions(+), 101 deletions(-)]]>
              +        https://code.incremental.social/thepaperpilot/pages/commit/70ad2d0b28b2706e473fb5877d5e8652eb3eea83
              +        
              +        2024-06-26T00:00:00.000Z
              +        
              +        
              +
              +
              +Page
              +Changes
              +
              +
              +
              +commune2 +-
              +federated-identity3 +-
              +fedi-v2145 ++++++++++++++------------------------------
              +
              +]]>
              +    
                   
                       <![CDATA[ 2 files changed, 9 insertions(+), 11 deletions(-)]]>
                       https://code.incremental.social/thepaperpilot/pages/commit/06e718dee102c97ed97cdbf9b5e59e32bb6cec95
              @@ -357,11 +377,11 @@
               ]]>
                   
                   
              -        <![CDATA[ 47 files changed, 1226 insertions(+)]]>
              -        https://code.incremental.social/thepaperpilot/pages/commit/fe175090d3fc0cfa81754ec5b19a184005e31d8c
              -        
              -        2024-06-03T00:00:00.000Z
              -        
              +        <![CDATA[ 3 files changed, 48 insertions(+), 38 deletions(-)]]>
              +        https://code.incremental.social/thepaperpilot/pages/commit/f55b76ee790425e33432c56e398c1d76f8e2e1a6
              +        
              +        2024-06-06T00:00:00.000Z
              +        
                       
               
               
              @@ -370,53 +390,28 @@
               
               
               
              -activitypub13 ++
              -advent-incremental21 +++
              -atproto18 +++
              -babble-buds22 ++++
              -capture-the-citadel15 +++
              -chat-glue12 ++
              -chronological21 +++
              -cinny10 ++
              -commune33 +++++
              -decentralized28 ++++
              -dice-armor55 ++++++++
              -digital-gardens20 +++
              -federated-identity23 ++++
              -fedi-v295 ++++++++++++++
              -fediverse21 +++
              -forgejo10 ++
              -freeform-vs-chronological-dichotomy10 ++
              -freeform17 +++
              -game-dev-tree17 +++
              -garden-rss22 ++++
              -.../appeal-to-developers30 +++++
              -guide-to-incrementals/appeal-to-players60 +++++++++
              -guide-to-incrementals/defining-the-genre141 +++++++++++++++++++++
              -guide-to-incrementals27 ++++
              -.../navigating-criticism26 ++++
              -guide-to-incrementals/what-is-content52 ++++++++
              -incremental-social16 +++
              -kronos18 +++
              -logseq10 ++
              -matrix10 ++
              -mbin12 ++
              -my-personal-website10 ++
              -my-projects27 ++++
              -nostr13 ++
              -open-source12 ++
              -opti-speech37 ++++++
              -planar-pioneers15 +++
              -profectus24 ++++
              -social-media25 ++++
              -synapse10 ++
              -the-cozy-web16 +++
              -the-small-web58 +++++++++
              -this-knowledge-hub22 ++++
              -v-ecs25 ++++
              -vitepress10 ++
              -webrings25 ++++
              -weird12 ++
              +digital-gardens2 +-
              +fedi-v23 +-
              +the-small-web81 +++++++++++++++++++++++++++---------------------
              +
              +]]>
              +    
              +    
              +        <![CDATA[ 2 files changed, 9 insertions(+), 4 deletions(-)]]>
              +        https://code.incremental.social/thepaperpilot/pages/commit/d4d1e112feca180efdcc10b4465211fbbec4e6a5
              +        
              +        2024-06-27T00:00:00.000Z
              +        
              +        
              +
              +
              +Page
              +Changes
              +
              +
              +
              +fedi-v210 +++++++---
              +the-small-web3 ++-
               
               ]]>
                   
              @@ -493,45 +488,6 @@
               webrings2 +-
               weird2 +-
               
              -]]>
              -    
              -    
              -        <![CDATA[ 2 files changed, 9 insertions(+), 4 deletions(-)]]>
              -        https://code.incremental.social/thepaperpilot/pages/commit/d4d1e112feca180efdcc10b4465211fbbec4e6a5
              -        
              -        2024-06-27T00:00:00.000Z
              -        
              -        
              -
              -
              -Page
              -Changes
              -
              -
              -
              -fedi-v210 +++++++---
              -the-small-web3 ++-
              -
              -]]>
              -    
              -    
              -        <![CDATA[ 3 files changed, 49 insertions(+), 101 deletions(-)]]>
              -        https://code.incremental.social/thepaperpilot/pages/commit/70ad2d0b28b2706e473fb5877d5e8652eb3eea83
              -        
              -        2024-06-26T00:00:00.000Z
              -        
              -        
              -
              -
              -Page
              -Changes
              -
              -
              -
              -commune2 +-
              -federated-identity3 +-
              -fedi-v2145 ++++++++++++++------------------------------
              -
               ]]>
                   
                   
              @@ -568,11 +524,11 @@
               ]]>
                   
                   
              -        <![CDATA[ 3 files changed, 48 insertions(+), 38 deletions(-)]]>
              -        https://code.incremental.social/thepaperpilot/pages/commit/f55b76ee790425e33432c56e398c1d76f8e2e1a6
              -        
              -        2024-06-06T00:00:00.000Z
              -        
              +        <![CDATA[ 47 files changed, 1226 insertions(+)]]>
              +        https://code.incremental.social/thepaperpilot/pages/commit/fe175090d3fc0cfa81754ec5b19a184005e31d8c
              +        
              +        2024-06-03T00:00:00.000Z
              +        
                       
               
               
              @@ -581,9 +537,53 @@
               
               
               
              -digital-gardens2 +-
              -fedi-v23 +-
              -the-small-web81 +++++++++++++++++++++++++++---------------------
              +activitypub13 ++
              +advent-incremental21 +++
              +atproto18 +++
              +babble-buds22 ++++
              +capture-the-citadel15 +++
              +chat-glue12 ++
              +chronological21 +++
              +cinny10 ++
              +commune33 +++++
              +decentralized28 ++++
              +dice-armor55 ++++++++
              +digital-gardens20 +++
              +federated-identity23 ++++
              +fedi-v295 ++++++++++++++
              +fediverse21 +++
              +forgejo10 ++
              +freeform-vs-chronological-dichotomy10 ++
              +freeform17 +++
              +game-dev-tree17 +++
              +garden-rss22 ++++
              +.../appeal-to-developers30 +++++
              +guide-to-incrementals/appeal-to-players60 +++++++++
              +guide-to-incrementals/defining-the-genre141 +++++++++++++++++++++
              +guide-to-incrementals27 ++++
              +.../navigating-criticism26 ++++
              +guide-to-incrementals/what-is-content52 ++++++++
              +incremental-social16 +++
              +kronos18 +++
              +logseq10 ++
              +matrix10 ++
              +mbin12 ++
              +my-personal-website10 ++
              +my-projects27 ++++
              +nostr13 ++
              +open-source12 ++
              +opti-speech37 ++++++
              +planar-pioneers15 +++
              +profectus24 ++++
              +social-media25 ++++
              +synapse10 ++
              +the-cozy-web16 +++
              +the-small-web58 +++++++++
              +this-knowledge-hub22 ++++
              +v-ecs25 ++++
              +vitepress10 ++
              +webrings25 ++++
              +weird12 ++
               
               ]]>
                   
              diff --git a/changelog/index.html b/changelog/index.html
              index eafee7cd..ca30460e 100644
              --- a/changelog/index.html
              +++ b/changelog/index.html
              @@ -6,13 +6,13 @@
                   Site Changelog | The Paper Pilot
                   
                   
              -    
              +    
                   
              -    
              +    
                   
              -    
              -    
              -    
              +    
              +    
              +    
                   
                   
                   
              @@ -34,8 +34,8 @@
                   
                 
                 
              -    
              Skip to content

              Site Changelog

              This feed starts when I formatted the site to be a Digital Garden. If you'd like to look further into this site's history, check here!

              58 files changed, 79 insertions(+), 79 deletions(-)

              16 files changed, 24 insertions(+), 8 deletions(-)

              60 files changed, 513 insertions(+), 93 deletions(-)

              Pushed on
              PageChanges
              activitypub9 +++++++-
              advent-incremental9 +++++++-
              artificial-intelligence9 +++++++-
              atproto9 +++++++-
              babble-buds9 +++++++-
              capture-the-citadel11 +++++++--
              chat-glue9 +++++++-
              chronological9 +++++++-
              cinny9 +++++++-
              command-palettes9 +++++++-
              commune9 +++++++-
              davey-wreden9 +++++++-
              decentralized9 +++++++-
              dice-armor27 ++++++++++++++--------
              digital-gardens9 +++++++-
              federated-identity9 +++++++-
              fedi-v29 +++++++-
              fediverse9 +++++++-
              forgejo9 +++++++-
              freeform-vs-chronological-dichotomy9 +++++++-
              freeform9 +++++++-
              game-dev-tree9 +++++++-
              garden-rss9 +++++++-
              .../appeal-to-developers13 ++++++++---
              guide-to-incrementals/appeal-to-players13 ++++++++---
              guide-to-incrementals/defining-the-genre13 ++++++++---
              guide-to-incrementals9 +++++++-
              .../navigating-criticism13 ++++++++---
              guide-to-incrementals/what-is-content13 ++++++++---
              incremental-social9 +++++++-
              ivy-road9 +++++++-
              kronos9 +++++++-
              life-is-strange13 ++++++++---
              logseq9 +++++++-
              matrix9 +++++++-
              mbin9 +++++++-
              mtx9 +++++++-
              my-personal-website9 +++++++-
              my-projects9 +++++++-
              nostr9 +++++++-
              open-source9 +++++++-
              opti-speech17 ++++++++++----
              planar-pioneers9 +++++++-
              pre-order-bonuses9 +++++++-
              premium-currency9 +++++++-
              profectus9 +++++++-
              social-media9 +++++++-
              synapse9 +++++++-
              the-beginner-s-guide9 +++++++-
              the-cozy-web9 +++++++-
              the-indieweb/amplification13 ++++++++---
              the-indieweb/signature-blocks13 ++++++++---
              the-small-web9 +++++++-
              this-knowledge-hub9 +++++++-
              v-ecs15 ++++++++----
              video-game-monetization9 +++++++-
              vitepress9 +++++++-
              wanderstop9 +++++++-
              webrings9 +++++++-
              weird9 +++++++-

              20 files changed, 274 insertions(+), 16 deletions(-)

              Pushed on
              PageChanges
              artificial-intelligence28 ++++++++++++++++
              command-palettes25 ++++++++++++++
              fedi-v215 +++++----
              fediverse2 +-
              guide-to-incrementals2 ++
              incremental-social2 +-
              life-is-strange60 ++++++++++++++++++++++++++++++++++
              logseq2 +-
              mtx13 ++++++++
              my-personal-website2 +-
              my-projects2 ++
              pre-order-bonuses28 ++++++++++++++++
              premium-currency19 +++++++++++
              social-media2 +-
              the-beginner-s-guide2 +-
              the-indieweb/amplification14 ++++++++
              the-indieweb/signature-blocks10 ++++++
              the-small-web8 +++--
              video-game-monetization43 ++++++++++++++++++++++++
              weird11 +++++--

              47 files changed, 124 insertions(+), 13 deletions(-)

              47 files changed, 1226 insertions(+)

              - +
              Skip to content

              Site Changelog

              This feed starts when I formatted the site to be a Digital Garden. If you'd like to look further into this site's history, check here!

              58 files changed, 79 insertions(+), 79 deletions(-)

              16 files changed, 24 insertions(+), 8 deletions(-)

              60 files changed, 513 insertions(+), 93 deletions(-)

              Pushed on
              PageChanges
              activitypub9 +++++++-
              advent-incremental9 +++++++-
              artificial-intelligence9 +++++++-
              atproto9 +++++++-
              babble-buds9 +++++++-
              capture-the-citadel11 +++++++--
              chat-glue9 +++++++-
              chronological9 +++++++-
              cinny9 +++++++-
              command-palettes9 +++++++-
              commune9 +++++++-
              davey-wreden9 +++++++-
              decentralized9 +++++++-
              dice-armor27 ++++++++++++++--------
              digital-gardens9 +++++++-
              federated-identity9 +++++++-
              fedi-v29 +++++++-
              fediverse9 +++++++-
              forgejo9 +++++++-
              freeform-vs-chronological-dichotomy9 +++++++-
              freeform9 +++++++-
              game-dev-tree9 +++++++-
              garden-rss9 +++++++-
              .../appeal-to-developers13 ++++++++---
              guide-to-incrementals/appeal-to-players13 ++++++++---
              guide-to-incrementals/defining-the-genre13 ++++++++---
              guide-to-incrementals9 +++++++-
              .../navigating-criticism13 ++++++++---
              guide-to-incrementals/what-is-content13 ++++++++---
              incremental-social9 +++++++-
              ivy-road9 +++++++-
              kronos9 +++++++-
              life-is-strange13 ++++++++---
              logseq9 +++++++-
              matrix9 +++++++-
              mbin9 +++++++-
              mtx9 +++++++-
              my-personal-website9 +++++++-
              my-projects9 +++++++-
              nostr9 +++++++-
              open-source9 +++++++-
              opti-speech17 ++++++++++----
              planar-pioneers9 +++++++-
              pre-order-bonuses9 +++++++-
              premium-currency9 +++++++-
              profectus9 +++++++-
              social-media9 +++++++-
              synapse9 +++++++-
              the-beginner-s-guide9 +++++++-
              the-cozy-web9 +++++++-
              the-indieweb/amplification13 ++++++++---
              the-indieweb/signature-blocks13 ++++++++---
              the-small-web9 +++++++-
              this-knowledge-hub9 +++++++-
              v-ecs15 ++++++++----
              video-game-monetization9 +++++++-
              vitepress9 +++++++-
              wanderstop9 +++++++-
              webrings9 +++++++-
              weird9 +++++++-

              20 files changed, 274 insertions(+), 16 deletions(-)

              Pushed on
              PageChanges
              artificial-intelligence28 ++++++++++++++++
              command-palettes25 ++++++++++++++
              fedi-v215 +++++----
              fediverse2 +-
              guide-to-incrementals2 ++
              incremental-social2 +-
              life-is-strange60 ++++++++++++++++++++++++++++++++++
              logseq2 +-
              mtx13 ++++++++
              my-personal-website2 +-
              my-projects2 ++
              pre-order-bonuses28 ++++++++++++++++
              premium-currency19 +++++++++++
              social-media2 +-
              the-beginner-s-guide2 +-
              the-indieweb/amplification14 ++++++++
              the-indieweb/signature-blocks10 ++++++
              the-small-web8 +++--
              video-game-monetization43 ++++++++++++++++++++++++
              weird11 +++++--

              47 files changed, 124 insertions(+), 13 deletions(-)

              47 files changed, 1226 insertions(+)

              + \ No newline at end of file diff --git a/changelog/json b/changelog/json index 7a9c2d4a..7eb2b0f2 100644 --- a/changelog/json +++ b/changelog/json @@ -9,6 +9,14 @@ "url": "https://www.thepaperpilot.org/" }, "items": [ + { + "id": "https://code.incremental.social/thepaperpilot/pages/commit/70ad2d0b28b2706e473fb5877d5e8652eb3eea83", + "content_html": "\n\n\n\n\n\n\n\n\n\n\n\n
              PageChanges
              commune2 +-
              federated-identity3 +-
              fedi-v2145 ++++++++++++++------------------------------
              ", + "url": "https://code.incremental.social/thepaperpilot/pages/commit/70ad2d0b28b2706e473fb5877d5e8652eb3eea83", + "title": " 3 files changed, 49 insertions(+), 101 deletions(-)", + "summary": " 3 files changed, 49 insertions(+), 101 deletions(-)", + "date_modified": "2024-06-26T00:00:00.000Z" + }, { "id": "https://code.incremental.social/thepaperpilot/pages/commit/06e718dee102c97ed97cdbf9b5e59e32bb6cec95", "content_html": "\n\n\n\n\n\n\n\n\n\n\n
              PageChanges
              guide-to-incrementals/appeal-to-players16 ++++++++--------
              guide-to-incrementals4 +---
              ", @@ -114,20 +122,12 @@ "date_modified": "2024-06-09T00:00:00.000Z" }, { - "id": "https://code.incremental.social/thepaperpilot/pages/commit/fe175090d3fc0cfa81754ec5b19a184005e31d8c", - "content_html": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
              PageChanges
              activitypub13 ++
              advent-incremental21 +++
              atproto18 +++
              babble-buds22 ++++
              capture-the-citadel15 +++
              chat-glue12 ++
              chronological21 +++
              cinny10 ++
              commune33 +++++
              decentralized28 ++++
              dice-armor55 ++++++++
              digital-gardens20 +++
              federated-identity23 ++++
              fedi-v295 ++++++++++++++
              fediverse21 +++
              forgejo10 ++
              freeform-vs-chronological-dichotomy10 ++
              freeform17 +++
              game-dev-tree17 +++
              garden-rss22 ++++
              .../appeal-to-developers30 +++++
              guide-to-incrementals/appeal-to-players60 +++++++++
              guide-to-incrementals/defining-the-genre141 +++++++++++++++++++++
              guide-to-incrementals27 ++++
              .../navigating-criticism26 ++++
              guide-to-incrementals/what-is-content52 ++++++++
              incremental-social16 +++
              kronos18 +++
              logseq10 ++
              matrix10 ++
              mbin12 ++
              my-personal-website10 ++
              my-projects27 ++++
              nostr13 ++
              open-source12 ++
              opti-speech37 ++++++
              planar-pioneers15 +++
              profectus24 ++++
              social-media25 ++++
              synapse10 ++
              the-cozy-web16 +++
              the-small-web58 +++++++++
              this-knowledge-hub22 ++++
              v-ecs25 ++++
              vitepress10 ++
              webrings25 ++++
              weird12 ++
              ", - "url": "https://code.incremental.social/thepaperpilot/pages/commit/fe175090d3fc0cfa81754ec5b19a184005e31d8c", - "title": " 47 files changed, 1226 insertions(+)", - "summary": " 47 files changed, 1226 insertions(+)", - "date_modified": "2024-06-03T00:00:00.000Z" - }, - { - "id": "https://code.incremental.social/thepaperpilot/pages/commit/5ac040e4c90a8c29635aec2017065e2dfd7e5a83", - "content_html": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
              PageChanges
              activitypub4 ++--
              advent-incremental2 +-
              artificial-intelligence2 +-
              atproto4 ++--
              babble-buds2 +-
              capture-the-citadel2 +-
              chat-glue2 +-
              chronological2 +-
              cinny2 +-
              commune2 +-
              davey-wreden4 ++--
              decentralized4 ++--
              dice-armor4 ++--
              digital-gardens2 +-
              federated-identity4 ++--
              fedi-v22 +-
              fediverse4 ++--
              forgejo2 +-
              freeform-vs-chronological-dichotomy2 +-
              freeform2 +-
              game-dev-tree2 +-
              garden-rss2 +-
              guide-to-incrementals/appeal-to-developers4 ++--
              guide-to-incrementals/appeal-to-players4 ++--
              guide-to-incrementals/defining-the-genre4 ++--
              guide-to-incrementals2 +-
              guide-to-incrementals/navigating-criticism4 ++--
              guide-to-incrementals/what-is-content4 ++--
              incremental-social4 ++--
              ivy-road4 ++--
              kronos4 ++--
              logseq2 +-
              matrix2 +-
              mbin2 +-
              mtx2 +-
              my-personal-website2 +-
              my-projects2 +-
              nostr4 ++--
              open-source2 +-
              opti-speech2 +-
              planar-pioneers2 +-
              pre-order-bonuses2 +-
              premium-currency2 +-
              profectus6 +++---
              social-media2 +-
              synapse2 +-
              the-beginner-s-guide4 ++--
              the-cozy-web2 +-
              the-indieweb/amplification4 ++--
              the-indieweb/signature-blocks4 ++--
              the-small-web2 +-
              this-knowledge-hub2 +-
              v-ecs2 +-
              video-game-monetization2 +-
              vitepress2 +-
              wanderstop2 +-
              webrings2 +-
              weird2 +-
              ", - "url": "https://code.incremental.social/thepaperpilot/pages/commit/5ac040e4c90a8c29635aec2017065e2dfd7e5a83", - "title": " 58 files changed, 79 insertions(+), 79 deletions(-)", - "summary": " 58 files changed, 79 insertions(+), 79 deletions(-)", - "date_modified": "2024-06-26T00:00:00.000Z" + "id": "https://code.incremental.social/thepaperpilot/pages/commit/f55b76ee790425e33432c56e398c1d76f8e2e1a6", + "content_html": "\n\n\n\n\n\n\n\n\n\n\n\n
              PageChanges
              digital-gardens2 +-
              fedi-v23 +-
              the-small-web81 +++++++++++++++++++++++++++---------------------
              ", + "url": "https://code.incremental.social/thepaperpilot/pages/commit/f55b76ee790425e33432c56e398c1d76f8e2e1a6", + "title": " 3 files changed, 48 insertions(+), 38 deletions(-)", + "summary": " 3 files changed, 48 insertions(+), 38 deletions(-)", + "date_modified": "2024-06-06T00:00:00.000Z" }, { "id": "https://code.incremental.social/thepaperpilot/pages/commit/d4d1e112feca180efdcc10b4465211fbbec4e6a5", @@ -138,11 +138,11 @@ "date_modified": "2024-06-27T00:00:00.000Z" }, { - "id": "https://code.incremental.social/thepaperpilot/pages/commit/70ad2d0b28b2706e473fb5877d5e8652eb3eea83", - "content_html": "\n\n\n\n\n\n\n\n\n\n\n\n
              PageChanges
              commune2 +-
              federated-identity3 +-
              fedi-v2145 ++++++++++++++------------------------------
              ", - "url": "https://code.incremental.social/thepaperpilot/pages/commit/70ad2d0b28b2706e473fb5877d5e8652eb3eea83", - "title": " 3 files changed, 49 insertions(+), 101 deletions(-)", - "summary": " 3 files changed, 49 insertions(+), 101 deletions(-)", + "id": "https://code.incremental.social/thepaperpilot/pages/commit/5ac040e4c90a8c29635aec2017065e2dfd7e5a83", + "content_html": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
              PageChanges
              activitypub4 ++--
              advent-incremental2 +-
              artificial-intelligence2 +-
              atproto4 ++--
              babble-buds2 +-
              capture-the-citadel2 +-
              chat-glue2 +-
              chronological2 +-
              cinny2 +-
              commune2 +-
              davey-wreden4 ++--
              decentralized4 ++--
              dice-armor4 ++--
              digital-gardens2 +-
              federated-identity4 ++--
              fedi-v22 +-
              fediverse4 ++--
              forgejo2 +-
              freeform-vs-chronological-dichotomy2 +-
              freeform2 +-
              game-dev-tree2 +-
              garden-rss2 +-
              guide-to-incrementals/appeal-to-developers4 ++--
              guide-to-incrementals/appeal-to-players4 ++--
              guide-to-incrementals/defining-the-genre4 ++--
              guide-to-incrementals2 +-
              guide-to-incrementals/navigating-criticism4 ++--
              guide-to-incrementals/what-is-content4 ++--
              incremental-social4 ++--
              ivy-road4 ++--
              kronos4 ++--
              logseq2 +-
              matrix2 +-
              mbin2 +-
              mtx2 +-
              my-personal-website2 +-
              my-projects2 +-
              nostr4 ++--
              open-source2 +-
              opti-speech2 +-
              planar-pioneers2 +-
              pre-order-bonuses2 +-
              premium-currency2 +-
              profectus6 +++---
              social-media2 +-
              synapse2 +-
              the-beginner-s-guide4 ++--
              the-cozy-web2 +-
              the-indieweb/amplification4 ++--
              the-indieweb/signature-blocks4 ++--
              the-small-web2 +-
              this-knowledge-hub2 +-
              v-ecs2 +-
              video-game-monetization2 +-
              vitepress2 +-
              wanderstop2 +-
              webrings2 +-
              weird2 +-
              ", + "url": "https://code.incremental.social/thepaperpilot/pages/commit/5ac040e4c90a8c29635aec2017065e2dfd7e5a83", + "title": " 58 files changed, 79 insertions(+), 79 deletions(-)", + "summary": " 58 files changed, 79 insertions(+), 79 deletions(-)", "date_modified": "2024-06-26T00:00:00.000Z" }, { @@ -154,12 +154,12 @@ "date_modified": "2024-06-26T00:00:00.000Z" }, { - "id": "https://code.incremental.social/thepaperpilot/pages/commit/f55b76ee790425e33432c56e398c1d76f8e2e1a6", - "content_html": "\n\n\n\n\n\n\n\n\n\n\n\n
              PageChanges
              digital-gardens2 +-
              fedi-v23 +-
              the-small-web81 +++++++++++++++++++++++++++---------------------
              ", - "url": "https://code.incremental.social/thepaperpilot/pages/commit/f55b76ee790425e33432c56e398c1d76f8e2e1a6", - "title": " 3 files changed, 48 insertions(+), 38 deletions(-)", - "summary": " 3 files changed, 48 insertions(+), 38 deletions(-)", - "date_modified": "2024-06-06T00:00:00.000Z" + "id": "https://code.incremental.social/thepaperpilot/pages/commit/fe175090d3fc0cfa81754ec5b19a184005e31d8c", + "content_html": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
              PageChanges
              activitypub13 ++
              advent-incremental21 +++
              atproto18 +++
              babble-buds22 ++++
              capture-the-citadel15 +++
              chat-glue12 ++
              chronological21 +++
              cinny10 ++
              commune33 +++++
              decentralized28 ++++
              dice-armor55 ++++++++
              digital-gardens20 +++
              federated-identity23 ++++
              fedi-v295 ++++++++++++++
              fediverse21 +++
              forgejo10 ++
              freeform-vs-chronological-dichotomy10 ++
              freeform17 +++
              game-dev-tree17 +++
              garden-rss22 ++++
              .../appeal-to-developers30 +++++
              guide-to-incrementals/appeal-to-players60 +++++++++
              guide-to-incrementals/defining-the-genre141 +++++++++++++++++++++
              guide-to-incrementals27 ++++
              .../navigating-criticism26 ++++
              guide-to-incrementals/what-is-content52 ++++++++
              incremental-social16 +++
              kronos18 +++
              logseq10 ++
              matrix10 ++
              mbin12 ++
              my-personal-website10 ++
              my-projects27 ++++
              nostr13 ++
              open-source12 ++
              opti-speech37 ++++++
              planar-pioneers15 +++
              profectus24 ++++
              social-media25 ++++
              synapse10 ++
              the-cozy-web16 +++
              the-small-web58 +++++++++
              this-knowledge-hub22 ++++
              v-ecs25 ++++
              vitepress10 ++
              webrings25 ++++
              weird12 ++
              ", + "url": "https://code.incremental.social/thepaperpilot/pages/commit/fe175090d3fc0cfa81754ec5b19a184005e31d8c", + "title": " 47 files changed, 1226 insertions(+)", + "summary": " 47 files changed, 1226 insertions(+)", + "date_modified": "2024-06-03T00:00:00.000Z" }, { "id": "https://code.incremental.social/thepaperpilot/pages/commit/91e757f7ccbeb570d900aaa5b49e6e4874d19b2f", diff --git a/changelog/rss b/changelog/rss index 801cb8ea..4ef95b26 100644 --- a/changelog/rss +++ b/changelog/rss @@ -4,12 +4,32 @@ The Paper Pilot's Digital Garden Changelog https://www.thepaperpilot.org/changelog/ A feed of updates made to my digital garden! - Thu, 27 Jun 2024 13:30:09 GMT + Fri, 28 Jun 2024 04:15:28 GMT https://validator.w3.org/feed/docs/rss2.html https://github.com/jpmonette/feed en All rights reserved 2024, The Paper Pilot + + <![CDATA[ 3 files changed, 49 insertions(+), 101 deletions(-)]]> + https://code.incremental.social/thepaperpilot/pages/commit/70ad2d0b28b2706e473fb5877d5e8652eb3eea83 + https://code.incremental.social/thepaperpilot/pages/commit/70ad2d0b28b2706e473fb5877d5e8652eb3eea83 + Wed, 26 Jun 2024 00:00:00 GMT + + + + +Page +Changes + + + +commune2 +- +federated-identity3 +- +fedi-v2145 ++++++++++++++------------------------------ + +]]> + <![CDATA[ 2 files changed, 9 insertions(+), 11 deletions(-)]]> https://code.incremental.social/thepaperpilot/pages/commit/06e718dee102c97ed97cdbf9b5e59e32bb6cec95 @@ -354,11 +374,11 @@ ]]> - <![CDATA[ 47 files changed, 1226 insertions(+)]]> - https://code.incremental.social/thepaperpilot/pages/commit/fe175090d3fc0cfa81754ec5b19a184005e31d8c - https://code.incremental.social/thepaperpilot/pages/commit/fe175090d3fc0cfa81754ec5b19a184005e31d8c - Mon, 03 Jun 2024 00:00:00 GMT - + <![CDATA[ 3 files changed, 48 insertions(+), 38 deletions(-)]]> + https://code.incremental.social/thepaperpilot/pages/commit/f55b76ee790425e33432c56e398c1d76f8e2e1a6 + https://code.incremental.social/thepaperpilot/pages/commit/f55b76ee790425e33432c56e398c1d76f8e2e1a6 + Thu, 06 Jun 2024 00:00:00 GMT + @@ -367,53 +387,28 @@ -activitypub13 ++ -advent-incremental21 +++ -atproto18 +++ -babble-buds22 ++++ -capture-the-citadel15 +++ -chat-glue12 ++ -chronological21 +++ -cinny10 ++ -commune33 +++++ -decentralized28 ++++ -dice-armor55 ++++++++ -digital-gardens20 +++ -federated-identity23 ++++ -fedi-v295 ++++++++++++++ -fediverse21 +++ -forgejo10 ++ -freeform-vs-chronological-dichotomy10 ++ -freeform17 +++ -game-dev-tree17 +++ -garden-rss22 ++++ -.../appeal-to-developers30 +++++ -guide-to-incrementals/appeal-to-players60 +++++++++ -guide-to-incrementals/defining-the-genre141 +++++++++++++++++++++ -guide-to-incrementals27 ++++ -.../navigating-criticism26 ++++ -guide-to-incrementals/what-is-content52 ++++++++ -incremental-social16 +++ -kronos18 +++ -logseq10 ++ -matrix10 ++ -mbin12 ++ -my-personal-website10 ++ -my-projects27 ++++ -nostr13 ++ -open-source12 ++ -opti-speech37 ++++++ -planar-pioneers15 +++ -profectus24 ++++ -social-media25 ++++ -synapse10 ++ -the-cozy-web16 +++ -the-small-web58 +++++++++ -this-knowledge-hub22 ++++ -v-ecs25 ++++ -vitepress10 ++ -webrings25 ++++ -weird12 ++ +digital-gardens2 +- +fedi-v23 +- +the-small-web81 +++++++++++++++++++++++++++--------------------- + +]]> + + + <![CDATA[ 2 files changed, 9 insertions(+), 4 deletions(-)]]> + https://code.incremental.social/thepaperpilot/pages/commit/d4d1e112feca180efdcc10b4465211fbbec4e6a5 + https://code.incremental.social/thepaperpilot/pages/commit/d4d1e112feca180efdcc10b4465211fbbec4e6a5 + Thu, 27 Jun 2024 00:00:00 GMT + + + + +Page +Changes + + + +fedi-v210 +++++++--- +the-small-web3 ++- ]]> @@ -490,45 +485,6 @@ webrings2 +- weird2 +- -]]> - - - <![CDATA[ 2 files changed, 9 insertions(+), 4 deletions(-)]]> - https://code.incremental.social/thepaperpilot/pages/commit/d4d1e112feca180efdcc10b4465211fbbec4e6a5 - https://code.incremental.social/thepaperpilot/pages/commit/d4d1e112feca180efdcc10b4465211fbbec4e6a5 - Thu, 27 Jun 2024 00:00:00 GMT - - - - -Page -Changes - - - -fedi-v210 +++++++--- -the-small-web3 ++- - -]]> - - - <![CDATA[ 3 files changed, 49 insertions(+), 101 deletions(-)]]> - https://code.incremental.social/thepaperpilot/pages/commit/70ad2d0b28b2706e473fb5877d5e8652eb3eea83 - https://code.incremental.social/thepaperpilot/pages/commit/70ad2d0b28b2706e473fb5877d5e8652eb3eea83 - Wed, 26 Jun 2024 00:00:00 GMT - - - - -Page -Changes - - - -commune2 +- -federated-identity3 +- -fedi-v2145 ++++++++++++++------------------------------ - ]]> @@ -565,11 +521,11 @@ ]]> - <![CDATA[ 3 files changed, 48 insertions(+), 38 deletions(-)]]> - https://code.incremental.social/thepaperpilot/pages/commit/f55b76ee790425e33432c56e398c1d76f8e2e1a6 - https://code.incremental.social/thepaperpilot/pages/commit/f55b76ee790425e33432c56e398c1d76f8e2e1a6 - Thu, 06 Jun 2024 00:00:00 GMT - + <![CDATA[ 47 files changed, 1226 insertions(+)]]> + https://code.incremental.social/thepaperpilot/pages/commit/fe175090d3fc0cfa81754ec5b19a184005e31d8c + https://code.incremental.social/thepaperpilot/pages/commit/fe175090d3fc0cfa81754ec5b19a184005e31d8c + Mon, 03 Jun 2024 00:00:00 GMT + @@ -578,9 +534,53 @@ -digital-gardens2 +- -fedi-v23 +- -the-small-web81 +++++++++++++++++++++++++++--------------------- +activitypub13 ++ +advent-incremental21 +++ +atproto18 +++ +babble-buds22 ++++ +capture-the-citadel15 +++ +chat-glue12 ++ +chronological21 +++ +cinny10 ++ +commune33 +++++ +decentralized28 ++++ +dice-armor55 ++++++++ +digital-gardens20 +++ +federated-identity23 ++++ +fedi-v295 ++++++++++++++ +fediverse21 +++ +forgejo10 ++ +freeform-vs-chronological-dichotomy10 ++ +freeform17 +++ +game-dev-tree17 +++ +garden-rss22 ++++ +.../appeal-to-developers30 +++++ +guide-to-incrementals/appeal-to-players60 +++++++++ +guide-to-incrementals/defining-the-genre141 +++++++++++++++++++++ +guide-to-incrementals27 ++++ +.../navigating-criticism26 ++++ +guide-to-incrementals/what-is-content52 ++++++++ +incremental-social16 +++ +kronos18 +++ +logseq10 ++ +matrix10 ++ +mbin12 ++ +my-personal-website10 ++ +my-projects27 ++++ +nostr13 ++ +open-source12 ++ +opti-speech37 ++++++ +planar-pioneers15 +++ +profectus24 ++++ +social-media25 ++++ +synapse10 ++ +the-cozy-web16 +++ +the-small-web58 +++++++++ +this-knowledge-hub22 ++++ +v-ecs25 ++++ +vitepress10 ++ +webrings25 ++++ +weird12 ++ ]]> diff --git a/garden/activitypub/index.html b/garden/activitypub/index.html index b6db4d99..6ed836f8 100644 --- a/garden/activitypub/index.html +++ b/garden/activitypub/index.html @@ -6,14 +6,14 @@ ActivityPub | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              ActivityPub

              8 words, ~0 minute read. Planted +

              Skip to content

              ActivityPub

              8 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:Fediverse
              Tags:Decentralized

              ActivityPub is a protocol for Federated Social Media

              - +.


              Referenced by:Fediverse
              Tags:Decentralized

              ActivityPub is a protocol for Federated Social Media

              + \ No newline at end of file diff --git a/garden/advent-incremental/index.html b/garden/advent-incremental/index.html index 247df6d6..0a2b0bb8 100644 --- a/garden/advent-incremental/index.html +++ b/garden/advent-incremental/index.html @@ -6,14 +6,14 @@ Advent Incremental | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Advent Incremental

              104 words, ~1 minute read. Planted +

              Skip to content

              Advent Incremental

              104 words, ~1 minute read. Planted . Last tended to -.


              Tags:My ProjectsProfectus

              Play it here!

              An Open Source game made in Profectus over the course of 1 month by myself and other devs I know in the Incremental Games community!

              I had the idea of an advent-style game that unlocked new pieces of content every real-life day a couple days before December started.

              This was one of the most hectic months of my life!

              I'm super happy with how it turned out. It ended up being way more ambitious than I anticipated but the end result is super large and awesome!

              The TV Tropes page on this game mentions some of the cool things about this game

              - +.


              Tags:My ProjectsProfectus

              Play it here!

              An Open Source game made in Profectus over the course of 1 month by myself and other devs I know in the Incremental Games community!

              I had the idea of an advent-style game that unlocked new pieces of content every real-life day a couple days before December started.

              This was one of the most hectic months of my life!

              I'm super happy with how it turned out. It ended up being way more ambitious than I anticipated but the end result is super large and awesome!

              The TV Tropes page on this game mentions some of the cool things about this game

              + \ No newline at end of file diff --git a/garden/artificial-intelligence/index.html b/garden/artificial-intelligence/index.html index 95b3cb91..f8f1d25a 100644 --- a/garden/artificial-intelligence/index.html +++ b/garden/artificial-intelligence/index.html @@ -6,14 +6,14 @@ Artificial Intelligence | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Artificial Intelligence

              101 words, ~1 minute read. Planted +

              Skip to content

              Artificial Intelligence

              101 words, ~1 minute read. Planted . Last tended to -.


              Referenced by:Command Palettes

              Catch all term that refers to many different things

              Generative AI

              • Models trained on large amounts of existing human made content in order to produce more of that content
              • Copyright concerns over how training data is obtained
              • Common Examples

              Human + AI cooperation

              - +.


              Referenced by:Command Palettes

              Catch all term that refers to many different things

              Generative AI

              • Models trained on large amounts of existing human made content in order to produce more of that content
              • Copyright concerns over how training data is obtained
              • Common Examples

              Human + AI cooperation

              + \ No newline at end of file diff --git a/garden/atproto/index.html b/garden/atproto/index.html index 7c253206..988566fc 100644 --- a/garden/atproto/index.html +++ b/garden/atproto/index.html @@ -6,14 +6,14 @@ ATProto | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              ATProto

              31 words, ~0 minute read. Planted +

              Skip to content

              ATProto

              31 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:Fediverse
              Tags:Decentralized

              The AT Protocol is a protocol for Federated Social Media

              Currently only used by Bluesky

              In comparison to other Fediverse protocols, ATProto is designed for a small number of large instances

              - +.


              Referenced by:Fediverse
              Tags:Decentralized

              The AT Protocol is a protocol for Federated Social Media

              Currently only used by Bluesky

              In comparison to other Fediverse protocols, ATProto is designed for a small number of large instances

              + \ No newline at end of file diff --git a/garden/babble-buds/index.html b/garden/babble-buds/index.html index d4e6e44d..c5266e88 100644 --- a/garden/babble-buds/index.html +++ b/garden/babble-buds/index.html @@ -6,14 +6,14 @@ Babble Buds | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Babble Buds

              113 words, ~1 minute read. Planted +

              Skip to content

              Babble Buds

              113 words, ~1 minute read. Planted . Last tended to -.


              Tags:My Projects

              Babble Buds is a tool for creating puppets and interacting with puppets controlled by others on a shared stage

              Note: I need to move the website off replit because of their monetization strategy changing. In the meantime, you can check it out from its github repository

              Inspired by Puppet Pals by Robert Moran

              Intended for use in RPG Campaigns

              The renderer was separated into its own project, babble.js, so it could be used for stuff like cutscenes

              I ported the engine to C# and used it for the cutscenes in Dice Armor

              • I don't believe I ever separated it out into its own project, but you can find the code here
              - +.


              Tags:My Projects

              Babble Buds is a tool for creating puppets and interacting with puppets controlled by others on a shared stage

              Note: I need to move the website off replit because of their monetization strategy changing. In the meantime, you can check it out from its github repository

              Inspired by Puppet Pals by Robert Moran

              Intended for use in RPG Campaigns

              The renderer was separated into its own project, babble.js, so it could be used for stuff like cutscenes

              I ported the engine to C# and used it for the cutscenes in Dice Armor

              • I don't believe I ever separated it out into its own project, but you can find the code here
              + \ No newline at end of file diff --git a/garden/capture-the-citadel/index.html b/garden/capture-the-citadel/index.html index bb3d965f..79e9a7c6 100644 --- a/garden/capture-the-citadel/index.html +++ b/garden/capture-the-citadel/index.html @@ -6,14 +6,14 @@ Capture the Citadel | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Capture the Citadel

              39 words, ~0 minute read. Planted +

              Skip to content

              Capture the Citadel

              39 words, ~0 minute read. Planted . Last tended to -.


              Tags:My Projects

              A 3D VR re-envisioning of a Slay the Spire-style game by Anthony Lawn and Grant Barbee for their VR class in college's final project.

              For more details, visit Grant's page on the game.

              - +.


              Tags:My Projects

              A 3D VR re-envisioning of a Slay the Spire-style game by Anthony Lawn and Grant Barbee for their VR class in college's final project.

              For more details, visit Grant's page on the game.

              + \ No newline at end of file diff --git a/garden/chat-glue/index.html b/garden/chat-glue/index.html index f20bae4b..9453c741 100644 --- a/garden/chat-glue/index.html +++ b/garden/chat-glue/index.html @@ -6,14 +6,14 @@ Chat Glue | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Chat Glue

              23 words, ~0 minute read. Planted +

              Skip to content

              Chat Glue

              23 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:CommuneMy Personal WebsiteThe Small Web

              A theoretical chat system designed to solve the problems of transcribing branching conversations into linear timelines.

              Defined by the Chatting with Glue comic.

              - +.


              Referenced by:CommuneMy Personal WebsiteThe Small Web

              A theoretical chat system designed to solve the problems of transcribing branching conversations into linear timelines.

              Defined by the Chatting with Glue comic.

              + \ No newline at end of file diff --git a/garden/chronological/index.html b/garden/chronological/index.html index 2a70e202..27e32219 100644 --- a/garden/chronological/index.html +++ b/garden/chronological/index.html @@ -6,14 +6,14 @@ Chronological | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Chronological

              73 words, ~0 minute read. Planted +

              Skip to content

              Chronological

              73 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:Digital GardensFreeform vs Chronological Dichotomy

              A collection of information that is tied to its creation or edit date

              Part of the Freeform vs Chronological Dichotomy

              Anything with a "timeline" or "feed" is considered chronological

              • Even if there's algorithmic sortings that take things other than creation or edit date into account!

              Chronological displays are less suitable as stores of knowledge (Digital Gardens)

              Social media overuses timelines and feeds

              RSS feeds work really well with this form of content

              - +.


              Referenced by:Digital GardensFreeform vs Chronological Dichotomy

              A collection of information that is tied to its creation or edit date

              Part of the Freeform vs Chronological Dichotomy

              Anything with a "timeline" or "feed" is considered chronological

              • Even if there's algorithmic sortings that take things other than creation or edit date into account!

              Chronological displays are less suitable as stores of knowledge (Digital Gardens)

              Social media overuses timelines and feeds

              RSS feeds work really well with this form of content

              + \ No newline at end of file diff --git a/garden/cinny/index.html b/garden/cinny/index.html index 2e34d9e8..85a3641f 100644 --- a/garden/cinny/index.html +++ b/garden/cinny/index.html @@ -6,14 +6,14 @@ Cinny | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Cinny

              3 words, ~0 minute read. Planted +

              Skip to content

              Cinny

              3 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:Incremental Social

              Cinny is an Open Source web client for the Matrix messaging protocol

              - +.


              Referenced by:Incremental Social

              Cinny is an Open Source web client for the Matrix messaging protocol

              + \ No newline at end of file diff --git a/garden/command-palettes/index.html b/garden/command-palettes/index.html index 16f6554d..eaf77701 100644 --- a/garden/command-palettes/index.html +++ b/garden/command-palettes/index.html @@ -6,14 +6,14 @@ Command Palettes | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Command Palettes

              117 words, ~1 minute read. Planted +

              Skip to content

              Command Palettes

              117 words, ~1 minute read. Planted . Last tended to -.


              Command palettes are a design pattern where apps expose functionality through a search bar

              Typing what you want is almost certainly easier and faster than finding the action in some submenu or remembering an arcane hotkey

              • Especially with fuzzy search that also looks through descriptions of actions
              • Command palettes scale very well with large amounts of actions

              Artificial Intelligence will make command palettes increasingly powerful

              • Eventually these may become conversational interfaces

              Maggie Appleton discusses this pattern in her article on Command K Bars

              • The name comes from the fact many apps use the ctrl/cmd k shortcut to open the command palette

              Many softwares I use have some form of command palette

              • Linear
              • Logseq
              • Visual Studio Code
              - +.


              Command palettes are a design pattern where apps expose functionality through a search bar

              Typing what you want is almost certainly easier and faster than finding the action in some submenu or remembering an arcane hotkey

              • Especially with fuzzy search that also looks through descriptions of actions
              • Command palettes scale very well with large amounts of actions

              Artificial Intelligence will make command palettes increasingly powerful

              • Eventually these may become conversational interfaces

              Maggie Appleton discusses this pattern in her article on Command K Bars

              • The name comes from the fact many apps use the ctrl/cmd k shortcut to open the command palette

              Many softwares I use have some form of command palette

              • Linear
              • Logseq
              • Visual Studio Code
              + \ No newline at end of file diff --git a/garden/commune/index.html b/garden/commune/index.html index 4fd56825..7e557b30 100644 --- a/garden/commune/index.html +++ b/garden/commune/index.html @@ -6,14 +6,14 @@ Commune | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Commune

              144 words, ~1 minute read. Planted +

              Skip to content

              Commune

              144 words, ~1 minute read. Planted . Last tended to -.


              Referenced by:Federated IdentityMy Personal Website/nowWebringsWeird

              An Open Source Matrix web client built to be better for communities than anything else out there

              • Currently in development
              • Exposes certain channels such that they are web indexable
              • Will include features like Chat Glue and communal Digital Gardens

              Created by Erlend Sogge Heggen, a ex-employee from Discourse

              • Maintains the Commune Blog with great write ups on the issues of the modern web, social media, etc. and how they can be improved (by Commune or related projects)
              • Also maintains a Personal Blog about similar topics

              The Commune community is very interested in various topics and how they can relate together:

              Related projects:

              • @laxla@tech.lgbt is creating Gimli, a federated discord alternative
                • Built on ActivityPub
                • "Guild-based" in ways matrix is not?
                • Will integrate with F3 as well
                • Wants to handle blogging as well
                • Certainly seems similar to Commune's message gardening concept
              - +.


              Referenced by:Federated IdentityMy Personal Website/nowWebringsWeird

              An Open Source Matrix web client built to be better for communities than anything else out there

              • Currently in development
              • Exposes certain channels such that they are web indexable
              • Will include features like Chat Glue and communal Digital Gardens

              Created by Erlend Sogge Heggen, a ex-employee from Discourse

              • Maintains the Commune Blog with great write ups on the issues of the modern web, social media, etc. and how they can be improved (by Commune or related projects)
              • Also maintains a Personal Blog about similar topics

              The Commune community is very interested in various topics and how they can relate together:

              Related projects:

              • @laxla@tech.lgbt is creating Gimli, a federated discord alternative
                • Built on ActivityPub
                • "Guild-based" in ways matrix is not?
                • Will integrate with F3 as well
                • Wants to handle blogging as well
                • Certainly seems similar to Commune's message gardening concept
              + \ No newline at end of file diff --git a/garden/davey-wreden/index.html b/garden/davey-wreden/index.html index a1ef75d5..64a599b1 100644 --- a/garden/davey-wreden/index.html +++ b/garden/davey-wreden/index.html @@ -6,14 +6,14 @@ Davey Wreden | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Davey Wreden

              37 words, ~0 minute read. Planted +

              Skip to content
              - +.


              Referenced by:Ivy RoadThe Beginner's Guide
              Tagged by:Ivy RoadThe Beginner's GuideWanderstop

              Projects:

              Talks and Interviews:

              + \ No newline at end of file diff --git a/garden/decentralized/index.html b/garden/decentralized/index.html index 273e68ea..11af10b5 100644 --- a/garden/decentralized/index.html +++ b/garden/decentralized/index.html @@ -6,14 +6,14 @@ Decentralized | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Decentralized

              80 words, ~0 minute read. Planted +

              Skip to content

              Decentralized

              80 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:CommuneFedi v2MatrixSocial Media
              Tagged by:ATProtoActivityPubFederated IdentityFediverseNostr

              Something with no central source of authority

              Common examples:

              In practice, the "pick a server" problem causes email and the fediverse to trend towards a handful of large servers that still suffer from some of the issues of centralization

              Advantages over centralization:

              • Data ownership
              • Increased privacy
              • No rules to follow
              • Can fully customize your experience
              • No single entity can make the experience worse for everyone
              • Anyone and everyone can try their hand at improving the ecosystem
              - +.


              Referenced by:CommuneFedi v2MatrixSocial Media
              Tagged by:ATProtoActivityPubFederated IdentityFediverseNostr

              Something with no central source of authority

              Common examples:

              In practice, the "pick a server" problem causes email and the fediverse to trend towards a handful of large servers that still suffer from some of the issues of centralization

              Advantages over centralization:

              • Data ownership
              • Increased privacy
              • No rules to follow
              • Can fully customize your experience
              • No single entity can make the experience worse for everyone
              • Anyone and everyone can try their hand at improving the ecosystem
              + \ No newline at end of file diff --git a/garden/dice-armor/index.html b/garden/dice-armor/index.html index fcc53071..c7afe441 100644 --- a/garden/dice-armor/index.html +++ b/garden/dice-armor/index.html @@ -6,14 +6,14 @@ Dice Armor | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Dice Armor

              963 words, ~5 minute read. Planted +

              Skip to content

              Dice Armor

              963 words, ~5 minute read. Planted . Last tended to -.


              Referenced by:Babble Buds
              Tags:My Projects

              Download it here

              Dice Armor is a game that started development as a semester-long project by a team of nine: a producer, a creative director, a narrative writer, an artist, two programmers, and 3 game designers. The information here is about my contributions as the lead programmer over the semester because I can show off stuff like the editor scripts I wrote. I was doing everything from interface coding, editor scripts, integrating Babble Buds, and of course, everything related to the gameplay itself. To date I'm still the lead programmer for the game; for more up-to-date information on the current state of the game please visit the official site.

              The build available here was created for showing off at the end of the semester, and as such has some buttons present to make the game easier to skip parts of the game to see all the content: You start with all the dice in the game already in the shop, there's a button to give yourself free money to buy these dice with, and in the duel, there are buttons to force a win or a loss, which can be used to skip the tutorial (not recommended for first-time players).

              Dice Armor is a dice dueling game. Players can use abilities, flip dice, and attack each other to win in a dice game that puts chance into the hands of the players. This is what the dueling scene looks like, with a tutorial cutscene happening on top to guide the player through the basics. Also, all the dice are constructed dynamically, using quaternion math to figure out the placement of each component relative to the face it is going on. The die in the middle has one of the player' and opponents' portraits on each of its sides.

              For many of the objects I've created, I've made scriptable objects so that game designers can add and modify them easily. Additionally, I would create custom inspectors for the objects to help make them as easy to understand and edit as possible. The opponent's artificial intelligence is made up of many strategies, in a prioritized list. When it is the opponents' turn they go through each strategy and check if they can be run, and if so then the opponent performs the strategy and starts back over at the top of the list of strategies. The + sign under the list of strategies opens an organized dropdown of all the various strategies.

              In addition to custom inspector code, I've created new tools for the editor for our game designers to use. This is a duel simulator that will take two opponents and simulate an arbitrary number of duels between them, and output the results and summarize them for you, much much quicker than manually going through the duels, even with an absurdly high timeScale. This will become incredibly useful in making balance changes and testing new dice against existing sets. This is a screenshot of it in edit mode, but in play mode it removes the "Dueling Managers" field and will use whatever the current duel balance settings are, allowing for the GDs to test freely in play mode without worrying about undoing all their changes afterward.

              I created the Babble Buds puppet editor and ported the rendering library I wrote for it to C# so it could be used in Unity. Dice Armor has a full campaign using cutscenes made using the Babble Buds cutscene editor, taking advantage of its support for custom commands and fields to control things like talking, giving the player dice and money, starting duels, and controlling player progression through the story.

              When a cutscene ends, its final command is to either start a duel or set the next cutscene in the story. In the latter case, there is an additional field for what to call the next cutscene, and what location it takes place. The cutscene is then added to the player's save file, and when they visit the city locations are greyed out until they have at least one action to do there. Each location has a dynamically populated action wheel with a custom range of acceptable angles.

              The dice shop is dynamically populated by a list of dice available to the player, which can be changed during cutscenes, and is checked against the dice owned by the player to generate sold-out indicators. On the left, the player can choose to filter the options down to a single dice effect, which also updates the "Buy All" button to buy only all the dice in the current filter.

              The inventory works most the same as the shop, but for equipping dice. It also allows you to drag individual dice or entire sets to the equipped dice glyph. While dragging it will highlight all the slots the new dice will be equipped into.

              The dice rolling uses the physics engine and detects once the dice have stopped moving, then determines which side is face up based on which of the normals is closest to straight up. It flags the die as cocked if that smallest angle is above a threshold. The dice sink into the table when not rolling to not interfere with any dice that are rolling.

              During certain events like winning the game or having the face of a die broken, the players' portraits will flash an emotion for a second. After winning, a random living die from the winning player is chosen to play their "finisher move", a flashy and dramatic effect to end the game. Shown is the arcane mechana's finisher, "Missile Storm".

              After development stopped, the project became Open Source - check it out here

              - +.


              Referenced by:Babble Buds
              Tags:My Projects

              Download it here

              Dice Armor is a game that started development as a semester-long project by a team of nine: a producer, a creative director, a narrative writer, an artist, two programmers, and 3 game designers. The information here is about my contributions as the lead programmer over the semester because I can show off stuff like the editor scripts I wrote. I was doing everything from interface coding, editor scripts, integrating Babble Buds, and of course, everything related to the gameplay itself. To date I'm still the lead programmer for the game; for more up-to-date information on the current state of the game please visit the official site.

              The build available here was created for showing off at the end of the semester, and as such has some buttons present to make the game easier to skip parts of the game to see all the content: You start with all the dice in the game already in the shop, there's a button to give yourself free money to buy these dice with, and in the duel, there are buttons to force a win or a loss, which can be used to skip the tutorial (not recommended for first-time players).

              Dice Armor is a dice dueling game. Players can use abilities, flip dice, and attack each other to win in a dice game that puts chance into the hands of the players. This is what the dueling scene looks like, with a tutorial cutscene happening on top to guide the player through the basics. Also, all the dice are constructed dynamically, using quaternion math to figure out the placement of each component relative to the face it is going on. The die in the middle has one of the player' and opponents' portraits on each of its sides.

              For many of the objects I've created, I've made scriptable objects so that game designers can add and modify them easily. Additionally, I would create custom inspectors for the objects to help make them as easy to understand and edit as possible. The opponent's artificial intelligence is made up of many strategies, in a prioritized list. When it is the opponents' turn they go through each strategy and check if they can be run, and if so then the opponent performs the strategy and starts back over at the top of the list of strategies. The + sign under the list of strategies opens an organized dropdown of all the various strategies.

              In addition to custom inspector code, I've created new tools for the editor for our game designers to use. This is a duel simulator that will take two opponents and simulate an arbitrary number of duels between them, and output the results and summarize them for you, much much quicker than manually going through the duels, even with an absurdly high timeScale. This will become incredibly useful in making balance changes and testing new dice against existing sets. This is a screenshot of it in edit mode, but in play mode it removes the "Dueling Managers" field and will use whatever the current duel balance settings are, allowing for the GDs to test freely in play mode without worrying about undoing all their changes afterward.

              I created the Babble Buds puppet editor and ported the rendering library I wrote for it to C# so it could be used in Unity. Dice Armor has a full campaign using cutscenes made using the Babble Buds cutscene editor, taking advantage of its support for custom commands and fields to control things like talking, giving the player dice and money, starting duels, and controlling player progression through the story.

              When a cutscene ends, its final command is to either start a duel or set the next cutscene in the story. In the latter case, there is an additional field for what to call the next cutscene, and what location it takes place. The cutscene is then added to the player's save file, and when they visit the city locations are greyed out until they have at least one action to do there. Each location has a dynamically populated action wheel with a custom range of acceptable angles.

              The dice shop is dynamically populated by a list of dice available to the player, which can be changed during cutscenes, and is checked against the dice owned by the player to generate sold-out indicators. On the left, the player can choose to filter the options down to a single dice effect, which also updates the "Buy All" button to buy only all the dice in the current filter.

              The inventory works most the same as the shop, but for equipping dice. It also allows you to drag individual dice or entire sets to the equipped dice glyph. While dragging it will highlight all the slots the new dice will be equipped into.

              The dice rolling uses the physics engine and detects once the dice have stopped moving, then determines which side is face up based on which of the normals is closest to straight up. It flags the die as cocked if that smallest angle is above a threshold. The dice sink into the table when not rolling to not interfere with any dice that are rolling.

              During certain events like winning the game or having the face of a die broken, the players' portraits will flash an emotion for a second. After winning, a random living die from the winning player is chosen to play their "finisher move", a flashy and dramatic effect to end the game. Shown is the arcane mechana's finisher, "Missile Storm".

              After development stopped, the project became Open Source - check it out here

              + \ No newline at end of file diff --git a/garden/digital-gardens/index.html b/garden/digital-gardens/index.html index d7ce224c..ab3f6391 100644 --- a/garden/digital-gardens/index.html +++ b/garden/digital-gardens/index.html @@ -6,14 +6,14 @@ Digital Gardens | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Digital Gardens

              67 words, ~0 minute read. Planted +

              Skip to content

              Digital Gardens

              67 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:ChronologicalCommuneGarden-RSSThe Cozy WebThe Small WebThis Knowledge Hub

              Digital Gardens are Freeform collections of information made by an individual or community

              This Knowledge Hub is a digital garden

              Collections of digital gardens and resources for creating them:

              - +.


              Referenced by:ChronologicalCommuneGarden-RSSThe Cozy WebThe Small WebThis Knowledge Hub

              Digital Gardens are Freeform collections of information made by an individual or community

              This Knowledge Hub is a digital garden

              Collections of digital gardens and resources for creating them:

              + \ No newline at end of file diff --git a/garden/federated-identity/index.html b/garden/federated-identity/index.html index 821d0fcc..11fbae35 100644 --- a/garden/federated-identity/index.html +++ b/garden/federated-identity/index.html @@ -6,14 +6,14 @@ Federated Identity | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Federated Identity

              68 words, ~0 minute read. Planted +

              Skip to content

              Federated Identity

              68 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:CommuneFedi v2Weird
              Tags:Decentralized

              Allow for validating one's identity without relying on a specific centralized server

              Implementations:

              Self hosted identity providers are NOT enough to be considered federated identity

              • OIDC and OAuth require the service owner to have pre-configured with explicitly allowed identity providers

              Incremental Social uses Zitadel which does NOT support IndieAuth and probably won't

              - +.


              Referenced by:CommuneFedi v2Weird
              Tags:Decentralized

              Allow for validating one's identity without relying on a specific centralized server

              Implementations:

              Self hosted identity providers are NOT enough to be considered federated identity

              • OIDC and OAuth require the service owner to have pre-configured with explicitly allowed identity providers

              Incremental Social uses Zitadel which does NOT support IndieAuth and probably won't

              + \ No newline at end of file diff --git a/garden/fedi-v2/index.html b/garden/fedi-v2/index.html index ed997f14..3db640ff 100644 --- a/garden/fedi-v2/index.html +++ b/garden/fedi-v2/index.html @@ -6,14 +6,14 @@ Fedi v2 | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Fedi v2

              1835 words, ~10 minute read. Planted +

              Skip to content

              Fedi v2

              1835 words, ~10 minute read. Planted . Last tended to -.


              Referenced by:Social MediaThe IndieWeb/Signature BlocksWeird

              A placeholder name for a theoretical new federated network that is client-centric, in contrast to the server-centric Fediverse. Many of the ideas here will be implemented as described or similarly by people much smarter than me as part of Agentic Federation on Iroh, an initiative by the Weird developers.

              Motivation

              The current fediverse, while in theory fully Decentralized, in practice suffers many of the issues associated with centralization. This is primarily caused by the friction of having to pick a server and the non feasibility of individuals buying a domain and setting up a single user instance - both the causes lead to a handful of large servers with the bulk of the users. You can see this in action by looking up the relative sizes of lemmy and mastodon instances. Single-user Mastodon Instance is a Bad Idea goes over the non feasibility of self hosting and how it contributes to a handful of servers having the majority of the users.

              The promise of federation is the ability to interact with the whole network, while being able to fully choose and customize how you yourself interact with the network. In practice though, clients are severely limited to what they can do based on the server software. Of particular note, Lemmy and Mastodon show content in different formats (threads vs microblogs), and no clients allow changing how they're displayed, or respecting the format of the source of the content. Clients also are unable to change sorting algorithms or how downvotes are handled - those are all dependent on the server. A Plan for Social Media - Rethinking Federation similarly criticizes how much of the decisions are dependent on the server, which most people won't be able to or willing to self host.

              The pick a server problem is such a problem because not only do you have to pick what server has moderation policies you align with, but that you're also linking your identity with that server. Smaller servers tend to be more focused or niche, which is unlikely to fully encompass any person's entire identity. Why would I confine myself to being thepaperpilot@writinglovers.com if I'm more than a writing lover? Additionally, I'm risking that the community at that instance won't grow away from things I want to associate with, such as fascism or crypto. My identity could end up being associated with things I drastically don't want it to be.

              Nostr fixes the pick a server problem with a properly decentralized identity, however it's done so by associating itself with crypto and the alt right, and fixing that culture problem is more effort than it's worth. It'll be difficult to gain broad adoption as anyone using the platform will have to take care to explain how they're using nostr but aren't alt right.

              ATProto by bluesky offers a version of federation built for a handful of large instances, but allowing smaller servers to be spun up that can implement custom sorting algorithms, views, etc. This fixes a couple of the problems where you're unable to change certain things dictated by the servers, but doesn't quite go far enough - and of particular note, you still have to associate your identity with a specific server.

              Identity

              The new fediverse should have a fully Decentralized Identity, where it's completely attached to the client rather than any server(s). This means you don't have to pick a server, worry about your chosen server going down, or that yout identity will become associated with an undesired community. It can properly allow you to engage in your variety of interests without having to associate any as core enough to attach your identity to.

              This identity can be accomplished by the client merely generating a private and public key, which can then be stored however the user pleases. Reasonably, there's be default options to back up the private key to Google drive or alternatives, as most users will not desire to go the extra effort of backing up their identity without relying on big storage websites. But for those who wish, you could keep the identity solely on the device, or choose your own method of storage and backup.

              The client can sign messages using the private key and distribute it through whatever means they wish, and it can be verified as sent by that identity using the public key to decode the message. In this context, messages could also refer to any other signed information, such as a bundle of profile information.

              For casual conversation, a nickname in the profile data should be sufficient. Once a client interacts with someone, they can be added as a contact as a way of verifying the next conversation with someone with that username is actually the same person as before. For situations where you want to verify an identity actually has a credentials they claim, you can query a nameserver that vouches for them. For example, whitehouse.gov would have a nameserver that specifies which identity is the actual president of the United States (and other government officials). There could be nameservers that allow you to openly "register" your identity with them to get a unique human readable username you can include on billboards or other visual media where you want someone to be able to memorize the identifier, rather than scan a QR code or something. For more details on how these decentralized usernames would work, check out Petnames.

              Through cryptography, you can be confident messages are verifiably sent by someone with access to the private key, and that the message was not tampered with. These are guarantees you can't make with the current server centric fediverse.

              If you lose access to your account, it's gone forever. That is why I think there should be defaults to backup your private key to existing reliable servers, even if they're owned by large corporations. Otherwise I would see someone have their phone stolen, lost, or upgraded and be surprised when their account is now inaccessible.

              If you do lose your account and create a new identity, you could have others "vouch" for the new identity being an alias for the previous identity. You could verify your new identity with people IRL, and then other clients can see those vouches publicly and, after sufficient quantity, just implicitly assume they're the same (although with some sort of indicator, so if this gets abused, users are at least aware of the possibility of impersonation.

              Servers

              Servers would act as mere relays, whose job it is is to store messages and send them to any other clients or servers that have requested to hear about any new messages. Some relays may also display these messages in a web interface, so that you can still share links to messages online. Because your identity isn't attached to any specific server, you could send your messages out to any servers you wish, and change that list as often as you'd like. It's extremely resilient to individual servers going down.

              If you want a private network, say for a school or job, you could setup a relay server that requires some sort of password when sending them messages, and then have that server not federate with the rest of the fediverse.

              Servers would give clients ways to subscribe to subsets of all received messages - e.g. all messages, all messages from a specific user, any replies to messages from a specific user, or "shallow" subscriptions to a message, meaning it'll send you only 1 level of replies to that message.

              Content

              The protocol should be fairly content agnostic, and allow arbitrary metadata on messages that can be used by the community to come up with their own new forms of content to transmit over the protocol. For example, perhaps there's a body field that could include arbitrary text or binary data, and for binary data another field could clarify if its audio, video, an image, or something else.

              The signature of the message acts as the de facto ID of that message, for replying purposes. Edits and reactions would be handled by "replying" to a message with a metadata flag indicating what the message actually represents. Edit messages should typically be ignored if they're not from the same author as the original message. We should assume some servers will always make an edit history fully public. Reactions should just be replies without any actual body, and a tag for what the reaction is - either binary image data or a code representing an emoji, like "+1" or "laughing". Upvotes and downvotes could be implemented via reactions.

              Groups/communities could also be specially flagged messages, effectively allowing for subreddit-style content. Posting to the community is just replying to the message. Subscribing to that community is just subscribing to that message. The original message creator can send edits to update stuff like the description of the community. Perhaps they can also send a message detailing other identities to trust for editing or moderating the community.

              A bot could fairly easily be setup to make IndieWeb posts and web mentions use this protocol. Indeed, this protocol is very POSSE-friendly because you could have your original content on the website, and the messages can be spread across the network while allowing clients to verify it was untampered with and definitely came from that website. I plan on writing a proposal for IndieWeb posts to include The IndieWeb/Signature Blocks to enable this. Within this framework, Fedi v2 would not just be a other social media silo. It would be the source of truth, fully controlled by the author. Even if the author cross posts to other social media (silos), we'd effectively still be the original copy.

              Moderation

              Anyone can send edit and delete requests as replies to messages, but they'll typically be ignored since they'd be coming from a different identity. However, you could have clients or even servers honor those requests based on various heuristics - deleting anything that's gotten X delete requests, or trust specific identities to act as moderators. Since individual clients could choose which identities to honor, the moderation is effectively fully decentralized. Clients will probably have a couple identities trusted by default, to check for illegal content or that would otherwise prevent the app from breaking the app store's TOS.

              Anyone can spin up their own bots that just automatically send out delete requests based on custom logic, like checking for images that match the CSAM hash list, or messages that ChatGPT says are non-constructive. Through this, the ecosystem will over time allow people to further customize their experience by filtering out unwanted content more and more precisely.

              Success

              I believe the main benefits of this new fediverse are mostly going to apply to the techy power users who will appreciate the increased control over their identity and browsing experience. As far as the general public goes, I think the main benefit will be verified authorship and guaranteeing lack of tampering. Specifically, I think this will appeal to notable figures who have to be wary of concerns like that. Reddit and Twitter could edit your content or stifle it in the algorithm, or any other sort of malicious actions. So I think success of this platform will mostly come from seeing notable figures switching to it, and treating is as the source of truth (even if they cross post it to other platforms for increased outreach). Ideally, they even host their messages on their own website.

              - +.


              Referenced by:Social MediaThe IndieWeb/Signature BlocksWeird

              A placeholder name for a theoretical new federated network that is client-centric, in contrast to the server-centric Fediverse. Many of the ideas here will be implemented as described or similarly by people much smarter than me as part of Agentic Federation on Iroh, an initiative by the Weird developers.

              Motivation

              The current fediverse, while in theory fully Decentralized, in practice suffers many of the issues associated with centralization. This is primarily caused by the friction of having to pick a server and the non feasibility of individuals buying a domain and setting up a single user instance - both the causes lead to a handful of large servers with the bulk of the users. You can see this in action by looking up the relative sizes of lemmy and mastodon instances. Single-user Mastodon Instance is a Bad Idea goes over the non feasibility of self hosting and how it contributes to a handful of servers having the majority of the users.

              The promise of federation is the ability to interact with the whole network, while being able to fully choose and customize how you yourself interact with the network. In practice though, clients are severely limited to what they can do based on the server software. Of particular note, Lemmy and Mastodon show content in different formats (threads vs microblogs), and no clients allow changing how they're displayed, or respecting the format of the source of the content. Clients also are unable to change sorting algorithms or how downvotes are handled - those are all dependent on the server. A Plan for Social Media - Rethinking Federation similarly criticizes how much of the decisions are dependent on the server, which most people won't be able to or willing to self host.

              The pick a server problem is such a problem because not only do you have to pick what server has moderation policies you align with, but that you're also linking your identity with that server. Smaller servers tend to be more focused or niche, which is unlikely to fully encompass any person's entire identity. Why would I confine myself to being thepaperpilot@writinglovers.com if I'm more than a writing lover? Additionally, I'm risking that the community at that instance won't grow away from things I want to associate with, such as fascism or crypto. My identity could end up being associated with things I drastically don't want it to be.

              Nostr fixes the pick a server problem with a properly decentralized identity, however it's done so by associating itself with crypto and the alt right, and fixing that culture problem is more effort than it's worth. It'll be difficult to gain broad adoption as anyone using the platform will have to take care to explain how they're using nostr but aren't alt right.

              ATProto by bluesky offers a version of federation built for a handful of large instances, but allowing smaller servers to be spun up that can implement custom sorting algorithms, views, etc. This fixes a couple of the problems where you're unable to change certain things dictated by the servers, but doesn't quite go far enough - and of particular note, you still have to associate your identity with a specific server.

              Identity

              The new fediverse should have a fully Decentralized Identity, where it's completely attached to the client rather than any server(s). This means you don't have to pick a server, worry about your chosen server going down, or that yout identity will become associated with an undesired community. It can properly allow you to engage in your variety of interests without having to associate any as core enough to attach your identity to.

              This identity can be accomplished by the client merely generating a private and public key, which can then be stored however the user pleases. Reasonably, there's be default options to back up the private key to Google drive or alternatives, as most users will not desire to go the extra effort of backing up their identity without relying on big storage websites. But for those who wish, you could keep the identity solely on the device, or choose your own method of storage and backup.

              The client can sign messages using the private key and distribute it through whatever means they wish, and it can be verified as sent by that identity using the public key to decode the message. In this context, messages could also refer to any other signed information, such as a bundle of profile information.

              For casual conversation, a nickname in the profile data should be sufficient. Once a client interacts with someone, they can be added as a contact as a way of verifying the next conversation with someone with that username is actually the same person as before. For situations where you want to verify an identity actually has a credentials they claim, you can query a nameserver that vouches for them. For example, whitehouse.gov would have a nameserver that specifies which identity is the actual president of the United States (and other government officials). There could be nameservers that allow you to openly "register" your identity with them to get a unique human readable username you can include on billboards or other visual media where you want someone to be able to memorize the identifier, rather than scan a QR code or something. For more details on how these decentralized usernames would work, check out Petnames.

              Through cryptography, you can be confident messages are verifiably sent by someone with access to the private key, and that the message was not tampered with. These are guarantees you can't make with the current server centric fediverse.

              If you lose access to your account, it's gone forever. That is why I think there should be defaults to backup your private key to existing reliable servers, even if they're owned by large corporations. Otherwise I would see someone have their phone stolen, lost, or upgraded and be surprised when their account is now inaccessible.

              If you do lose your account and create a new identity, you could have others "vouch" for the new identity being an alias for the previous identity. You could verify your new identity with people IRL, and then other clients can see those vouches publicly and, after sufficient quantity, just implicitly assume they're the same (although with some sort of indicator, so if this gets abused, users are at least aware of the possibility of impersonation.

              Servers

              Servers would act as mere relays, whose job it is is to store messages and send them to any other clients or servers that have requested to hear about any new messages. Some relays may also display these messages in a web interface, so that you can still share links to messages online. Because your identity isn't attached to any specific server, you could send your messages out to any servers you wish, and change that list as often as you'd like. It's extremely resilient to individual servers going down.

              If you want a private network, say for a school or job, you could setup a relay server that requires some sort of password when sending them messages, and then have that server not federate with the rest of the fediverse.

              Servers would give clients ways to subscribe to subsets of all received messages - e.g. all messages, all messages from a specific user, any replies to messages from a specific user, or "shallow" subscriptions to a message, meaning it'll send you only 1 level of replies to that message.

              Content

              The protocol should be fairly content agnostic, and allow arbitrary metadata on messages that can be used by the community to come up with their own new forms of content to transmit over the protocol. For example, perhaps there's a body field that could include arbitrary text or binary data, and for binary data another field could clarify if its audio, video, an image, or something else.

              The signature of the message acts as the de facto ID of that message, for replying purposes. Edits and reactions would be handled by "replying" to a message with a metadata flag indicating what the message actually represents. Edit messages should typically be ignored if they're not from the same author as the original message. We should assume some servers will always make an edit history fully public. Reactions should just be replies without any actual body, and a tag for what the reaction is - either binary image data or a code representing an emoji, like "+1" or "laughing". Upvotes and downvotes could be implemented via reactions.

              Groups/communities could also be specially flagged messages, effectively allowing for subreddit-style content. Posting to the community is just replying to the message. Subscribing to that community is just subscribing to that message. The original message creator can send edits to update stuff like the description of the community. Perhaps they can also send a message detailing other identities to trust for editing or moderating the community.

              A bot could fairly easily be setup to make IndieWeb posts and web mentions use this protocol. Indeed, this protocol is very POSSE-friendly because you could have your original content on the website, and the messages can be spread across the network while allowing clients to verify it was untampered with and definitely came from that website. I plan on writing a proposal for IndieWeb posts to include The IndieWeb/Signature Blocks to enable this. Within this framework, Fedi v2 would not just be a other social media silo. It would be the source of truth, fully controlled by the author. Even if the author cross posts to other social media (silos), we'd effectively still be the original copy.

              Moderation

              Anyone can send edit and delete requests as replies to messages, but they'll typically be ignored since they'd be coming from a different identity. However, you could have clients or even servers honor those requests based on various heuristics - deleting anything that's gotten X delete requests, or trust specific identities to act as moderators. Since individual clients could choose which identities to honor, the moderation is effectively fully decentralized. Clients will probably have a couple identities trusted by default, to check for illegal content or that would otherwise prevent the app from breaking the app store's TOS.

              Anyone can spin up their own bots that just automatically send out delete requests based on custom logic, like checking for images that match the CSAM hash list, or messages that ChatGPT says are non-constructive. Through this, the ecosystem will over time allow people to further customize their experience by filtering out unwanted content more and more precisely.

              Success

              I believe the main benefits of this new fediverse are mostly going to apply to the techy power users who will appreciate the increased control over their identity and browsing experience. As far as the general public goes, I think the main benefit will be verified authorship and guaranteeing lack of tampering. Specifically, I think this will appeal to notable figures who have to be wary of concerns like that. Reddit and Twitter could edit your content or stifle it in the algorithm, or any other sort of malicious actions. So I think success of this platform will mostly come from seeing notable figures switching to it, and treating is as the source of truth (even if they cross post it to other platforms for increased outreach). Ideally, they even host their messages on their own website.

              + \ No newline at end of file diff --git a/garden/fediverse/index.html b/garden/fediverse/index.html index f5cc62df..0f9b6253 100644 --- a/garden/fediverse/index.html +++ b/garden/fediverse/index.html @@ -6,14 +6,14 @@ Fediverse | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Fediverse

              29 words, ~0 minute read. Planted +

              Skip to content

              Fediverse

              29 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:ATProtoActivityPubDecentralizedFedi v2Incremental SocialMbinNostrSocial MediaThe Small WebWeird
              Tags:Decentralized

              A collection of Social Media websites that can all talk to each other by virtue of a shared protocol

              Typically refers to sites implementing ActivityPub

              Implementations:

              - +.


              Referenced by:ATProtoActivityPubDecentralizedFedi v2Incremental SocialMbinNostrSocial MediaThe Small WebWeird
              Tags:Decentralized

              A collection of Social Media websites that can all talk to each other by virtue of a shared protocol

              Typically refers to sites implementing ActivityPub

              Implementations:

              + \ No newline at end of file diff --git a/garden/forgejo/index.html b/garden/forgejo/index.html index 901f2723..6c1cfc16 100644 --- a/garden/forgejo/index.html +++ b/garden/forgejo/index.html @@ -6,14 +6,14 @@ Forgejo | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Forgejo

              5 words, ~0 minute read. Planted +

              Skip to content

              Forgejo

              5 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:Incremental Social

              Forgejo is an Open Source code repository hosting software

              - +.


              Referenced by:Incremental Social

              Forgejo is an Open Source code repository hosting software

              + \ No newline at end of file diff --git a/garden/freeform-vs-chronological-dichotomy/index.html b/garden/freeform-vs-chronological-dichotomy/index.html index 458fe959..bf30a6a6 100644 --- a/garden/freeform-vs-chronological-dichotomy/index.html +++ b/garden/freeform-vs-chronological-dichotomy/index.html @@ -6,14 +6,14 @@ Freeform vs Chronological Dichotomy | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Freeform vs Chronological Dichotomy

              10 words, ~0 minute read. Planted +

              Skip to content

              Freeform vs Chronological Dichotomy

              10 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:ChronologicalFreeform

              Describes a dichotomy between displaying information in a Freeform vs Chronological manner

              - +.


              Referenced by:ChronologicalFreeform

              Describes a dichotomy between displaying information in a Freeform vs Chronological manner

              + \ No newline at end of file diff --git a/garden/freeform/index.html b/garden/freeform/index.html index 3baddb79..6815b7b1 100644 --- a/garden/freeform/index.html +++ b/garden/freeform/index.html @@ -6,14 +6,14 @@ Freeform | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Freeform

              46 words, ~0 minute read. Planted +

              Skip to content

              Freeform

              46 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:CommuneDigital GardensFreeform vs Chronological DichotomyGarden-RSS

              A collection of information that is not tied to when it was created or edited

              Part of the Freeform vs Chronological Dichotomy

              Anything wiki-style is considered freeform

              • A collection of living documents

              Garden-RSS, a theoretical alternative to RSS that's better for freeform content

              - +.


              Referenced by:CommuneDigital GardensFreeform vs Chronological DichotomyGarden-RSS

              A collection of information that is not tied to when it was created or edited

              Part of the Freeform vs Chronological Dichotomy

              Anything wiki-style is considered freeform

              • A collection of living documents

              Garden-RSS, a theoretical alternative to RSS that's better for freeform content

              + \ No newline at end of file diff --git a/garden/game-dev-tree/index.html b/garden/game-dev-tree/index.html index 4daea11d..d9eb507a 100644 --- a/garden/game-dev-tree/index.html +++ b/garden/game-dev-tree/index.html @@ -6,14 +6,14 @@ Game Dev Tree | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Game Dev Tree

              34 words, ~0 minute read. Planted +

              Skip to content

              Game Dev Tree

              34 words, ~0 minute read. Planted . Last tended to -.


              Tags:My Projects

              Play it here!

              My first (good) incremental game! (My actual first was Shape Tycoon - I don't recommend it!)

              It's Open Source!

              The TV Tropes page on this game mentions some of the cool things about this game

              - +.


              Tags:My Projects

              Play it here!

              My first (good) incremental game! (My actual first was Shape Tycoon - I don't recommend it!)

              It's Open Source!

              The TV Tropes page on this game mentions some of the cool things about this game

              + \ No newline at end of file diff --git a/garden/garden-rss/index.html b/garden/garden-rss/index.html index a1c838b4..2a7672c7 100644 --- a/garden/garden-rss/index.html +++ b/garden/garden-rss/index.html @@ -6,14 +6,14 @@ Garden-RSS | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Garden-RSS

              59 words, ~0 minute read. Planted +

              Skip to content

              Garden-RSS

              59 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:FreeformThe Small WebThis Knowledge Hub

              A theoretical alternative to RSS that's better for Freeform websites (and Digital Gardens specifically )

              Why is it useful?

              How should it work?

              • Could display changes similar to git diffs

              Existing Work

              - +.


              Referenced by:FreeformThe Small WebThis Knowledge Hub

              A theoretical alternative to RSS that's better for Freeform websites (and Digital Gardens specifically )

              Why is it useful?

              How should it work?

              • Could display changes similar to git diffs

              Existing Work

              + \ No newline at end of file diff --git a/garden/guide-to-incrementals/appeal-to-developers/index.html b/garden/guide-to-incrementals/appeal-to-developers/index.html index 4099a154..f63bcf49 100644 --- a/garden/guide-to-incrementals/appeal-to-developers/index.html +++ b/garden/guide-to-incrementals/appeal-to-developers/index.html @@ -6,14 +6,14 @@ Guide to Incrementals/Appeal to Developers | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Guide to Incrementals___Appeal to Developers

              636 words, ~3 minute read. Planted +

              Skip to content

              Guide to Incrementals___Appeal to Developers

              636 words, ~3 minute read. Planted . Last tended to -.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              There are a lot of developers in the incremental games community - the genre seems to draw them in, and convert a lot of players into developers. Let's explore the reasons why this genre appeals to developers.

              Incrementals are Easy to Make

              Compared to other genres, incrementals have quite low expectations. You don't need to make fancy art, or music, or lay things out nicely. If you can make a button and learn the few lines of code necessary to make a number go up, you can make an incremental. This low threshold makes the genre perfect for those who are actively learning to code and haven't developed any gamedev-related skills yet.

              Additionally, unlike other genres incrementals are uniquely easy to implement in a normal web page - no need to worry about rendering sprites, moving them around, implementing physics, etc. New developers can just use HTML to add a button, and the game is now available in your browser. You don't need to choose an engine, have admin privileges, or hell for the dedicated you don't even need a computer - there are tools for web development that run in the browser itself, so you can technically use your phone if that's all you have.

              Javascript is a perfectly viable language for making web games, whereas other genres are typically going to require using other more difficult languages to learn. There are countless javascript tutorials that start from 0 knowledge of programming, making it incredibly accessible to beginners.

              Players are Easy to Find

              Once you've finished your game and uploaded it on github pages or itch or just copied the link if you're using glitch or replit (all of which are easy to do), anyone can now play the game in their browser. This low barrier to entry has shown tremendous success in getting completely unknown developers to have thousands of plays.

              The incremental games community, which mostly centers around r/incremental_games, is always looking for new games and tends to flood any new ones posted with initial players.

              Having your games be played can be incredibly motivating, and the community makes it quite clear that you can expect players to play your game. These communities - both for incremental games in general as well as game-specific communities - tend to be very developer friendly as well. A lot of the developers know each other, and welcome new developers with open arms, often with dedicated channels for programming help and discussions.

              Monetization

              I'd like to clarify that everything I've said above mainly applies to web-based incrementals. Incremental games are also incredibly popular on mobile, but with a much different culture and community. Many mobile gamers will still participate in the web-focused community for the culture. This web-focused community has a culture that has been criticized for being "anti-monetization". Ads, IAPs, and similar forms of monetization are often criticized, mainly due to the abundance of completely non-monetized games available from hobbyist developers. There are exceptions, like paid games often being considered fine, like Increlution or Stuck in Time, or donation ware games like kittens game, but even popular games that have IAP see some level of regular criticism, like NGU Idle, Idle Skilling, or Idle Pins. A large part of this can be explained by the community being hyper-aware of the addictive) nature of this genre and its susceptibility to exploiting players.

              On mobile, however, monetization is the norm and expected. If an incremental game is available on mobile, it almost certainly will be monetized, and mobile players are aware and accepting of that. Mobile incremental games, due to their addictive nature, tend to make a lot of money. It's very lucrative, and therefore these games are quite abundant on mobile storefronts.

              - +.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              There are a lot of developers in the incremental games community - the genre seems to draw them in, and convert a lot of players into developers. Let's explore the reasons why this genre appeals to developers.

              Incrementals are Easy to Make

              Compared to other genres, incrementals have quite low expectations. You don't need to make fancy art, or music, or lay things out nicely. If you can make a button and learn the few lines of code necessary to make a number go up, you can make an incremental. This low threshold makes the genre perfect for those who are actively learning to code and haven't developed any gamedev-related skills yet.

              Additionally, unlike other genres incrementals are uniquely easy to implement in a normal web page - no need to worry about rendering sprites, moving them around, implementing physics, etc. New developers can just use HTML to add a button, and the game is now available in your browser. You don't need to choose an engine, have admin privileges, or hell for the dedicated you don't even need a computer - there are tools for web development that run in the browser itself, so you can technically use your phone if that's all you have.

              Javascript is a perfectly viable language for making web games, whereas other genres are typically going to require using other more difficult languages to learn. There are countless javascript tutorials that start from 0 knowledge of programming, making it incredibly accessible to beginners.

              Players are Easy to Find

              Once you've finished your game and uploaded it on github pages or itch or just copied the link if you're using glitch or replit (all of which are easy to do), anyone can now play the game in their browser. This low barrier to entry has shown tremendous success in getting completely unknown developers to have thousands of plays.

              The incremental games community, which mostly centers around r/incremental_games, is always looking for new games and tends to flood any new ones posted with initial players.

              Having your games be played can be incredibly motivating, and the community makes it quite clear that you can expect players to play your game. These communities - both for incremental games in general as well as game-specific communities - tend to be very developer friendly as well. A lot of the developers know each other, and welcome new developers with open arms, often with dedicated channels for programming help and discussions.

              Monetization

              I'd like to clarify that everything I've said above mainly applies to web-based incrementals. Incremental games are also incredibly popular on mobile, but with a much different culture and community. Many mobile gamers will still participate in the web-focused community for the culture. This web-focused community has a culture that has been criticized for being "anti-monetization". Ads, IAPs, and similar forms of monetization are often criticized, mainly due to the abundance of completely non-monetized games available from hobbyist developers. There are exceptions, like paid games often being considered fine, like Increlution or Stuck in Time, or donation ware games like kittens game, but even popular games that have IAP see some level of regular criticism, like NGU Idle, Idle Skilling, or Idle Pins. A large part of this can be explained by the community being hyper-aware of the addictive) nature of this genre and its susceptibility to exploiting players.

              On mobile, however, monetization is the norm and expected. If an incremental game is available on mobile, it almost certainly will be monetized, and mobile players are aware and accepting of that. Mobile incremental games, due to their addictive nature, tend to make a lot of money. It's very lucrative, and therefore these games are quite abundant on mobile storefronts.

              + \ No newline at end of file diff --git a/garden/guide-to-incrementals/appeal-to-players/index.html b/garden/guide-to-incrementals/appeal-to-players/index.html index 4ad9d074..8acbb744 100644 --- a/garden/guide-to-incrementals/appeal-to-players/index.html +++ b/garden/guide-to-incrementals/appeal-to-players/index.html @@ -6,14 +6,14 @@ Guide to Incrementals/Appeal to Players | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Guide to Incrementals___Appeal to Players

              2166 words, ~12 minute read. Planted +

              Skip to content

              Guide to Incrementals___Appeal to Players

              2166 words, ~12 minute read. Planted . Last tended to -.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              This is something that has been discussed and analyzed by many people, and to some extent, I feel like everything that can be said on the topic already has. However, a lot of these analyses are from the perspective of those with not as much experience and involvement within the genre as I'd argue would be necessary for a fully contextualized answer. I'm interested in ludology and part of that includes interpreting games as art, and to that end what constitutes a game, let alone a "good game". Incremental games are oft criticized, unfairly in my biased opinion, of not even constituting games, such as was posited by this polygon article.

              Numbers Going Up

              This is a very common response to why people enjoy incremental games, although it's not one I find compels me personally, and I suspect it might be a stand-in for progression) or Guide to Incrementals/What is Content?. But reportedly, some people do just like seeing big numbers. I must reiterate I suspect the actual cause is seeing big numbers in context though - if you start at 1e1000 of a currency and get to 1e1001, that isn't going to feel as satisfying as going from 1e10 to 1e100, and in any case, I don't think a button that just adds a zero to your number will feel quite satisfying - I believe its the sense of having made progress, and comparing where you are to where you started and feeling like you've earned your way here that is enjoyable.

              Progression

              I think a strong sense of progression is seen as very enjoyable to many players of all sorts of genres - engine builder board games, RPGs, rogue_lites_, etc. Incremental games tend to have an extremely exaggerated sense of progression, which makes them very appealing.

              Meta-progression is when games have some sort of progression that persists when other progress gets lost - for example, upgrades that persist between runs of a roguelite game. These are common mechanics in incremental games - in fact, its not uncommon to have multiple of these reset mechanics nested on top of each other, each with their own meta-progression. These are satisfying to players, although they can be a bit controversial. These mechanics can often be seen as an optional crutch, and in roguelite games, players often challenge themselves to win without any meta progression. Essentially these challenges argue that meta-progression de-emphasizes player skill by replacing it with time served. Incremental games, through their exaggerated progression, eschew that possibility though - they make it impossible to beat without the meta progression systems, as the meta-progression becomes an entire chapter of the gameplay. I'd argue this does not detract from the game, however, and is actually a part of what makes incremental games, and roguelikes, enjoyable to many players: meta-progression augments the increases in skill the player is naturally gaining as they play. In effect, it's not replacing the skill increase, but exaggerating it to make it feel more real to the player.

              Effortlessness

              Incremental games are so easy, a lot of them even have you progress while you're not playing! Part of the appeal is being able to feel like you're making progress while doing something actually productive - multitasking, in a way. In this sense, the game is more of a fidget toy - not something to think hard about and play actively, but something to click a few buttons every so often while you're paying attention to a lecture or studying or working. Of course, not all incremental games lend themselves to being played this way - it's specifically "idle" games that work like this. These are games that take an incredibly long amount of time to see all the content, stretching it as thin as possible, but they aren't expecting you to be sitting at your device playing it the entire time. They expect you to leave and come back later to make a bit of progress and repeat the cycle.

              If you look at the higher-level play of most games, you'll see them perform difficult feats with ease and speed. They'll achieve a "flow state" that takes all their knowledge and experience of the game and uses it to play the game as instinctively as possible. It's incredible to watch things like Slay the Spire speed runs or competitive DDR-likes. I'd argue the goal of a lot of games with a competitive scene is to get so good that the game becomes effortless. In that sense, a game that allows you to reach that point earlier isn't any less legitimate, but rather lowers the barrier to entry by allowing more people to get "really good" at the game. And to be clear, (most) incremental games aren't trivially easy - they, and to an extent, every game will have some level of learning and improvement over time.

              Addiction

              A lot of these reasons for why incremental games appeal may have reminded you of why gambling appeals to people, particularly those prone to addiction. Indeed, incremental games are quite often criticized for their similarity to a skinner box. Some have gone as far as to say incremental games as a genre are commenting that all games are skinner boxes). The argument goes that some games are not fun, but rather condition players into continuing to play without actually getting anything from the experience. When tied to real-world money this is seen as predatory, and to a lesser extent, even free games may be feeding the addictive sides of people and making them more prone to seek out gambling or micro-transaction heavy games.

              While incremental games can be fun and even healthy in certain contexts, they can exacerbate video game addiction more than other genres. If you feel like playing incremental games is taking priority over other things in your life, or manipulating your sleep schedule, it may be prudent to seek help. See r/StopGaming for resources.

              Since incremental games are often built on extrinsic motivations in the form of progression systems, it's hard to argue whether players continue to play because they are enjoying the gameplay, or if they are just conditioned to keep doing it because the game keeps rewarding them. Unfortunately, it can often feel like it's the latter, as there isn't typically anything compelling about the "gameplay" of clicking a button and waiting. There may be a significant overlap between those who enjoy incremental games and those who are most prone to addiction, and there are often posts on r/incremental_games about someone either struggling with or overcoming video game addiction.

              Strategy

              Incremental games could be considered a subset of strategy games), and inherit the appeals of strategy games. This includes the appeal of feeling like you've found a good solution to a puzzle, or that you're learning more about the game and are improving at making decisions within it.

              Note that strategy games are not all the same difficulty, as well. Cookie Clicker is probably easier than Starcraft 2 (although late game may beg to differ). Plenty of incremental games can be used as evidence that "easier" strategies may have their separate appeal to harder strategy games - players like to feel smart and that they figured the game out and have optimized or mastered it, and the game being easier doesn't detract from that sense of accomplishment as much as it allows more and more users to be able to reach the point where they gain that sense.

              Avoiding Staleness

              Incremental games tend to have "paradigm shifts", where the gameplay changes in a meaningful way at various times throughout the progression of the game. These upset and change the gameplay loop, which helps keep them from stagnating. This constant "freshness" to the gameplay can keep players engaged for longer, compared to a game with a repetitive and static gameplay loop.

              Good Game Design

              Incremental games tend to show their game design "plainly", so it's more readily apparent if a game has good game design while playing, even if you're not looking for it. While different players have different preferences and might enjoy different types of games more than others, there are underlying good and bad game design principles that players will notice the effects of. To be clear, this isn't talking about stuff like big numbers being enjoyable, where I can comfortably agree to disagree with other players. They don't intrinsically make my experience better, but I'm aware of those for whom it does and I won't argue against their feelings. However, the game designer in me does feel like there are some extremely clear-cut examples of good and bad game design philosophies.

              Let's start by giving an example of a mechanic I think can be easily and strongly argued is good game design. There are of course many examples, but a personal favorite of mine is how DOOM encourages aggressive gameplay by linking health drops to melee attacks. It has an intended experience it's trying to give the player - immersing themselves as DOOM guy, who would not hide behind cover when low on health - and this mechanic does a great job at encouraging and effectively teaching players to behave properly. This is in sharp contrast to shooters like Call of Duty, which have you regen health passively, encouraging players to hide behind cover and wait after getting hit. Note that I'm not arguing CoD is poorly designed, as the games have different intended experiences. I'm specifically praising DOOM for having a mechanic that does a good job at ensuring the player has that intended experience.

              To contrast with an example I think is bad game design, let's talk about shields in souls-likes. This is a bit of a famous example, and I highly recommend this video essay which spends quite a good bit of time on this topic. Essentially, the argument boils down to players of earlier games in the souls games using shields too much - playing slowly, conservatively, and ultimately having less fun. Players wanted to feel safe, so they ended up playing in a way that ruined the experience for them. The developers solved this by removing shields, apart from an intentionally bad one effectively mocking the playstyle, and it did its job at getting players to play more aggressively, and often have more fun.

              To bring the conversation back to incrementals, I'm incredibly opinionated on what makes a good incremental game, which I'll discuss in the game design section. Suffice it to say, incremental games rely more on good game design than other genres, due to not having much to distract from bad game design. This helps (although imperfectly - gamers are a bit too tolerant of bad game design!) well-designed games rise to the top within the genre.

              Artistic Merit

              The discussion of whether video games are art has resulted in a pretty universal "yes, they are", but with some games the argument may still crop up. The reason why Incremental games are sometimes questioned is due to their perceived lack of complexity. However, even setting aside the fact that if players are having fun then it's not time wasted, I think games can have artistic merit that supersedes the necessity of having (any / engaging / "deep") gameplay. Incremental games are no less legitimate of a game or the "art" label because of any lack perceived lack of depth. For what it's worth, most art can be consumed with more ease than any video game - any painting, movie, sculpture, etc.

              A lot of incrementals have a narrative context that can similarly qualify them as art. Cookie Clicker is, as has been pointed out numerous times before, commenting on excess and increasing production beyond any reasonable limits - devolving into increasing production for its own sake. Indeed, a lot of incremental games are written to comment upon various concepts like capitalism or tropes in games, as discussed when defining Incrementals). However, I'd like to argue most incremental games are still art, even without any narrative context. "Art" as a concept is pretty nebulous already, but I personally like those who define it as an act of expression more than any physical result. The creator and the context within which they created the art, and any meaning they put into it, are all relevant and a part of the art itself. Most incremental games have artistic merit from things like why the creator made it, why they chose to make it an incremental game, and why they made any particular design decision. Hell, even if you play through an entire incremental game without a single thought or feeling, that very fact it elicited nothing can itself be artistic merit!

              I'm not an art major, and I may be taking a somewhat extreme take on what is art and what has artistic merit, but I'd argue the overall point stands that games, and incremental games specifically, can have artistic merit, which appeals to many gamers.

              - +.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              This is something that has been discussed and analyzed by many people, and to some extent, I feel like everything that can be said on the topic already has. However, a lot of these analyses are from the perspective of those with not as much experience and involvement within the genre as I'd argue would be necessary for a fully contextualized answer. I'm interested in ludology and part of that includes interpreting games as art, and to that end what constitutes a game, let alone a "good game". Incremental games are oft criticized, unfairly in my biased opinion, of not even constituting games, such as was posited by this polygon article.

              Numbers Going Up

              This is a very common response to why people enjoy incremental games, although it's not one I find compels me personally, and I suspect it might be a stand-in for progression) or Guide to Incrementals/What is Content?. But reportedly, some people do just like seeing big numbers. I must reiterate I suspect the actual cause is seeing big numbers in context though - if you start at 1e1000 of a currency and get to 1e1001, that isn't going to feel as satisfying as going from 1e10 to 1e100, and in any case, I don't think a button that just adds a zero to your number will feel quite satisfying - I believe its the sense of having made progress, and comparing where you are to where you started and feeling like you've earned your way here that is enjoyable.

              Progression

              I think a strong sense of progression is seen as very enjoyable to many players of all sorts of genres - engine builder board games, RPGs, rogue_lites_, etc. Incremental games tend to have an extremely exaggerated sense of progression, which makes them very appealing.

              Meta-progression is when games have some sort of progression that persists when other progress gets lost - for example, upgrades that persist between runs of a roguelite game. These are common mechanics in incremental games - in fact, its not uncommon to have multiple of these reset mechanics nested on top of each other, each with their own meta-progression. These are satisfying to players, although they can be a bit controversial. These mechanics can often be seen as an optional crutch, and in roguelite games, players often challenge themselves to win without any meta progression. Essentially these challenges argue that meta-progression de-emphasizes player skill by replacing it with time served. Incremental games, through their exaggerated progression, eschew that possibility though - they make it impossible to beat without the meta progression systems, as the meta-progression becomes an entire chapter of the gameplay. I'd argue this does not detract from the game, however, and is actually a part of what makes incremental games, and roguelikes, enjoyable to many players: meta-progression augments the increases in skill the player is naturally gaining as they play. In effect, it's not replacing the skill increase, but exaggerating it to make it feel more real to the player.

              Effortlessness

              Incremental games are so easy, a lot of them even have you progress while you're not playing! Part of the appeal is being able to feel like you're making progress while doing something actually productive - multitasking, in a way. In this sense, the game is more of a fidget toy - not something to think hard about and play actively, but something to click a few buttons every so often while you're paying attention to a lecture or studying or working. Of course, not all incremental games lend themselves to being played this way - it's specifically "idle" games that work like this. These are games that take an incredibly long amount of time to see all the content, stretching it as thin as possible, but they aren't expecting you to be sitting at your device playing it the entire time. They expect you to leave and come back later to make a bit of progress and repeat the cycle.

              If you look at the higher-level play of most games, you'll see them perform difficult feats with ease and speed. They'll achieve a "flow state" that takes all their knowledge and experience of the game and uses it to play the game as instinctively as possible. It's incredible to watch things like Slay the Spire speed runs or competitive DDR-likes. I'd argue the goal of a lot of games with a competitive scene is to get so good that the game becomes effortless. In that sense, a game that allows you to reach that point earlier isn't any less legitimate, but rather lowers the barrier to entry by allowing more people to get "really good" at the game. And to be clear, (most) incremental games aren't trivially easy - they, and to an extent, every game will have some level of learning and improvement over time.

              Addiction

              A lot of these reasons for why incremental games appeal may have reminded you of why gambling appeals to people, particularly those prone to addiction. Indeed, incremental games are quite often criticized for their similarity to a skinner box. Some have gone as far as to say incremental games as a genre are commenting that all games are skinner boxes). The argument goes that some games are not fun, but rather condition players into continuing to play without actually getting anything from the experience. When tied to real-world money this is seen as predatory, and to a lesser extent, even free games may be feeding the addictive sides of people and making them more prone to seek out gambling or micro-transaction heavy games.

              While incremental games can be fun and even healthy in certain contexts, they can exacerbate video game addiction more than other genres. If you feel like playing incremental games is taking priority over other things in your life, or manipulating your sleep schedule, it may be prudent to seek help. See r/StopGaming for resources.

              Since incremental games are often built on extrinsic motivations in the form of progression systems, it's hard to argue whether players continue to play because they are enjoying the gameplay, or if they are just conditioned to keep doing it because the game keeps rewarding them. Unfortunately, it can often feel like it's the latter, as there isn't typically anything compelling about the "gameplay" of clicking a button and waiting. There may be a significant overlap between those who enjoy incremental games and those who are most prone to addiction, and there are often posts on r/incremental_games about someone either struggling with or overcoming video game addiction.

              Strategy

              Incremental games could be considered a subset of strategy games), and inherit the appeals of strategy games. This includes the appeal of feeling like you've found a good solution to a puzzle, or that you're learning more about the game and are improving at making decisions within it.

              Note that strategy games are not all the same difficulty, as well. Cookie Clicker is probably easier than Starcraft 2 (although late game may beg to differ). Plenty of incremental games can be used as evidence that "easier" strategies may have their separate appeal to harder strategy games - players like to feel smart and that they figured the game out and have optimized or mastered it, and the game being easier doesn't detract from that sense of accomplishment as much as it allows more and more users to be able to reach the point where they gain that sense.

              Avoiding Staleness

              Incremental games tend to have "paradigm shifts", where the gameplay changes in a meaningful way at various times throughout the progression of the game. These upset and change the gameplay loop, which helps keep them from stagnating. This constant "freshness" to the gameplay can keep players engaged for longer, compared to a game with a repetitive and static gameplay loop.

              Good Game Design

              Incremental games tend to show their game design "plainly", so it's more readily apparent if a game has good game design while playing, even if you're not looking for it. While different players have different preferences and might enjoy different types of games more than others, there are underlying good and bad game design principles that players will notice the effects of. To be clear, this isn't talking about stuff like big numbers being enjoyable, where I can comfortably agree to disagree with other players. They don't intrinsically make my experience better, but I'm aware of those for whom it does and I won't argue against their feelings. However, the game designer in me does feel like there are some extremely clear-cut examples of good and bad game design philosophies.

              Let's start by giving an example of a mechanic I think can be easily and strongly argued is good game design. There are of course many examples, but a personal favorite of mine is how DOOM encourages aggressive gameplay by linking health drops to melee attacks. It has an intended experience it's trying to give the player - immersing themselves as DOOM guy, who would not hide behind cover when low on health - and this mechanic does a great job at encouraging and effectively teaching players to behave properly. This is in sharp contrast to shooters like Call of Duty, which have you regen health passively, encouraging players to hide behind cover and wait after getting hit. Note that I'm not arguing CoD is poorly designed, as the games have different intended experiences. I'm specifically praising DOOM for having a mechanic that does a good job at ensuring the player has that intended experience.

              To contrast with an example I think is bad game design, let's talk about shields in souls-likes. This is a bit of a famous example, and I highly recommend this video essay which spends quite a good bit of time on this topic. Essentially, the argument boils down to players of earlier games in the souls games using shields too much - playing slowly, conservatively, and ultimately having less fun. Players wanted to feel safe, so they ended up playing in a way that ruined the experience for them. The developers solved this by removing shields, apart from an intentionally bad one effectively mocking the playstyle, and it did its job at getting players to play more aggressively, and often have more fun.

              To bring the conversation back to incrementals, I'm incredibly opinionated on what makes a good incremental game, which I'll discuss in the game design section. Suffice it to say, incremental games rely more on good game design than other genres, due to not having much to distract from bad game design. This helps (although imperfectly - gamers are a bit too tolerant of bad game design!) well-designed games rise to the top within the genre.

              Artistic Merit

              The discussion of whether video games are art has resulted in a pretty universal "yes, they are", but with some games the argument may still crop up. The reason why Incremental games are sometimes questioned is due to their perceived lack of complexity. However, even setting aside the fact that if players are having fun then it's not time wasted, I think games can have artistic merit that supersedes the necessity of having (any / engaging / "deep") gameplay. Incremental games are no less legitimate of a game or the "art" label because of any lack perceived lack of depth. For what it's worth, most art can be consumed with more ease than any video game - any painting, movie, sculpture, etc.

              A lot of incrementals have a narrative context that can similarly qualify them as art. Cookie Clicker is, as has been pointed out numerous times before, commenting on excess and increasing production beyond any reasonable limits - devolving into increasing production for its own sake. Indeed, a lot of incremental games are written to comment upon various concepts like capitalism or tropes in games, as discussed when defining Incrementals). However, I'd like to argue most incremental games are still art, even without any narrative context. "Art" as a concept is pretty nebulous already, but I personally like those who define it as an act of expression more than any physical result. The creator and the context within which they created the art, and any meaning they put into it, are all relevant and a part of the art itself. Most incremental games have artistic merit from things like why the creator made it, why they chose to make it an incremental game, and why they made any particular design decision. Hell, even if you play through an entire incremental game without a single thought or feeling, that very fact it elicited nothing can itself be artistic merit!

              I'm not an art major, and I may be taking a somewhat extreme take on what is art and what has artistic merit, but I'd argue the overall point stands that games, and incremental games specifically, can have artistic merit, which appeals to many gamers.

              + \ No newline at end of file diff --git a/garden/guide-to-incrementals/defining-the-genre/index.html b/garden/guide-to-incrementals/defining-the-genre/index.html index 7296a68e..c920dd85 100644 --- a/garden/guide-to-incrementals/defining-the-genre/index.html +++ b/garden/guide-to-incrementals/defining-the-genre/index.html @@ -6,14 +6,14 @@ Guide to Incrementals/Defining the Genre | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Guide to Incrementals___Defining the Genre

              3429 words, ~19 minute read. Planted +

              Skip to content

              Guide to Incrementals___Defining the Genre

              3429 words, ~19 minute read. Planted . Last tended to -.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              Video games are placed into genres for a variety of reasons. They can give a mental shorthand to set the player's expectations up, they can help a game market itself by its similarities to other, already popular games, and honestly, people just love categorization for its own sake. For this guide, it's important to define the genre so it is clear what games it's even talking about.

              This poses a problem. "Incremental" is a horribly vague way to define games. Most games have numbers going up in some form or another. We need a more specific definition - similar to how "strategy" can't just mean any game with any amount of strategy because that would be most games. What specifically differentiates incremental games from the rest?

              "Incremental" implies it's a genre defined by a game mechanic, but all those game mechanics it could imply exist in many other games. Having a skill tree or upgrades doesn't make you incremental, and if a reset mechanic is all it takes then every roguelite would be an incremental as well. So clearly there's more to it than that - what makes an incremental an incremental?

              I'd like to go over a couple of popular suggestions I've seen on defining the genre here. I have my personal preferences and will state them here, but I don't think there's a truly perfect answer here.

              Disclaimer: I mostly play incremental games on my computer, and my definitions will be heavily biased towards the games I'm familiar with.

              Incrementals vs Idlers vs Clickers

              Oftentimes people refer to this genre as idle games and/or clicker games. You'll even find a trend of oxymoronic game titles that contain both terms. "Incremental games" is the umbrella term both those terms fall under. However, I'd like to argue that not only is it better to just use the term "incremental games", but calling them "idle games" or "clicker games" is wrong. Almost universally, these terms are used interchangeably to refer to the same kind of game, where you start the game click spamming and eventually automate the process. Frankly, that kind of game deserves neither title, and the genre of incremental games has trended away from ever requiring click spamming, as it's a bad mechanic, anyways.

              While these games do span a spectrum of how active it requires you to be, and sorting games by that metric can be useful for those looking for a particular experience, the borders of when an incremental game counts as an "idler" is too blurry for the term to be useful. "Incremental games" may not be a great descriptive term for the genre (hence this many thousands of words long page on defining what the genre even is), but it's strictly better than calling them "idler" or "clicker" games. This guide will always use the term "incremental games" unless quoting someone else, as it is the term you typically see on all modern games in the genre.

              Incrementals as Parodies

              Let's start with one of the most interesting definitions of incremental games. Incremental games appear to be distilled versions of games or genres, "revealing" the naked game design at the core of these games or genres not unlike how parodies comment upon their source material.

              To understand what that means, think of how a casino uses skinner boxes to emotionally manipulate its customers to keep playing, but "dressing" up the skinner box with tons of stimuli to hide that ultimately the goal is to condition you into coming back compulsively. The idea that incremental games are parodies means taking the stance that at some level all games are similarly manipulating you, giving dopamine rewards in a way that manipulates you to keep playing while not necessarily giving you any value or fulfillment. Incremental games, then, are any games that plainly display the skinner box, and the manipulative core of the game, at the forefront of the experience.

              While incremental games can be fun and even healthy in certain contexts, they can exacerbate video game addiction more than other genres. If you feel like playing incremental games is taking priority over other things in your life, or manipulating your sleep schedule, it may be prudent to seek help. See r/StopGaming for resources.

              This "undressing" tends to go hand in hand with a reduced focus on aesthetics, often just printing the game state directly to the screen as text. This makes incremental games much easier to develop, particularly for those with programming skills but not art skills, but that's a tangent for why Incremental Games Guide to Incrementals/Appeal to Developers.

              Before I continue, I'd like to make my stance clear that I love games and incremental games, and do not think they should be considered inherently bad or manipulative with the above logic. Skinner boxes are just a way of manipulating behavior via rewards. The games are still fun - that's the reward! I'd believe the real criticism here is that it is "empty fun", or "empty dopamine", that doesn't offer any additional value or sense of fulfillment. I don't think that's inherently bad in moderation, although it can become a problem if the game is manipulating you for profit-seeking, or if you play the game to the detriment of the other parts of your life.

              Another interpretation of incremental games as parodies comes from several mainstream incremental games that are also parodies of capitalism, such as cookie clicker and adventure capitalist. It's a very common framework for incremental games to portray the ever-increasing numbers as an insatiable hunger for resources, like the ones observed within capitalism. Therefore, these games are used as evidence that the genre as a whole is about parody and commentary.

              Popular videos on incremental games that portray the genre as parodies are Why Idle games make good satire, and how it was ruined. and Bad Game Design - Clicker Games. You may also be interested in this response to the latter video from a fan of incremental games: BadGood Game Design - Clicker Games.

              I think that this definition ultimately ascribes a motive to the genre as a whole that only happens to apply to some of the more mainstream titles. There certainly are incremental games commenting on different things, including the genre itself as in the case of The Prestige Tree Classic, The Ascension Tree, or Omega Layers, but certainly not all. And of course, not all games that comment on something or parody something are incremental games! Additionally, a very large majority of incremental games are mobile games using these manipulative strategies to get players to spend as much money as possible - hell, Adventure Capitalist is ostensibly a critique on capitalism but features microtransactions and gameplay that manipulates you into buying them! These profit-seeking incremental games certainly belong within the genre but are hardly parodies when they too use manipulation to serve their interests. Also, from my own anecdotal experience, those who use this definition seem to do so from a fairly surface-level familiarity with the genre, and often in the context of criticizing the genre or the fans thereof.

              Incrementals as NGU

              Another broad definition often used is that incremental games are games where the focus of the game is "numbers going up". This definition proposes that other genres simply use increasing numbers as a means to an end, but incremental games uniquely only care about the numbers themselves going up. Put another way, it implies there should be no narrative justification for the numbers going up other than "why shouldn't they be going up?"

              While this definition is common because it feels easy to understand, it is difficult to formally define. Often phrases are used to describe games using this framework, such as having an "exaggerated sense of progression" or "big" numbers. These terms are vague and don't demonstrate an actual threshold between non-incrementals and incrementals. Most games have a sense of progression, so when is it "exaggerated"? How big are "big" numbers? Most notably, RPGs that are typically not considered incrementals will often pass this definition.

              Additionally, a lot of incrementals tend to have some theme guiding the gameplay, or at least the names of mechanics. This makes the line blurred between when numbers are going up for their own sake versus for a contextual reason. I believe this point is best illustrated that, while most RPGs are not considered incremental games, there is a sub-genre of "incremental RPGs" that typically relates to RPGs that perform combat automatically. This definition of incremental games does not support RPGs and "incremental RPGs" being on distinct sides of the line if the only difference between them is manual vs automatic combat.

              Incrementals as Strategies

              This is a rarer interpretation, but there are similarities between incremental games and strategy games, implying incrementals might just be a sub-genre of strategy games. By this approach, incremental games would be defined by their relation to strategy games, and how they involve player strategy. Incremental games are often large optimization problems - above all else, the actual gameplay the player is performing is deciding what to do next. The consequences of wrong decisions are typically more lenient in incremental games - such as just not making optimal progress - but they certainly get complex.

              So if we accept the premise that incrementals could fall under strategy, we still need to define what makes a strategy game an incremental versus some other strategy sub-genre. This is a bit tricky due to one particular sub-genre of strategy games: Factory Builders.

              Factory builders, such as Factorio or Satisfactory, are games about gaining ever increasing resources, optimizing production, and expanding more and more. That... sounds pretty similar, doesn't it? In fact, there's been some debate on whether factory builders would fall under the "incremental" umbrella. I think it's safe to say the two are certainly related, and probably have quite a bit of overlap in playerbase.

              Roguelites as Incrementals?

              Earlier on, I mentioned reset mechanics shouldn't be used in the definition because that could make all roguelites incrementals... But what if it does? A lot of incrementals can be described as games with a strong sense of progression, often with layers of meta-progression. Roguelites fit that bill to a T. What would make roguelites not incremental? I honestly don't think there's a good explanation here, but many fans of incremental games will state they do believe the two genres to be unrelated, even if there's a significant overlap between their player bases due to having similar appealing traits.

              At this point, it'd be appropriate to consider what part of the definition of roguelites precludes them from also being incrementals, but that reveals a new problem: What are roguelites? They're usually defined as rogue_likes with meta-progression, but that just pushes the problem back a step: Incrementals aren't the only genre to have difficulties defining themselves, it seems! Roguelikes are another genre where the community argues over the formal definition of their genre, although that means we can borrow from their process of coming to a consensus, and maybe come across a viable definition for incremental games.

              The Berlin Interpretation

              By far the most popular way of defining roguelikes is the "Berlin Interpretation", which acknowledged the diversity of games within the genre and argued the definition should not be based on any ideals about what the genre ought to be, but rather defined by "its canon". They argued there are a handful of games that can be used to define the canon for roguelikes, and from those games, a list of factors can be derived to determine a game's "roguelikeness". The more factors a game has, the more of a roguelike it is. This strategy is very lenient, allowing a game to not present any specific factor so long as it shows enough, and accounts for the blurriness of any genre definition by not explicitly stating how many factors a game must have to qualify as a definite roguelike.

              I believe this strategy for defining genres can be applied to other genres as well. A handful of games can be argued to be the incremental games canon, and a list of factors derived from them can be used to judge any game based on its "incrementalness". I'll propose such a canon and list of factors here, but by no means should it be considered the end-all-be-all.

              Note: The "Temple of the roguelike", an authority within the genre, has since replaced the Berlin Interpretation with a new set of factors here: https://blog.roguetemple.com/what-is-a-traditional-roguelike/

              The Incremental Games Canon

              Alright, time to get controversial. Up til now, I've been trying my best to stay objective and analytical, but now it's time to start making some opinionated decisions. Here is a list of games I think could justifiably make up an Incremental Games Canon:

              I chose a variety of games here, biasing towards newer games, purposefully to avoid making a narrow or "traditional" definition. The genre is growing and shouldn't be constrained by the traits of the early popular titles. A lot of these could easily be replaced with other games that are mechanically congruent, so ultimately I'm sure if you asked 10 people for their canon list you'd just get 10 different answers, but I think this should sufficiently allow us to determine what factors make a game have higher "incrementalness".

              The Paradigm Shift

              The Paradigm Shift is probably the highest possible value factor for an incremental. It's so common that for a while people referred to incrementals that exhibit this trait as "unfolding" games, to the point of trying to replace the term incremental due to their popularity. Paradigm shifts refer to when the gameplay significantly changes. There are too many examples to list here, but notably, every single reset mechanic is typically going to be a paradigm shift. Examples of games with paradigm shifts that aren't tied to reset mechanics include Universal Paperclips and A Dark Room.

              There are many reasons for the appeal of paradigm shifts. Oftentimes each mechanic builds on top of the existing mechanics, increasing the complexity of the game in steps so the player can follow along. They provide a sense of mystery, with the player anticipating what will happen next. They shake up the gameplay before it gets too stale - allowing the game to entertain for longer before the sense of Guide to Incrementals/What is Content? dissipates. Of the canon games selected above, I would argue every single one contains a paradigm shift (although I could see someone disagreeing with that statement wrt Increlution).

              I should take a moment to say that while I'm hyping up this specific factor, we cannot just reduce the genre definition to "does it have paradigm shifts". Many games have paradigm shifts that are not incremental, so it's just an indicator of incrementalness. Additionally, it can become quite hard to determine how large of a shift is a "paradigm" shift. Take, for example, any game with a skill tree. In some games, each skill node might have a large impact on how you play with the game, and qualify as a paradigm shift for some players. In other games, each skill node might just be a small percentage modifier on some stat that doesn't really impact much more than a slight bias towards an already established mechanic that's newly buffed. Every single canon game may show that it's common amongst incremental games, but could just as easily indicate that they're common in games in general.

              High-Value Factors

              I won't take as long to discuss the high and low-value factors, as you've already seen most of them brought up earlier on this page. As a reminder, a game does NOT need all of these to be an incremental game, but these are factors that each indicate a strong possibility the game is an incremental, so having several of these means they probably are. These factors apply to most of the canon incremental games.

              "Pure UI" Display. Incrementals typically have a textual presentation of the game state - there isn't a visual representation of the entities within the game. The interface is closer to what would be just the UI of a game in another genre or the control panel of a plane. If there is a visual representation, the player is often still interacting with non-diegetic game elements.

              Reduced Consequences. Incrementals tend to have reduced repurcussions for misplaying. They very rarely have fail states, where often the largest consequence is simply not progressing - never losing progress.

              Optimization Problems. The predominant gameplay of incrementals is typically solving optimization problems, from deciding which purchase to save up for to reasoning and deciding between different mutually exclusive options the game presents.

              Resource Management. Incrementals tend to have a lot of resources within the game to keep track of.

              Low-Value Factors

              These are low-value factors, meaning they aren't as strongly correlated with incremental games. Incremental games may have none of these, and non-incrementals may have several of these - if a game only has low-value factors, they're probably not an incremental.

              Fast Numeric Growth. Numbers in incremental games tend to grow faster than in other genres. There are more instances of superlinear growth. The larger the numbers get, the stronger of a signal this factor is.

              Automation. As an incremental game progresses, the player often no longer has to deal with earlier mechanics, by having them either happen automatically or otherwise be replaced with an alternative that requires less player interaction.

              Goal-Oriented. Incrementals are often heavily reliant on extrinsic motivation to guide the player. Typically this is through some sort of in-game goal to work towards, such as a certain amount of a resource being required to unlock or purchase something new.

              Waiting is a Mechanic. In incremental games, the player may come across times where there is no action they can take, and the game will progress automatically instead. The player must wait for some amount of this automatic progress to occur before they can resume interaction with the game.

              Are Roguelites Incrementals?

              Having made our variation of the Berlin Interpretation for incremental games, we can compare it to the Berlin Interpretation to determine if there's enough overlap that any game that "passes" the Berlin Interpretation would also pass the incremental variant. That is to say, whether any roguelite would also be considered an incremental game.

              The meta-progression of an incremental game could arguably be considered a paradigm shift, and certainly adds some resource management. Goal-oriented would probably also apply. I think anything other than those would be a stretch, and in my opinion that just isn't enough to qualify. To be totally honest, I was never expecting to conclude otherwise though 😉

              Sub-Genres

              There are some trends in incremental games that go beyond just being a commonly used mechanic, such that they deeply affect the rest of the game design. These trends can be used to determine sub-genres within the incremental games umbrella:

              Loops games are a sub-genre defined by having a core mechanic related to a loop, where the player is deciding the actions taken per loop. Notable examples include Idle Loops, Stuck in Time, Cavernous II, and Increlution. You may also argue Groundhog Life and Progress Knight fall into this sub-genre.

              ITRTG-like games are a sub-genre defined by having a core mechanic based on clearing increasingly difficult battles and often tend to have a lot of different mechanics to become progressively stronger. Notable examples include Idling to Rule the Gods, NGU Idle, and Wizard and Minion Idle.

              Polynomial Growth games are a sub-genre defined by having a core mechanic related to a higher degree polynomial. Notable examples include the base layer of Antimatter Dimensions and Swarm Simulator.

              Upgrades Games is a category popular on flash games websites that featured games focused on buying upgrades that would allow you to attain more currency in some sort of minigame that would earn you more money to buy more upgrades, which I'd argue now belong under the fold of incremental games. Notable examples include the Learn to Fly series and Upgrade Complete.

              Cultivation RPGs are a genre of games, books, and anime popular in China that center around being in a fantasy world with characters getting stronger over time. While few of them get translated into English, a fan of incremental games may find the available games interesting.

              - +.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              Video games are placed into genres for a variety of reasons. They can give a mental shorthand to set the player's expectations up, they can help a game market itself by its similarities to other, already popular games, and honestly, people just love categorization for its own sake. For this guide, it's important to define the genre so it is clear what games it's even talking about.

              This poses a problem. "Incremental" is a horribly vague way to define games. Most games have numbers going up in some form or another. We need a more specific definition - similar to how "strategy" can't just mean any game with any amount of strategy because that would be most games. What specifically differentiates incremental games from the rest?

              "Incremental" implies it's a genre defined by a game mechanic, but all those game mechanics it could imply exist in many other games. Having a skill tree or upgrades doesn't make you incremental, and if a reset mechanic is all it takes then every roguelite would be an incremental as well. So clearly there's more to it than that - what makes an incremental an incremental?

              I'd like to go over a couple of popular suggestions I've seen on defining the genre here. I have my personal preferences and will state them here, but I don't think there's a truly perfect answer here.

              Disclaimer: I mostly play incremental games on my computer, and my definitions will be heavily biased towards the games I'm familiar with.

              Incrementals vs Idlers vs Clickers

              Oftentimes people refer to this genre as idle games and/or clicker games. You'll even find a trend of oxymoronic game titles that contain both terms. "Incremental games" is the umbrella term both those terms fall under. However, I'd like to argue that not only is it better to just use the term "incremental games", but calling them "idle games" or "clicker games" is wrong. Almost universally, these terms are used interchangeably to refer to the same kind of game, where you start the game click spamming and eventually automate the process. Frankly, that kind of game deserves neither title, and the genre of incremental games has trended away from ever requiring click spamming, as it's a bad mechanic, anyways.

              While these games do span a spectrum of how active it requires you to be, and sorting games by that metric can be useful for those looking for a particular experience, the borders of when an incremental game counts as an "idler" is too blurry for the term to be useful. "Incremental games" may not be a great descriptive term for the genre (hence this many thousands of words long page on defining what the genre even is), but it's strictly better than calling them "idler" or "clicker" games. This guide will always use the term "incremental games" unless quoting someone else, as it is the term you typically see on all modern games in the genre.

              Incrementals as Parodies

              Let's start with one of the most interesting definitions of incremental games. Incremental games appear to be distilled versions of games or genres, "revealing" the naked game design at the core of these games or genres not unlike how parodies comment upon their source material.

              To understand what that means, think of how a casino uses skinner boxes to emotionally manipulate its customers to keep playing, but "dressing" up the skinner box with tons of stimuli to hide that ultimately the goal is to condition you into coming back compulsively. The idea that incremental games are parodies means taking the stance that at some level all games are similarly manipulating you, giving dopamine rewards in a way that manipulates you to keep playing while not necessarily giving you any value or fulfillment. Incremental games, then, are any games that plainly display the skinner box, and the manipulative core of the game, at the forefront of the experience.

              While incremental games can be fun and even healthy in certain contexts, they can exacerbate video game addiction more than other genres. If you feel like playing incremental games is taking priority over other things in your life, or manipulating your sleep schedule, it may be prudent to seek help. See r/StopGaming for resources.

              This "undressing" tends to go hand in hand with a reduced focus on aesthetics, often just printing the game state directly to the screen as text. This makes incremental games much easier to develop, particularly for those with programming skills but not art skills, but that's a tangent for why Incremental Games Guide to Incrementals/Appeal to Developers.

              Before I continue, I'd like to make my stance clear that I love games and incremental games, and do not think they should be considered inherently bad or manipulative with the above logic. Skinner boxes are just a way of manipulating behavior via rewards. The games are still fun - that's the reward! I'd believe the real criticism here is that it is "empty fun", or "empty dopamine", that doesn't offer any additional value or sense of fulfillment. I don't think that's inherently bad in moderation, although it can become a problem if the game is manipulating you for profit-seeking, or if you play the game to the detriment of the other parts of your life.

              Another interpretation of incremental games as parodies comes from several mainstream incremental games that are also parodies of capitalism, such as cookie clicker and adventure capitalist. It's a very common framework for incremental games to portray the ever-increasing numbers as an insatiable hunger for resources, like the ones observed within capitalism. Therefore, these games are used as evidence that the genre as a whole is about parody and commentary.

              Popular videos on incremental games that portray the genre as parodies are Why Idle games make good satire, and how it was ruined. and Bad Game Design - Clicker Games. You may also be interested in this response to the latter video from a fan of incremental games: BadGood Game Design - Clicker Games.

              I think that this definition ultimately ascribes a motive to the genre as a whole that only happens to apply to some of the more mainstream titles. There certainly are incremental games commenting on different things, including the genre itself as in the case of The Prestige Tree Classic, The Ascension Tree, or Omega Layers, but certainly not all. And of course, not all games that comment on something or parody something are incremental games! Additionally, a very large majority of incremental games are mobile games using these manipulative strategies to get players to spend as much money as possible - hell, Adventure Capitalist is ostensibly a critique on capitalism but features microtransactions and gameplay that manipulates you into buying them! These profit-seeking incremental games certainly belong within the genre but are hardly parodies when they too use manipulation to serve their interests. Also, from my own anecdotal experience, those who use this definition seem to do so from a fairly surface-level familiarity with the genre, and often in the context of criticizing the genre or the fans thereof.

              Incrementals as NGU

              Another broad definition often used is that incremental games are games where the focus of the game is "numbers going up". This definition proposes that other genres simply use increasing numbers as a means to an end, but incremental games uniquely only care about the numbers themselves going up. Put another way, it implies there should be no narrative justification for the numbers going up other than "why shouldn't they be going up?"

              While this definition is common because it feels easy to understand, it is difficult to formally define. Often phrases are used to describe games using this framework, such as having an "exaggerated sense of progression" or "big" numbers. These terms are vague and don't demonstrate an actual threshold between non-incrementals and incrementals. Most games have a sense of progression, so when is it "exaggerated"? How big are "big" numbers? Most notably, RPGs that are typically not considered incrementals will often pass this definition.

              Additionally, a lot of incrementals tend to have some theme guiding the gameplay, or at least the names of mechanics. This makes the line blurred between when numbers are going up for their own sake versus for a contextual reason. I believe this point is best illustrated that, while most RPGs are not considered incremental games, there is a sub-genre of "incremental RPGs" that typically relates to RPGs that perform combat automatically. This definition of incremental games does not support RPGs and "incremental RPGs" being on distinct sides of the line if the only difference between them is manual vs automatic combat.

              Incrementals as Strategies

              This is a rarer interpretation, but there are similarities between incremental games and strategy games, implying incrementals might just be a sub-genre of strategy games. By this approach, incremental games would be defined by their relation to strategy games, and how they involve player strategy. Incremental games are often large optimization problems - above all else, the actual gameplay the player is performing is deciding what to do next. The consequences of wrong decisions are typically more lenient in incremental games - such as just not making optimal progress - but they certainly get complex.

              So if we accept the premise that incrementals could fall under strategy, we still need to define what makes a strategy game an incremental versus some other strategy sub-genre. This is a bit tricky due to one particular sub-genre of strategy games: Factory Builders.

              Factory builders, such as Factorio or Satisfactory, are games about gaining ever increasing resources, optimizing production, and expanding more and more. That... sounds pretty similar, doesn't it? In fact, there's been some debate on whether factory builders would fall under the "incremental" umbrella. I think it's safe to say the two are certainly related, and probably have quite a bit of overlap in playerbase.

              Roguelites as Incrementals?

              Earlier on, I mentioned reset mechanics shouldn't be used in the definition because that could make all roguelites incrementals... But what if it does? A lot of incrementals can be described as games with a strong sense of progression, often with layers of meta-progression. Roguelites fit that bill to a T. What would make roguelites not incremental? I honestly don't think there's a good explanation here, but many fans of incremental games will state they do believe the two genres to be unrelated, even if there's a significant overlap between their player bases due to having similar appealing traits.

              At this point, it'd be appropriate to consider what part of the definition of roguelites precludes them from also being incrementals, but that reveals a new problem: What are roguelites? They're usually defined as rogue_likes with meta-progression, but that just pushes the problem back a step: Incrementals aren't the only genre to have difficulties defining themselves, it seems! Roguelikes are another genre where the community argues over the formal definition of their genre, although that means we can borrow from their process of coming to a consensus, and maybe come across a viable definition for incremental games.

              The Berlin Interpretation

              By far the most popular way of defining roguelikes is the "Berlin Interpretation", which acknowledged the diversity of games within the genre and argued the definition should not be based on any ideals about what the genre ought to be, but rather defined by "its canon". They argued there are a handful of games that can be used to define the canon for roguelikes, and from those games, a list of factors can be derived to determine a game's "roguelikeness". The more factors a game has, the more of a roguelike it is. This strategy is very lenient, allowing a game to not present any specific factor so long as it shows enough, and accounts for the blurriness of any genre definition by not explicitly stating how many factors a game must have to qualify as a definite roguelike.

              I believe this strategy for defining genres can be applied to other genres as well. A handful of games can be argued to be the incremental games canon, and a list of factors derived from them can be used to judge any game based on its "incrementalness". I'll propose such a canon and list of factors here, but by no means should it be considered the end-all-be-all.

              Note: The "Temple of the roguelike", an authority within the genre, has since replaced the Berlin Interpretation with a new set of factors here: https://blog.roguetemple.com/what-is-a-traditional-roguelike/

              The Incremental Games Canon

              Alright, time to get controversial. Up til now, I've been trying my best to stay objective and analytical, but now it's time to start making some opinionated decisions. Here is a list of games I think could justifiably make up an Incremental Games Canon:

              I chose a variety of games here, biasing towards newer games, purposefully to avoid making a narrow or "traditional" definition. The genre is growing and shouldn't be constrained by the traits of the early popular titles. A lot of these could easily be replaced with other games that are mechanically congruent, so ultimately I'm sure if you asked 10 people for their canon list you'd just get 10 different answers, but I think this should sufficiently allow us to determine what factors make a game have higher "incrementalness".

              The Paradigm Shift

              The Paradigm Shift is probably the highest possible value factor for an incremental. It's so common that for a while people referred to incrementals that exhibit this trait as "unfolding" games, to the point of trying to replace the term incremental due to their popularity. Paradigm shifts refer to when the gameplay significantly changes. There are too many examples to list here, but notably, every single reset mechanic is typically going to be a paradigm shift. Examples of games with paradigm shifts that aren't tied to reset mechanics include Universal Paperclips and A Dark Room.

              There are many reasons for the appeal of paradigm shifts. Oftentimes each mechanic builds on top of the existing mechanics, increasing the complexity of the game in steps so the player can follow along. They provide a sense of mystery, with the player anticipating what will happen next. They shake up the gameplay before it gets too stale - allowing the game to entertain for longer before the sense of Guide to Incrementals/What is Content? dissipates. Of the canon games selected above, I would argue every single one contains a paradigm shift (although I could see someone disagreeing with that statement wrt Increlution).

              I should take a moment to say that while I'm hyping up this specific factor, we cannot just reduce the genre definition to "does it have paradigm shifts". Many games have paradigm shifts that are not incremental, so it's just an indicator of incrementalness. Additionally, it can become quite hard to determine how large of a shift is a "paradigm" shift. Take, for example, any game with a skill tree. In some games, each skill node might have a large impact on how you play with the game, and qualify as a paradigm shift for some players. In other games, each skill node might just be a small percentage modifier on some stat that doesn't really impact much more than a slight bias towards an already established mechanic that's newly buffed. Every single canon game may show that it's common amongst incremental games, but could just as easily indicate that they're common in games in general.

              High-Value Factors

              I won't take as long to discuss the high and low-value factors, as you've already seen most of them brought up earlier on this page. As a reminder, a game does NOT need all of these to be an incremental game, but these are factors that each indicate a strong possibility the game is an incremental, so having several of these means they probably are. These factors apply to most of the canon incremental games.

              "Pure UI" Display. Incrementals typically have a textual presentation of the game state - there isn't a visual representation of the entities within the game. The interface is closer to what would be just the UI of a game in another genre or the control panel of a plane. If there is a visual representation, the player is often still interacting with non-diegetic game elements.

              Reduced Consequences. Incrementals tend to have reduced repurcussions for misplaying. They very rarely have fail states, where often the largest consequence is simply not progressing - never losing progress.

              Optimization Problems. The predominant gameplay of incrementals is typically solving optimization problems, from deciding which purchase to save up for to reasoning and deciding between different mutually exclusive options the game presents.

              Resource Management. Incrementals tend to have a lot of resources within the game to keep track of.

              Low-Value Factors

              These are low-value factors, meaning they aren't as strongly correlated with incremental games. Incremental games may have none of these, and non-incrementals may have several of these - if a game only has low-value factors, they're probably not an incremental.

              Fast Numeric Growth. Numbers in incremental games tend to grow faster than in other genres. There are more instances of superlinear growth. The larger the numbers get, the stronger of a signal this factor is.

              Automation. As an incremental game progresses, the player often no longer has to deal with earlier mechanics, by having them either happen automatically or otherwise be replaced with an alternative that requires less player interaction.

              Goal-Oriented. Incrementals are often heavily reliant on extrinsic motivation to guide the player. Typically this is through some sort of in-game goal to work towards, such as a certain amount of a resource being required to unlock or purchase something new.

              Waiting is a Mechanic. In incremental games, the player may come across times where there is no action they can take, and the game will progress automatically instead. The player must wait for some amount of this automatic progress to occur before they can resume interaction with the game.

              Are Roguelites Incrementals?

              Having made our variation of the Berlin Interpretation for incremental games, we can compare it to the Berlin Interpretation to determine if there's enough overlap that any game that "passes" the Berlin Interpretation would also pass the incremental variant. That is to say, whether any roguelite would also be considered an incremental game.

              The meta-progression of an incremental game could arguably be considered a paradigm shift, and certainly adds some resource management. Goal-oriented would probably also apply. I think anything other than those would be a stretch, and in my opinion that just isn't enough to qualify. To be totally honest, I was never expecting to conclude otherwise though 😉

              Sub-Genres

              There are some trends in incremental games that go beyond just being a commonly used mechanic, such that they deeply affect the rest of the game design. These trends can be used to determine sub-genres within the incremental games umbrella:

              Loops games are a sub-genre defined by having a core mechanic related to a loop, where the player is deciding the actions taken per loop. Notable examples include Idle Loops, Stuck in Time, Cavernous II, and Increlution. You may also argue Groundhog Life and Progress Knight fall into this sub-genre.

              ITRTG-like games are a sub-genre defined by having a core mechanic based on clearing increasingly difficult battles and often tend to have a lot of different mechanics to become progressively stronger. Notable examples include Idling to Rule the Gods, NGU Idle, and Wizard and Minion Idle.

              Polynomial Growth games are a sub-genre defined by having a core mechanic related to a higher degree polynomial. Notable examples include the base layer of Antimatter Dimensions and Swarm Simulator.

              Upgrades Games is a category popular on flash games websites that featured games focused on buying upgrades that would allow you to attain more currency in some sort of minigame that would earn you more money to buy more upgrades, which I'd argue now belong under the fold of incremental games. Notable examples include the Learn to Fly series and Upgrade Complete.

              Cultivation RPGs are a genre of games, books, and anime popular in China that center around being in a fantasy world with characters getting stronger over time. While few of them get translated into English, a fan of incremental games may find the available games interesting.

              + \ No newline at end of file diff --git a/garden/guide-to-incrementals/index.html b/garden/guide-to-incrementals/index.html index 480a5a3c..41e973b2 100644 --- a/garden/guide-to-incrementals/index.html +++ b/garden/guide-to-incrementals/index.html @@ -6,14 +6,14 @@ Guide to Incrementals | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Guide to Incrementals

              230 words, ~1 minute read. Planted +

              Skip to content

              Guide to Incrementals

              230 words, ~1 minute read. Planted . Last tended to -.


              Referenced by:My Personal Website

              This is a comprehensive guide to Incremental Games, a genre of video games. It will explore defining the genre, why it's appealing, and how to design and build your own incremental game. Along the way will be interactive examples, snippets from other creators, and relevant material to contextualize everything.

              Note: This is an incomplete document. I want to keep adding opinions and opposing views from other incremental games developers, and add interactive examples to illustrate various points regarding game design and balancing. Consider this a living document - and see the changelog at the end.

              Why am I making this?

              That's a good question! What authority do I have to be making this guide? I haven't made the best incremental games, nor the most incremental games, certainly not the most popular ones either. But I do have some formal education in game development, know a lot of incremental game devs (as well as other game devs), and have a passionate interest in ludology, classifying genres, etc. I've also made a couple of incremental games) myself.

              If you have any additional questions about my credentials or anything on this site, feel free to reach out!

              Ludology

              Making an Incremental

              - +.


              Referenced by:My Personal Website

              This is a comprehensive guide to Incremental Games, a genre of video games. It will explore defining the genre, why it's appealing, and how to design and build your own incremental game. Along the way will be interactive examples, snippets from other creators, and relevant material to contextualize everything.

              Note: This is an incomplete document. I want to keep adding opinions and opposing views from other incremental games developers, and add interactive examples to illustrate various points regarding game design and balancing. Consider this a living document - and see the changelog at the end.

              Why am I making this?

              That's a good question! What authority do I have to be making this guide? I haven't made the best incremental games, nor the most incremental games, certainly not the most popular ones either. But I do have some formal education in game development, know a lot of incremental game devs (as well as other game devs), and have a passionate interest in ludology, classifying genres, etc. I've also made a couple of incremental games) myself.

              If you have any additional questions about my credentials or anything on this site, feel free to reach out!

              Ludology

              Making an Incremental

              + \ No newline at end of file diff --git a/garden/guide-to-incrementals/navigating-criticism/index.html b/garden/guide-to-incrementals/navigating-criticism/index.html index 5281e52c..513d166e 100644 --- a/garden/guide-to-incrementals/navigating-criticism/index.html +++ b/garden/guide-to-incrementals/navigating-criticism/index.html @@ -6,14 +6,14 @@ Guide to Incrementals/Navigating Criticism | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Guide to Incrementals___Navigating Criticism

              747 words, ~4 minute read. Planted +

              Skip to content

              Guide to Incrementals___Navigating Criticism

              747 words, ~4 minute read. Planted . Last tended to -.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              Developing games is fun and exciting and teaches a lot of wonderful skills - I enthusiastically encourage anyone with an interest in game development to try it out - and incremental games are a wonderful way to get started. However, there are many challenges young and inexperienced developers have to face, and I think the hardest one - harder than coding, debugging, balancing, etc. - is handling criticism. When you put your heart and soul into a game it is natural to feel very vulnerable. While I think there's a lot communities can do to ensure they're welcoming, positive and constructive with their criticisms, inevitably you will eventually read some, and potentially a lot, of comments that can deeply affect you. No one is immune to this, from young incremental game developers to the largest content creators you can think of. That's why it's important to be able to process and navigate criticism, because ultimately collecting feedback is essential to the journey to becoming a better developer. On this page, we'll explore how to embrace criticism, grow from it, and continue to post your games publicly with confidence.

              Reading Feedback

              Game development is a skill that takes time and practice to get truly great at. Criticism and other constructive feedback are vital to continually improving. It's useful to look at the criticism as solely a tool for improving this game and future games - that is to say, it should never be used against you as a person. Insults towards the developer(s) themselves are never okay and should not be allowed within whatever community you're sharing your works in. If you do come across a comment you interpret as an attack upon your person, you should report it. For other negative comments, try not to internalize them; instead, focus on improving the game. By distancing your own identity from your work emotionally, you can better analyze the game and use the feedback to your advantage.

              Not all feedback is made equal, and you don't need to feel compelled to read and obey every piece of feedback you receive. Learn to distinguish between constructive feedback and unhelpful comments. Constructive feedback typically offers specific suggestions for improvement, while unhelpful comments are often vague or hurtful. Prioritize the former and disregard the latter. That said, most feedback you get will not be from game developers, so take specific suggestions with a grain of salt. Determine the actual problem they're experiencing, and design what you believe the best solution to that problem would be, regardless if that's the specific solution the player asked for. And keep in mind, due to different player preferences you'll never satisfy everyone, and you don't need to. Ultimately if even just you find the game fun, then that's a success.

              Seeking Feedback

              When deciding where to share your game, consider the type of players you anticipate getting, and the kind of feedback you can anticipate receiving. Different communities will have different levels of support for learning developers, and certain communities may prefer certain types of games or mechanics. It's important to get a diverse set of feedback focused on players you think will enjoy the specific game you're making.

              Collecting feedback from other game developers is incredibly helpful. They've trained themselves to recognize good and bad game design and how to articulate the differences, and from my experience are much more likely to leave positive and constructive comments since they've been in your shoes before! They understand the struggles and can offer guidance and emotional support.

              Responding to Feedback

              Negative feedback can naturally feel like an attack, and it's okay to get angry. However, lashing back is never the appropriate response. It's best to cool off IRL, and keep in mind all the positive comments you've received. There's a concept in Psychology called negative bias that explains how negative feedback tends to stick with us much more prominently than positive feedback, so it's useful to regularly remind yourself of all the positive feedback you've received. Celebrate your successes, no matter how small they may seem - getting a game to a state you can publicly share it with people is an accomplishment in and of itself!

              Remember your passion and your initial reasons for getting into game development. The journey will have its ups and downs, but staying true to your vision and passion will keep you motivated.

              - +.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              Developing games is fun and exciting and teaches a lot of wonderful skills - I enthusiastically encourage anyone with an interest in game development to try it out - and incremental games are a wonderful way to get started. However, there are many challenges young and inexperienced developers have to face, and I think the hardest one - harder than coding, debugging, balancing, etc. - is handling criticism. When you put your heart and soul into a game it is natural to feel very vulnerable. While I think there's a lot communities can do to ensure they're welcoming, positive and constructive with their criticisms, inevitably you will eventually read some, and potentially a lot, of comments that can deeply affect you. No one is immune to this, from young incremental game developers to the largest content creators you can think of. That's why it's important to be able to process and navigate criticism, because ultimately collecting feedback is essential to the journey to becoming a better developer. On this page, we'll explore how to embrace criticism, grow from it, and continue to post your games publicly with confidence.

              Reading Feedback

              Game development is a skill that takes time and practice to get truly great at. Criticism and other constructive feedback are vital to continually improving. It's useful to look at the criticism as solely a tool for improving this game and future games - that is to say, it should never be used against you as a person. Insults towards the developer(s) themselves are never okay and should not be allowed within whatever community you're sharing your works in. If you do come across a comment you interpret as an attack upon your person, you should report it. For other negative comments, try not to internalize them; instead, focus on improving the game. By distancing your own identity from your work emotionally, you can better analyze the game and use the feedback to your advantage.

              Not all feedback is made equal, and you don't need to feel compelled to read and obey every piece of feedback you receive. Learn to distinguish between constructive feedback and unhelpful comments. Constructive feedback typically offers specific suggestions for improvement, while unhelpful comments are often vague or hurtful. Prioritize the former and disregard the latter. That said, most feedback you get will not be from game developers, so take specific suggestions with a grain of salt. Determine the actual problem they're experiencing, and design what you believe the best solution to that problem would be, regardless if that's the specific solution the player asked for. And keep in mind, due to different player preferences you'll never satisfy everyone, and you don't need to. Ultimately if even just you find the game fun, then that's a success.

              Seeking Feedback

              When deciding where to share your game, consider the type of players you anticipate getting, and the kind of feedback you can anticipate receiving. Different communities will have different levels of support for learning developers, and certain communities may prefer certain types of games or mechanics. It's important to get a diverse set of feedback focused on players you think will enjoy the specific game you're making.

              Collecting feedback from other game developers is incredibly helpful. They've trained themselves to recognize good and bad game design and how to articulate the differences, and from my experience are much more likely to leave positive and constructive comments since they've been in your shoes before! They understand the struggles and can offer guidance and emotional support.

              Responding to Feedback

              Negative feedback can naturally feel like an attack, and it's okay to get angry. However, lashing back is never the appropriate response. It's best to cool off IRL, and keep in mind all the positive comments you've received. There's a concept in Psychology called negative bias that explains how negative feedback tends to stick with us much more prominently than positive feedback, so it's useful to regularly remind yourself of all the positive feedback you've received. Celebrate your successes, no matter how small they may seem - getting a game to a state you can publicly share it with people is an accomplishment in and of itself!

              Remember your passion and your initial reasons for getting into game development. The journey will have its ups and downs, but staying true to your vision and passion will keep you motivated.

              + \ No newline at end of file diff --git a/garden/guide-to-incrementals/what-is-content/index.html b/garden/guide-to-incrementals/what-is-content/index.html index 9ca3aeb7..f7adc027 100644 --- a/garden/guide-to-incrementals/what-is-content/index.html +++ b/garden/guide-to-incrementals/what-is-content/index.html @@ -6,14 +6,14 @@ Guide to Incrementals/What is Content? | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Guide to Incrementals___What is Content?

              2092 words, ~11 minute read. Planted +

              Skip to content

              Guide to Incrementals___What is Content?

              2092 words, ~11 minute read. Planted . Last tended to -.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              If you've been in the incremental games community for any amount of time, you'll quickly find the number one thing players want is content. They want as much of it as possible! The most popular incremental games have tons of content, so they just keep stretching on and on and on, introducing mechanic after mechanic, and players love it. In fact, players seem to value the amount of content over the quality of any specific content. However, there's a bit of a lack of understanding concerning what content is, and I'd like to explore what counts as content, and how we measure it. As a baseline definition, I think "content" can just be described as the parts of the game that engage the player, but to truly understand it we need to contextualize what that means and how it affects the gameplay experience.

              To clarify the purpose of this page, my goal is not to get (too) nitpicky or to attack games with "low content". There's nothing wrong with short / low-content games - I'm quite a big fan of those games myself! This is mostly targeted toward those who ask for content and settle for "long" games, and those who want to provide content but want to make sure they're not just artificially inflating the game. Ultimately, I suppose the goal is to just reduce the amount of artificially inflated content for the sake of having a "longer" game.

              Interaction

              I think it should be a fairly non-controversial opinion that time spent solely waiting should not count towards content. That is not including the time reading various effects or making decisions in your head, but rather time spent waiting for a condition to be met so you can re-engage with the game.

              That is not to say games should necessarily try to minimize this time. Plenty of games lead towards more infrequent interaction and still get popular. In fact, these games appeal to many gamers who want to have something to check up on in between bursts of working on some other activity. These games seem to have fallen slightly out of fashion amongst modern incremental games, but they're still fully valid. The point I'm trying to make here is just that this time is not content. As an extreme example, a game with no interactions and just a counter that goes up every second could safely be said to have 0 content beyond the time it takes to understand what's going on. If it has a list of "goals" to hit, then the time understanding those goals and a short time after achieving each one could be considered content, but not the idle times in between.

              Let's take a look at the opposite end of the spectrum - interaction that is so frequent as to become mindless. This is any mechanic where you need to spam-click something to progress. This may be a more controversial take, but I do not believe this constitutes content either. It does not engage the player, because each consecutive click blends together and they do not individually change the gameplay experience. That is to say, a single click and 100 clicks are not meaningfully different in terms of engaging the player. I'd go as far as to say clicking 100 times would be actively worse, as it's artificially delaying the next piece of actual content, alongside the issues of accessibility and potentially causing RSI.

              Repeatable Purchases

              Imagine an entity in a game that you can purchase multiple times, each time it performs the same thing but for a higher cost. These are incredibly common, from the buildings in cookie clicker to the units in swarm sim to the IP and EP multipliers in antimatter dimensions. However, how much content is each specific purchase? Is it content beyond the first purchase? Does it have diminishing returns? What if you are oscillating between two different repeatable purchases? How much content is lost when you automate) away a repeatable purchase?

              I don't want to take too harsh a stance against repeatable purchases. They're useful tools and can be used in a myriad of interesting ways. I feel they do become "stale" or less meaningful content over time, and this happens exponentially quickly the more frequently it can be purchased. A classic example that I believe goes too far is the IP/EP multipliers in Antimatter Dimensions. I would go as far as to say they are a chore and do not provide any meaningful content after you've bought them a couple of times. It's a method for inflating numbers (effectively making every OOM a 5x step instead of 10x), that punishes the player progression-wise whenever they forget to max it again, and eventually gets automated away as a reward to the player for making enough progress.

              Just to voice the other side of this argument, Acamaeda defended the IP multiplier as giving the player a "good" upgrade every OOM. I can understand that to a point and need to clarify I'm mainly criticizing IP/EP multipliers after they've been introduced for a while. In fact, I would defend the multipliers for a short while after they're introduced using the same logic I would use to defend normal dimensions as repeatable purchases, at least pre-infinity. There's "content" to be had in looking at what dimensions will become affordable next, and then choosing which to buy amongst those. The IP/EP multipliers, early into infinity or eternity respectively, provide another option that gets put into that mental queue of things to buy with each OOM reached - although the optimal order is often quite trivial and not particularly engaging.

              The IP/EP multipliers are not the only repeatable purchase in antimatter dimensions I take offense to. The time dimensions are also a series of repeatable purchases, that are all so similar and static that it doesn't take long before you never need to put any thought into buying them, how much you're buying at once, or the order you buy them in - you just press max all and move on. The entire tab could've been just the max all button and it would not have made a difference beyond the start of the eternity layer. The normal dimensions technically have this problem as well, but since you're constantly getting antimatter the order feels like it has a larger impact and it's more meaningful content, right up until they're automated away. Infinity dimensions are a compromise between the two, so I'm highlighting time dimensions here as the most egregious.

              Following Instructions

              We're getting more and more controversial as we go along! Let's talk about how linear content is not content now (in some circumstances). A trend in incremental games is adding difficulty by adding a web of effects that abstract the true change you can expect from any specific purchase or decision you make. If a game is both linear and sufficiently abstracts the effect of player decisions, then the player will no longer be engaging with the content - they'll simply be clicking on things as they become available. This isn't necessarily a bad thing, as plenty of players don't mind this style of gameplay, but I'd argue once you reach a point where players don't bother reading the effects, those interactions are no longer truly content. Note that unlike the previous qualifiers mentioned, this qualifier is based on the player, and therefore subjective. In effect, it's a spectrum where the more complicated the web of effects becomes, the more likely it is to disengage the player.

              This over-complicatedness leading to disengaging the player can also happen from non-linear gameplay. If the web of effects becomes sufficiently complicated and finding the optimal progression route too time-consuming to discover, players will seek out guides from other players who've completed the game. The second they do this, the game effectively becomes linearly following the instructions of the guide and all the above criticisms apply. Similarly to as before, though, this is a spectrum and not everyone will seek out a guide at the same level of difficulty.

              Automation

              Automation is a staple of the genre, but it has certain implications for the design of the game. Why, when new content is introduced, must the older content be automated away - why is it a chore and it feels rewarding to not have to do it again? Why does the new mechanic have such appeal if we know it too will just be automated away later on, and we'll be happy when that happens? It honestly begs the question of why this framework of introducing content and automating the old content is even enjoyable - and nearly nonexistent in other genres. You're not going to reach a point in a platformer game where they just automate the jumping part - that's the core mechanic! Instead, platformers either add new mechanics that build on the core mechanic or at least re-contextualize the core mechanic. However, in incremental games new content very frequently means replacing older content, as opposed to augmenting it.

              Admittedly, the above paragraph ignores the obvious answer that separates incremental games in this regard. These mechanics become chores as their frequency increases. The frequency increases to give a sense of progression, and automation is seen as a reward because it now manages what was becoming unmanageable. The new content then comes in and continues the loop to give a stronger sense of progression. That's all good and a fine justification for automating content instead of building upon the base mechanic. It's also much easier to design, as each layer essentially lets you start over instead of needing to think of ideas that conform to the original core mechanic.

              So, what's the problem? Even if this trend is justified and easy to implement, there are some other effects it has on the game design. First off, and this is probably a neutral point, incremental games with this cycle of replacing old mechanics with new ones trend towards more and more abstract and further away from any narrative throughline as they add layers. There are only so many justifications for resetting progress, so if a game wants to have several of these layers they're inevitably going to become generic or increasingly loosely associated with the original content. It's most unfortunate, in my opinion when an interesting or innovative core mechanic gets fully automated once a generic "prestige" layer is unlocked.

              A recent example is Really Grass Cutting Incremental, an incremental game about cutting grass (although I'm really criticizing the Roblox game it's based on). Except, it doesn't continue to be about cutting grass. After you buy enough upgrades to increase your grass cutting and level up sufficiently you "prestige", an abstract term that in this case means you reset all your progress to get some currency to buy upgrades that do the same things as the original upgrades, but these won't reset on future prestiges. You'll eventually be able to "crystallize", which means you reset all your progress to get some currency to buy upgrades that do the same things as the original upgrades (and a couple of new ones) and won't reset on future crystallizes. Fine. You'll progress a bit, complete some challenges, and finally get to... grasshop? Grasshopping is this mechanic where you reset all your progress to get some resource that isn't for buying upgrades - this time you just unlock different modifiers on everything based on their amount. You may have gotten the point by now, but there are also "steelie" resets which give you steel for some reason, before unlocking a factory with various machines - none of which are directly tied to cutting grass, and start gathering things like oil and reset for rocket parts and reset to go to space and so on and so on. Throughout all of this there is absolutely no narrative justification or throughline for the direction the game is going, or why cutting grass is still relevant when we're collecting things like rocket parts. I may be going a little hard on GCI, but it is far from alone.

              Tips for Developers

              If you're a developer, by this point you should have a pretty decent idea of how to create "true" content in your game. Here are some other specific tips I'd suggest:

              An upgrade that simply unlocks another upgrade trivially isn't content. However, many games have an upgrade that just unlocks a feature, which then has a wait or other requirements before it can be used. Try to make sure when you unlock a feature, there is immediately something to do with the feature - for example, perhaps give them a small amount of the new currency it unlocks, if applicable.

              If you don't have a large web of effects, and can definitively say the impact of a purchase is to multiply the gain of the cost currency by N, and the next purchase costs N times the amount of that same currency, then this purchase effectively made no difference and it may have made more sense to just go directly to the next upgrade. That said, having effects based on things like the number of purchases made will quickly invalidate this tip.

              - +.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              If you've been in the incremental games community for any amount of time, you'll quickly find the number one thing players want is content. They want as much of it as possible! The most popular incremental games have tons of content, so they just keep stretching on and on and on, introducing mechanic after mechanic, and players love it. In fact, players seem to value the amount of content over the quality of any specific content. However, there's a bit of a lack of understanding concerning what content is, and I'd like to explore what counts as content, and how we measure it. As a baseline definition, I think "content" can just be described as the parts of the game that engage the player, but to truly understand it we need to contextualize what that means and how it affects the gameplay experience.

              To clarify the purpose of this page, my goal is not to get (too) nitpicky or to attack games with "low content". There's nothing wrong with short / low-content games - I'm quite a big fan of those games myself! This is mostly targeted toward those who ask for content and settle for "long" games, and those who want to provide content but want to make sure they're not just artificially inflating the game. Ultimately, I suppose the goal is to just reduce the amount of artificially inflated content for the sake of having a "longer" game.

              Interaction

              I think it should be a fairly non-controversial opinion that time spent solely waiting should not count towards content. That is not including the time reading various effects or making decisions in your head, but rather time spent waiting for a condition to be met so you can re-engage with the game.

              That is not to say games should necessarily try to minimize this time. Plenty of games lead towards more infrequent interaction and still get popular. In fact, these games appeal to many gamers who want to have something to check up on in between bursts of working on some other activity. These games seem to have fallen slightly out of fashion amongst modern incremental games, but they're still fully valid. The point I'm trying to make here is just that this time is not content. As an extreme example, a game with no interactions and just a counter that goes up every second could safely be said to have 0 content beyond the time it takes to understand what's going on. If it has a list of "goals" to hit, then the time understanding those goals and a short time after achieving each one could be considered content, but not the idle times in between.

              Let's take a look at the opposite end of the spectrum - interaction that is so frequent as to become mindless. This is any mechanic where you need to spam-click something to progress. This may be a more controversial take, but I do not believe this constitutes content either. It does not engage the player, because each consecutive click blends together and they do not individually change the gameplay experience. That is to say, a single click and 100 clicks are not meaningfully different in terms of engaging the player. I'd go as far as to say clicking 100 times would be actively worse, as it's artificially delaying the next piece of actual content, alongside the issues of accessibility and potentially causing RSI.

              Repeatable Purchases

              Imagine an entity in a game that you can purchase multiple times, each time it performs the same thing but for a higher cost. These are incredibly common, from the buildings in cookie clicker to the units in swarm sim to the IP and EP multipliers in antimatter dimensions. However, how much content is each specific purchase? Is it content beyond the first purchase? Does it have diminishing returns? What if you are oscillating between two different repeatable purchases? How much content is lost when you automate) away a repeatable purchase?

              I don't want to take too harsh a stance against repeatable purchases. They're useful tools and can be used in a myriad of interesting ways. I feel they do become "stale" or less meaningful content over time, and this happens exponentially quickly the more frequently it can be purchased. A classic example that I believe goes too far is the IP/EP multipliers in Antimatter Dimensions. I would go as far as to say they are a chore and do not provide any meaningful content after you've bought them a couple of times. It's a method for inflating numbers (effectively making every OOM a 5x step instead of 10x), that punishes the player progression-wise whenever they forget to max it again, and eventually gets automated away as a reward to the player for making enough progress.

              Just to voice the other side of this argument, Acamaeda defended the IP multiplier as giving the player a "good" upgrade every OOM. I can understand that to a point and need to clarify I'm mainly criticizing IP/EP multipliers after they've been introduced for a while. In fact, I would defend the multipliers for a short while after they're introduced using the same logic I would use to defend normal dimensions as repeatable purchases, at least pre-infinity. There's "content" to be had in looking at what dimensions will become affordable next, and then choosing which to buy amongst those. The IP/EP multipliers, early into infinity or eternity respectively, provide another option that gets put into that mental queue of things to buy with each OOM reached - although the optimal order is often quite trivial and not particularly engaging.

              The IP/EP multipliers are not the only repeatable purchase in antimatter dimensions I take offense to. The time dimensions are also a series of repeatable purchases, that are all so similar and static that it doesn't take long before you never need to put any thought into buying them, how much you're buying at once, or the order you buy them in - you just press max all and move on. The entire tab could've been just the max all button and it would not have made a difference beyond the start of the eternity layer. The normal dimensions technically have this problem as well, but since you're constantly getting antimatter the order feels like it has a larger impact and it's more meaningful content, right up until they're automated away. Infinity dimensions are a compromise between the two, so I'm highlighting time dimensions here as the most egregious.

              Following Instructions

              We're getting more and more controversial as we go along! Let's talk about how linear content is not content now (in some circumstances). A trend in incremental games is adding difficulty by adding a web of effects that abstract the true change you can expect from any specific purchase or decision you make. If a game is both linear and sufficiently abstracts the effect of player decisions, then the player will no longer be engaging with the content - they'll simply be clicking on things as they become available. This isn't necessarily a bad thing, as plenty of players don't mind this style of gameplay, but I'd argue once you reach a point where players don't bother reading the effects, those interactions are no longer truly content. Note that unlike the previous qualifiers mentioned, this qualifier is based on the player, and therefore subjective. In effect, it's a spectrum where the more complicated the web of effects becomes, the more likely it is to disengage the player.

              This over-complicatedness leading to disengaging the player can also happen from non-linear gameplay. If the web of effects becomes sufficiently complicated and finding the optimal progression route too time-consuming to discover, players will seek out guides from other players who've completed the game. The second they do this, the game effectively becomes linearly following the instructions of the guide and all the above criticisms apply. Similarly to as before, though, this is a spectrum and not everyone will seek out a guide at the same level of difficulty.

              Automation

              Automation is a staple of the genre, but it has certain implications for the design of the game. Why, when new content is introduced, must the older content be automated away - why is it a chore and it feels rewarding to not have to do it again? Why does the new mechanic have such appeal if we know it too will just be automated away later on, and we'll be happy when that happens? It honestly begs the question of why this framework of introducing content and automating the old content is even enjoyable - and nearly nonexistent in other genres. You're not going to reach a point in a platformer game where they just automate the jumping part - that's the core mechanic! Instead, platformers either add new mechanics that build on the core mechanic or at least re-contextualize the core mechanic. However, in incremental games new content very frequently means replacing older content, as opposed to augmenting it.

              Admittedly, the above paragraph ignores the obvious answer that separates incremental games in this regard. These mechanics become chores as their frequency increases. The frequency increases to give a sense of progression, and automation is seen as a reward because it now manages what was becoming unmanageable. The new content then comes in and continues the loop to give a stronger sense of progression. That's all good and a fine justification for automating content instead of building upon the base mechanic. It's also much easier to design, as each layer essentially lets you start over instead of needing to think of ideas that conform to the original core mechanic.

              So, what's the problem? Even if this trend is justified and easy to implement, there are some other effects it has on the game design. First off, and this is probably a neutral point, incremental games with this cycle of replacing old mechanics with new ones trend towards more and more abstract and further away from any narrative throughline as they add layers. There are only so many justifications for resetting progress, so if a game wants to have several of these layers they're inevitably going to become generic or increasingly loosely associated with the original content. It's most unfortunate, in my opinion when an interesting or innovative core mechanic gets fully automated once a generic "prestige" layer is unlocked.

              A recent example is Really Grass Cutting Incremental, an incremental game about cutting grass (although I'm really criticizing the Roblox game it's based on). Except, it doesn't continue to be about cutting grass. After you buy enough upgrades to increase your grass cutting and level up sufficiently you "prestige", an abstract term that in this case means you reset all your progress to get some currency to buy upgrades that do the same things as the original upgrades, but these won't reset on future prestiges. You'll eventually be able to "crystallize", which means you reset all your progress to get some currency to buy upgrades that do the same things as the original upgrades (and a couple of new ones) and won't reset on future crystallizes. Fine. You'll progress a bit, complete some challenges, and finally get to... grasshop? Grasshopping is this mechanic where you reset all your progress to get some resource that isn't for buying upgrades - this time you just unlock different modifiers on everything based on their amount. You may have gotten the point by now, but there are also "steelie" resets which give you steel for some reason, before unlocking a factory with various machines - none of which are directly tied to cutting grass, and start gathering things like oil and reset for rocket parts and reset to go to space and so on and so on. Throughout all of this there is absolutely no narrative justification or throughline for the direction the game is going, or why cutting grass is still relevant when we're collecting things like rocket parts. I may be going a little hard on GCI, but it is far from alone.

              Tips for Developers

              If you're a developer, by this point you should have a pretty decent idea of how to create "true" content in your game. Here are some other specific tips I'd suggest:

              An upgrade that simply unlocks another upgrade trivially isn't content. However, many games have an upgrade that just unlocks a feature, which then has a wait or other requirements before it can be used. Try to make sure when you unlock a feature, there is immediately something to do with the feature - for example, perhaps give them a small amount of the new currency it unlocks, if applicable.

              If you don't have a large web of effects, and can definitively say the impact of a purchase is to multiply the gain of the cost currency by N, and the next purchase costs N times the amount of that same currency, then this purchase effectively made no difference and it may have made more sense to just go directly to the next upgrade. That said, having effects based on things like the number of purchases made will quickly invalidate this tip.

              + \ No newline at end of file diff --git a/garden/incremental-social/index.html b/garden/incremental-social/index.html index 8f7ac103..3df8a0d6 100644 --- a/garden/incremental-social/index.html +++ b/garden/incremental-social/index.html @@ -6,14 +6,14 @@ Incremental Social | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content
              + \ No newline at end of file diff --git a/garden/ivy-road/index.html b/garden/ivy-road/index.html index 67adc92f..8509d2c2 100644 --- a/garden/ivy-road/index.html +++ b/garden/ivy-road/index.html @@ -6,14 +6,14 @@ Ivy Road | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Ivy Road

              6 words, ~0 minute read. Planted +

              Skip to content

              Ivy Road

              6 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:Davey WredenWanderstop
              Tags:Davey Wreden

              Ivy Road is a indie game studio created by Davey Wreden, Karla Kimonja, and C418

              - +.


              Referenced by:Davey WredenWanderstop
              Tags:Davey Wreden

              Ivy Road is a indie game studio created by Davey Wreden, Karla Kimonja, and C418

              + \ No newline at end of file diff --git a/garden/kronos/index.html b/garden/kronos/index.html index bd7544a8..8dd590d0 100644 --- a/garden/kronos/index.html +++ b/garden/kronos/index.html @@ -6,14 +6,14 @@ Kronos | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Kronos

              60 words, ~0 minute read. Planted +

              Skip to content

              Kronos

              60 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:V-ecs
              Tags:My ProjectsProfectus

              My largest and most ambitious incremental game I've ever made

              • A magnum opus, of sorts ;P

              Still in development, and will be for a long time. I have full intention of completing it, however

              An older version, that is built in The Modding Tree, only has the gameplay, and only goes up to Chapter 2, can be played here

              - +.


              Referenced by:V-ecs
              Tags:My ProjectsProfectus

              My largest and most ambitious incremental game I've ever made

              • A magnum opus, of sorts ;P

              Still in development, and will be for a long time. I have full intention of completing it, however

              An older version, that is built in The Modding Tree, only has the gameplay, and only goes up to Chapter 2, can be played here

              + \ No newline at end of file diff --git a/garden/life-is-strange/index.html b/garden/life-is-strange/index.html index f71f1949..aac29020 100644 --- a/garden/life-is-strange/index.html +++ b/garden/life-is-strange/index.html @@ -6,14 +6,14 @@ Life is Strange | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Life is Strange

              654 words, ~4 minute read. Planted +

              Skip to content

              Life is Strange

              654 words, ~4 minute read. Planted . Last tended to -.


              A series of narrative driven video games with a focus on player choices

              I really enjoyed the first game and engaged with the community a lot. I would get very emotional playing through the later chapters, and it became one of my favorite games.

              Playthroughs I enjoyed:

              Around the start of Haley and I's relationship, we'd play through LiS1 on projectors in our's classrooms

              The ending

              I was not a huge fan of the ending of Life is Strange. Of the two endings, one very clearly got a lot more resources spent on it, but I think Max's story has a better conclusion under the other.

              In my mind, Max's arc (and major themes of the last chapter) was about learning not to rely on her powers, and to learn to live with the consequences of her actions. To that end, having the game end with her taking responsibility and living with the consequences of such a major event is a fitting thematic conclusion to the game and her character arc. In contrast, the other ending shows Max relying on her powers once again and, in my opinion, portrays Max as having not grown nor learned any lessons throughout the entire series. I think its a disservice this ending got so much more attention, with unique outfits and a song dedicated to it.

              Life is Strange: Before the Storm

              I really enjoyed this story. I didn't get quite as invested, perhaps due to it being a condensed 3 chapters rather than 5, but the characters will still just as amazing, which is what makes LiS so good. The ending didn't have as much of a punch as LiS1 - in fact, the entire back half of episode 3 didn't quite meet the bar in my eyes. At the time, I enjoyed these threads discussing criticisms levied at that part of the game:

              Deadbones played through the game here

              The Awesome Adventures of Captain Spirit

              I enjoyed the demo, and it certainly got me hyped for LiS2 (although I would've been regardless). Switching to UE seemed like a really good move, and the comic theme fits the aesthetic of the series well.

              Life is Strange 2

              Unfortunately, I've only played the first chapter of this game. I wanted to play through it with Haley, but we haven't found time to do so.

              LATER Skip the rest of LiS1 and play LiS2 with Haley

              Life is Strange: True Colors

              This game seems interesting, although the power does seem a little funnily close to "has empathy". I haven't had time to play it, but would like to.

              Life is Strange: Double Exposure

              I'm very excited for this game! Returning to Max's story sounds awesome. Although I will say, from the trailer alone it's incredibly obvious what one of the story beats will be: Revealing that the two timelines follow the two disparate endings from LiS1.

              This game was announced to come with premium editions that get access to the game earlier

              • I think this is a horrible anti-consumer practice
              • Since this game is narratively driven, it is prone to spoilers
              • They're getting more money from their biggest fans without providing any tangible value to them, other than making the experience worse for everyone who plays but doesn't cough up that money
              • I hope other narratively driven games find other ways to do Video Game Monetization
              - +.


              A series of narrative driven video games with a focus on player choices

              I really enjoyed the first game and engaged with the community a lot. I would get very emotional playing through the later chapters, and it became one of my favorite games.

              Playthroughs I enjoyed:

              Around the start of Haley and I's relationship, we'd play through LiS1 on projectors in our's classrooms

              The ending

              I was not a huge fan of the ending of Life is Strange. Of the two endings, one very clearly got a lot more resources spent on it, but I think Max's story has a better conclusion under the other.

              In my mind, Max's arc (and major themes of the last chapter) was about learning not to rely on her powers, and to learn to live with the consequences of her actions. To that end, having the game end with her taking responsibility and living with the consequences of such a major event is a fitting thematic conclusion to the game and her character arc. In contrast, the other ending shows Max relying on her powers once again and, in my opinion, portrays Max as having not grown nor learned any lessons throughout the entire series. I think its a disservice this ending got so much more attention, with unique outfits and a song dedicated to it.

              Life is Strange: Before the Storm

              I really enjoyed this story. I didn't get quite as invested, perhaps due to it being a condensed 3 chapters rather than 5, but the characters will still just as amazing, which is what makes LiS so good. The ending didn't have as much of a punch as LiS1 - in fact, the entire back half of episode 3 didn't quite meet the bar in my eyes. At the time, I enjoyed these threads discussing criticisms levied at that part of the game:

              Deadbones played through the game here

              The Awesome Adventures of Captain Spirit

              I enjoyed the demo, and it certainly got me hyped for LiS2 (although I would've been regardless). Switching to UE seemed like a really good move, and the comic theme fits the aesthetic of the series well.

              Life is Strange 2

              Unfortunately, I've only played the first chapter of this game. I wanted to play through it with Haley, but we haven't found time to do so.

              LATER Skip the rest of LiS1 and play LiS2 with Haley

              Life is Strange: True Colors

              This game seems interesting, although the power does seem a little funnily close to "has empathy". I haven't had time to play it, but would like to.

              Life is Strange: Double Exposure

              I'm very excited for this game! Returning to Max's story sounds awesome. Although I will say, from the trailer alone it's incredibly obvious what one of the story beats will be: Revealing that the two timelines follow the two disparate endings from LiS1.

              This game was announced to come with premium editions that get access to the game earlier

              • I think this is a horrible anti-consumer practice
              • Since this game is narratively driven, it is prone to spoilers
              • They're getting more money from their biggest fans without providing any tangible value to them, other than making the experience worse for everyone who plays but doesn't cough up that money
              • I hope other narratively driven games find other ways to do Video Game Monetization
              + \ No newline at end of file diff --git a/garden/logseq/index.html b/garden/logseq/index.html index 178670cf..5df60ff4 100644 --- a/garden/logseq/index.html +++ b/garden/logseq/index.html @@ -6,14 +6,14 @@ Logseq | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Logseq

              3 words, ~0 minute read. Planted +

              Skip to content

              Logseq

              3 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:Command PalettesMy Personal WebsiteThis Knowledge Hub

              Logseq is an Open Source outlining software

              - +.


              Referenced by:Command PalettesMy Personal WebsiteThis Knowledge Hub

              Logseq is an Open Source outlining software

              + \ No newline at end of file diff --git a/garden/matrix/index.html b/garden/matrix/index.html index 899d746e..b91c65eb 100644 --- a/garden/matrix/index.html +++ b/garden/matrix/index.html @@ -6,14 +6,14 @@ Matrix | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Matrix

              2 words, ~0 minute read. Planted +

              Skip to content

              Matrix

              2 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:CinnyCommuneSynapse

              Matrix is a protocol for Decentralized messaging

              - +.


              Referenced by:CinnyCommuneSynapse

              Matrix is a protocol for Decentralized messaging

              + \ No newline at end of file diff --git a/garden/mbin/index.html b/garden/mbin/index.html index 7845bfb9..ba0a9258 100644 --- a/garden/mbin/index.html +++ b/garden/mbin/index.html @@ -6,14 +6,14 @@ Mbin | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Mbin

              12 words, ~0 minute read. Planted +

              Skip to content

              Mbin

              12 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:Incremental Social

              Mbin is an Open Source Fediverse software

              Can show both twitter-style posts and reddit-style threads

              - +.


              Referenced by:Incremental Social

              Mbin is an Open Source Fediverse software

              Can show both twitter-style posts and reddit-style threads

              + \ No newline at end of file diff --git a/garden/mtx/index.html b/garden/mtx/index.html index 5b5559a5..89c9adef 100644 --- a/garden/mtx/index.html +++ b/garden/mtx/index.html @@ -6,14 +6,14 @@ MTX | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              MTX

              10 words, ~0 minute read. Planted +

              Skip to content

              MTX

              10 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:Premium CurrencyVideo Game Monetization

              Purchaseable items in video games that cost real life currencies

              - +.


              Referenced by:Premium CurrencyVideo Game Monetization

              Purchaseable items in video games that cost real life currencies

              + \ No newline at end of file diff --git a/garden/my-personal-website/index.html b/garden/my-personal-website/index.html index 5c678c24..b2505486 100644 --- a/garden/my-personal-website/index.html +++ b/garden/my-personal-website/index.html @@ -6,14 +6,14 @@ My Personal Website | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              My Personal Website

              422 words, ~2 minute read. Planted +

              Skip to content

              My Personal Website

              422 words, ~2 minute read. Planted . Last tended to -.


              Referenced by:The Small Web

              A Personal Websites for myself, available at https://thepaperpilot.org

              Tech Stack

              I use Logseq to journal and collect my thoughts on various topics that interest me

              • Seafile syncs my logseq files between my devices
              • Git syncs my logseq files to a private repo on Incremental Social for purposes of version control and using as a submodule
              • The seafile files and all repos on Incremental Social are independently backed up daily to backblaze

              My logseq files are synced to a private git repo which is added as a submodule to my website repo

              A Node.js script pre-processes my logseq files into markdown files in the /garden path of the website

              • Converts all links and block references
              • Adds lists of tags and references to pages
              • Adds <h1 /> titles, word counts, update commits, etc. to each page
              • Moves the /now page to /now instead of /garden/now
              • Copies some of the Guide to Incrementals pages to /guide-to-incrementals so as to not break links made before the current site iteration
              • Generates /changelog and its RSS, Atom, and JSON feeds
                • The outputs of the generation are NOT .gitignore'd, as I use the git log to determine which pages updated when - Commit information about when a file was last updated is added via a data loader because if it was added to the file directly, rebuilding the site would count as having updated every page, by updating each commit to the changes introduced last build

              Vitepress builds a static site from the markdown files

              • Includes a custom theme that makes the whole site paper-themed
              • Includes some pages like the homepage and the about me page that require markup, thus don't make sense to maintain inside logseq
              • The sidebar is generated from my favorited pages within Logseq
              • Includes various static files, like copies of several of my games and a robots.txt (borrowed from Tracy Durnell's robots.txt) that blocks several crawlers specifically used for training AI models

              Three.js is used to create the effect in the background

              • Simplex noise gets used to adjust the opacity of a repeating SVG pattern
              • Initially tried to use just SVG, which supports creating noise and using it as a mask, but it only does 2d noise and I need 2d slices of 3d noise

              Microformats are used to markup the site for The IndieWeb

              • The footer contains a minimal h-card with a link to my full profile
              • Each garden page is an h-entry, and the changelog an h-feed
              • All my socials are added as rel-me links, and the profiles then link back to me (as rel-me links, if allowed by the platform)
                • Together this can verify the owner of this website and those socials are the same person
              - +.


              Referenced by:The Small Web

              A Personal Websites for myself, available at https://thepaperpilot.org

              Tech Stack

              I use Logseq to journal and collect my thoughts on various topics that interest me

              • Seafile syncs my logseq files between my devices
              • Git syncs my logseq files to a private repo on Incremental Social for purposes of version control and using as a submodule
              • The seafile files and all repos on Incremental Social are independently backed up daily to backblaze

              My logseq files are synced to a private git repo which is added as a submodule to my website repo

              A Node.js script pre-processes my logseq files into markdown files in the /garden path of the website

              • Converts all links and block references
              • Adds lists of tags and references to pages
              • Adds <h1 /> titles, word counts, update commits, etc. to each page
              • Moves the /now page to /now instead of /garden/now
              • Copies some of the Guide to Incrementals pages to /guide-to-incrementals so as to not break links made before the current site iteration
              • Generates /changelog and its RSS, Atom, and JSON feeds
                • The outputs of the generation are NOT .gitignore'd, as I use the git log to determine which pages updated when - Commit information about when a file was last updated is added via a data loader because if it was added to the file directly, rebuilding the site would count as having updated every page, by updating each commit to the changes introduced last build

              Vitepress builds a static site from the markdown files

              • Includes a custom theme that makes the whole site paper-themed
              • Includes some pages like the homepage and the about me page that require markup, thus don't make sense to maintain inside logseq
              • The sidebar is generated from my favorited pages within Logseq
              • Includes various static files, like copies of several of my games and a robots.txt (borrowed from Tracy Durnell's robots.txt) that blocks several crawlers specifically used for training AI models

              Three.js is used to create the effect in the background

              • Simplex noise gets used to adjust the opacity of a repeating SVG pattern
              • Initially tried to use just SVG, which supports creating noise and using it as a mask, but it only does 2d noise and I need 2d slices of 3d noise

              Microformats are used to markup the site for The IndieWeb

              • The footer contains a minimal h-card with a link to my full profile
              • Each garden page is an h-entry, and the changelog an h-feed
              • All my socials are added as rel-me links, and the profiles then link back to me (as rel-me links, if allowed by the platform)
                • Together this can verify the owner of this website and those socials are the same person
              + \ No newline at end of file diff --git a/garden/my-projects/index.html b/garden/my-projects/index.html index c872ee98..a00f8bae 100644 --- a/garden/my-projects/index.html +++ b/garden/my-projects/index.html @@ -6,14 +6,14 @@ My Projects | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              My Projects

              72 words, ~0 minute read. Planted +

              Skip to content

              My Projects

              72 words, ~0 minute read. Planted . Last tended to -.


              Tagged by:Advent IncrementalBabble BudsCapture the CitadelDice ArmorGame Dev TreeIncremental SocialKronosOpti-SpeechPlanar PioneersProfectusV-ecs

              I like making games and tools!

              Games

              Tools (and other non-games)

              - +.


              Tagged by:Advent IncrementalBabble BudsCapture the CitadelDice ArmorGame Dev TreeIncremental SocialKronosOpti-SpeechPlanar PioneersProfectusV-ecs

              I like making games and tools!

              Games

              Tools (and other non-games)

              + \ No newline at end of file diff --git a/garden/nostr/index.html b/garden/nostr/index.html index 4f135486..14ad5f68 100644 --- a/garden/nostr/index.html +++ b/garden/nostr/index.html @@ -6,14 +6,14 @@ Nostr | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Nostr

              8 words, ~0 minute read. Planted +

              Skip to content

              Nostr

              8 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:Fediverse
              Tags:Decentralized

              Nostr is a protocol for Federated Social Media

              - +.


              Referenced by:Fediverse
              Tags:Decentralized

              Nostr is a protocol for Federated Social Media

              + \ No newline at end of file diff --git a/garden/open-source/index.html b/garden/open-source/index.html index 59d77622..4ec5a3ba 100644 --- a/garden/open-source/index.html +++ b/garden/open-source/index.html @@ -6,14 +6,14 @@ Open Source | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Open Source

              25 words, ~0 minute read. Planted +

              Skip to content

              Open Source

              25 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:Advent IncrementalCinnyCommuneDice ArmorForgejoGame Dev TreeLogseqMbinPlanar PioneersProfectusSynapseVitepressWeird

              Projects with the source code publicly accessible

              Typically also grants users the right to modify the code and redistribute those changes, depending on the license

              - +.


              Referenced by:Advent IncrementalCinnyCommuneDice ArmorForgejoGame Dev TreeLogseqMbinPlanar PioneersProfectusSynapseVitepressWeird

              Projects with the source code publicly accessible

              Typically also grants users the right to modify the code and redistribute those changes, depending on the license

              + \ No newline at end of file diff --git a/garden/opti-speech/index.html b/garden/opti-speech/index.html index 662e7327..01b7195f 100644 --- a/garden/opti-speech/index.html +++ b/garden/opti-speech/index.html @@ -6,14 +6,14 @@ Opti-Speech | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Opti-Speech

              312 words, ~2 minute read. Planted +

              Skip to content

              Opti-Speech

              312 words, ~2 minute read. Planted . Last tended to -.


              Tags:My Projects

              In college I continued development on the Opti-Speech project, originally built alongside the scientific paper Opti-speech: a real-time, 3d visual feedback system for speech training

              The Original Project

              The Optispeech project involves designing and testing a real-time tongue model that can be viewed in a transparent head while a subject talks — for the purposes of treating speech errors and teaching foreign language sounds. This work has been conducted in partnership with Vulintus and with support from the National Institutes of Health (NIH).

              This video shows a talker with WAVE sensors placed on the tongue hitting a virtual target sphere located at the alveolar ridge. When an alveolar consonant is hit (e.g., /s/, /n/, /d/) the sphere changes color from red to green.

              This video shows an American talker learning a novel sound not found in English. When the post-alveolar consonant is hit, the target sphere changes color from red to green. Here, the NDI WAVE system serves as input.

              My Work

              As the sole programmer at UT Dallas Speech Production Lab at the time, my changes involved updating to a more modern version of Unity, improving the interface, in general cleaning up tech debt so it can more easily support new features, and added support for additional EMA systems, namely the Carstens AG501.

              In addition, the program now includes documentation and unit tests to improve program stability and maintainability going forward.

              - +.


              Tags:My Projects

              In college I continued development on the Opti-Speech project, originally built alongside the scientific paper Opti-speech: a real-time, 3d visual feedback system for speech training

              The Original Project

              The Optispeech project involves designing and testing a real-time tongue model that can be viewed in a transparent head while a subject talks — for the purposes of treating speech errors and teaching foreign language sounds. This work has been conducted in partnership with Vulintus and with support from the National Institutes of Health (NIH).

              This video shows a talker with WAVE sensors placed on the tongue hitting a virtual target sphere located at the alveolar ridge. When an alveolar consonant is hit (e.g., /s/, /n/, /d/) the sphere changes color from red to green.

              This video shows an American talker learning a novel sound not found in English. When the post-alveolar consonant is hit, the target sphere changes color from red to green. Here, the NDI WAVE system serves as input.

              My Work

              As the sole programmer at UT Dallas Speech Production Lab at the time, my changes involved updating to a more modern version of Unity, improving the interface, in general cleaning up tech debt so it can more easily support new features, and added support for additional EMA systems, namely the Carstens AG501.

              In addition, the program now includes documentation and unit tests to improve program stability and maintainability going forward.

              + \ No newline at end of file diff --git a/garden/planar-pioneers/index.html b/garden/planar-pioneers/index.html index 3ae381d5..10f04f52 100644 --- a/garden/planar-pioneers/index.html +++ b/garden/planar-pioneers/index.html @@ -6,14 +6,14 @@ Planar Pioneers | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Planar Pioneers

              25 words, ~0 minute read. Planted +

              Skip to content

              Planar Pioneers

              25 words, ~0 minute read. Planted . Last tended to -.


              Tags:My ProjectsProfectus

              Play it here!

              An Open Source game designed to show off Profectus' dynamic layer system!

              The TV Tropes page on this game mentions some of the cool things about this game

              - +.


              Tags:My ProjectsProfectus

              Play it here!

              An Open Source game designed to show off Profectus' dynamic layer system!

              The TV Tropes page on this game mentions some of the cool things about this game

              + \ No newline at end of file diff --git a/garden/pre-order-bonuses/index.html b/garden/pre-order-bonuses/index.html index af0fac4b..34a7cfdd 100644 --- a/garden/pre-order-bonuses/index.html +++ b/garden/pre-order-bonuses/index.html @@ -6,14 +6,14 @@ Pre-Order Bonuses | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Pre-Order Bonuses

              98 words, ~1 minute read. Planted +

              Skip to content

              Pre-Order Bonuses

              98 words, ~1 minute read. Planted . Last tended to -.


              Referenced by:Video Game Monetization

              Pre-order bonuses are benefits given to players who buy a game before it comes out

              They primarily serve to benefit the company

              • People commit to buying before the embargo date passes
              • Heuristic of how well it'll sell after launch
              • Slight lead on return on investment
                • More significantly impacts indie studios, who will likely have less cash on hand
              • Companies make deals with storefronts to have exclusive bonuses, to drive customers to said storefronts

              Common bonuses:

              • Digital goods:
              • Physical goods:
                • Typically pins, keychains, etc.
                • Typically only included in physical editions of the game
              - +.


              Referenced by:Video Game Monetization

              Pre-order bonuses are benefits given to players who buy a game before it comes out

              They primarily serve to benefit the company

              • People commit to buying before the embargo date passes
              • Heuristic of how well it'll sell after launch
              • Slight lead on return on investment
                • More significantly impacts indie studios, who will likely have less cash on hand
              • Companies make deals with storefronts to have exclusive bonuses, to drive customers to said storefronts

              Common bonuses:

              • Digital goods:
              • Physical goods:
                • Typically pins, keychains, etc.
                • Typically only included in physical editions of the game
              + \ No newline at end of file diff --git a/garden/premium-currency/index.html b/garden/premium-currency/index.html index 13568793..d5b99e29 100644 --- a/garden/premium-currency/index.html +++ b/garden/premium-currency/index.html @@ -6,14 +6,14 @@ Premium Currency | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Premium Currency

              71 words, ~0 minute read. Planted +

              Skip to content

              Premium Currency

              71 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:Pre-Order Bonuses

              A popular form of MTX where instead of receiving a useful item or effect directly, you receive a currency that is then spent on an in game store

              Reasons companies use them

              • Abstracts the real world price of items
                • No strict conversion ratio
                • Discounts for bulk purchasing
                • Small amounts given for free based on story progression or watching ads
              • Consolidates smaller purchases into a larger one (decreasing friction of individual purchases)
              - +.


              Referenced by:Pre-Order Bonuses

              A popular form of MTX where instead of receiving a useful item or effect directly, you receive a currency that is then spent on an in game store

              Reasons companies use them

              • Abstracts the real world price of items
                • No strict conversion ratio
                • Discounts for bulk purchasing
                • Small amounts given for free based on story progression or watching ads
              • Consolidates smaller purchases into a larger one (decreasing friction of individual purchases)
              + \ No newline at end of file diff --git a/garden/profectus/index.html b/garden/profectus/index.html index 4bbb2c71..ed093cb2 100644 --- a/garden/profectus/index.html +++ b/garden/profectus/index.html @@ -6,14 +6,14 @@ Profectus | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Profectus

              73 words, ~0 minute read. Planted +

              Skip to content

              Profectus

              73 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:Advent IncrementalPlanar Pioneers
              Tagged by:Advent IncrementalKronosPlanar Pioneers
              Tags:My Projects

              Profectus is an Open Source game engine I made, loosely based on The Modding Tree by Acamaeda

              Technically it's more of a template for making web games

              It centers around using Vue's reactivity and is designed with the intent to not restrain developers into making games that only look or behave "one way"

              Games made with Profectus:

              • Everything in this garden tagged with this page!
              • The entries to the Profectus Creation Jam
              • Primordia by Jacorb
              - +.


              Referenced by:Advent IncrementalPlanar Pioneers
              Tagged by:Advent IncrementalKronosPlanar Pioneers
              Tags:My Projects

              Profectus is an Open Source game engine I made, loosely based on The Modding Tree by Acamaeda

              Technically it's more of a template for making web games

              It centers around using Vue's reactivity and is designed with the intent to not restrain developers into making games that only look or behave "one way"

              Games made with Profectus:

              • Everything in this garden tagged with this page!
              • The entries to the Profectus Creation Jam
              • Primordia by Jacorb
              + \ No newline at end of file diff --git a/garden/social-media/index.html b/garden/social-media/index.html index 1c4e92bf..daef57ac 100644 --- a/garden/social-media/index.html +++ b/garden/social-media/index.html @@ -6,14 +6,14 @@ Social Media | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Social Media

              98 words, ~1 minute read. Planted +

              Skip to content

              Social Media

              98 words, ~1 minute read. Planted . Last tended to -.


              Referenced by:CommuneFediverse

              Traditional social media

              • Not Decentralized
                • Can't choose your own rules, sorting methods, data queries, etc.
              • Overrun by scams and ads and influencers

              Federated Social Media

              • Partially Decentralized
                • Self hosting is too hard for everyone to do
                • Still subject to instance's moderation, limitations, etc.
              • Users need to pick an instance, associating their identity with one specific group
                • People belong to many groups
                • The person is permanently associated with that one group
                • You have to pick before getting a "trial period" to ensure you actually like that group/instance

              My take on an ideal social media Fedi v2

              - +.


              Referenced by:CommuneFediverse

              Traditional social media

              • Not Decentralized
                • Can't choose your own rules, sorting methods, data queries, etc.
              • Overrun by scams and ads and influencers

              Federated Social Media

              • Partially Decentralized
                • Self hosting is too hard for everyone to do
                • Still subject to instance's moderation, limitations, etc.
              • Users need to pick an instance, associating their identity with one specific group
                • People belong to many groups
                • The person is permanently associated with that one group
                • You have to pick before getting a "trial period" to ensure you actually like that group/instance

              My take on an ideal social media Fedi v2

              + \ No newline at end of file diff --git a/garden/synapse/index.html b/garden/synapse/index.html index 0d7f480a..c4da8e39 100644 --- a/garden/synapse/index.html +++ b/garden/synapse/index.html @@ -6,14 +6,14 @@ Synapse | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Synapse

              2 words, ~0 minute read. Planted +

              Skip to content

              Synapse

              2 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:Incremental Social

              Synapse is an Open Source server software for the Matrix protocol

              - +.


              Referenced by:Incremental Social

              Synapse is an Open Source server software for the Matrix protocol

              + \ No newline at end of file diff --git a/garden/the-beginner-s-guide/index.html b/garden/the-beginner-s-guide/index.html index ed1c17d1..838a85c2 100644 --- a/garden/the-beginner-s-guide/index.html +++ b/garden/the-beginner-s-guide/index.html @@ -6,14 +6,14 @@ The Beginner's Guide | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              The Beginner's Guide

              70 words, ~0 minute read. Planted +

              Skip to content

              The Beginner's Guide

              70 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:Davey Wreden
              Tags:Davey Wreden

              My favorite video game of all time, bar none. Created by Davey Wreden

              The game broadly comments on the relationship between creators and consumers, and it can apply to all forms of art

              • Perhaps also an important commentary on parasocial relationships

              Important analyses:

              - +.


              Referenced by:Davey Wreden
              Tags:Davey Wreden

              My favorite video game of all time, bar none. Created by Davey Wreden

              The game broadly comments on the relationship between creators and consumers, and it can apply to all forms of art

              • Perhaps also an important commentary on parasocial relationships

              Important analyses:

              + \ No newline at end of file diff --git a/garden/the-cozy-web/index.html b/garden/the-cozy-web/index.html index 5695a26c..b28cdeb1 100644 --- a/garden/the-cozy-web/index.html +++ b/garden/the-cozy-web/index.html @@ -6,14 +6,14 @@ The Cozy Web | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              The Cozy Web

              45 words, ~0 minute read. Planted +

              Skip to content

              The Cozy Web

              45 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:Digital Gardens

              The Cozy Web is an extension of the dark forest theory of the Internet

              It refers to the part of the web that is not web indexable

              This part of the web is known for not typically having ads or marketers

              Popularized by this article written by Maggie Appleton, who has also written a lot about Digital Gardens

              - +.


              Referenced by:Digital Gardens

              The Cozy Web is an extension of the dark forest theory of the Internet

              It refers to the part of the web that is not web indexable

              This part of the web is known for not typically having ads or marketers

              Popularized by this article written by Maggie Appleton, who has also written a lot about Digital Gardens

              + \ No newline at end of file diff --git a/garden/the-indieweb/amplification/index.html b/garden/the-indieweb/amplification/index.html index 02144acd..d31f8959 100644 --- a/garden/the-indieweb/amplification/index.html +++ b/garden/the-indieweb/amplification/index.html @@ -6,14 +6,14 @@ The IndieWeb/Amplification | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              The IndieWeb___Amplification

              57 words, ~0 minute read. Planted +

              Skip to content

              The IndieWeb___Amplification

              57 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              Refers to reblogging (and re-hosting, sometimes) of someone else's content on your own site

              The Internet is a series of webs discusses some ideas and best practices for amplification

              To ensure the rehosted content actually came from the claimed author and was not tampered with, all content should be signed using The IndieWeb/Signature Blocks

              - +.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              Refers to reblogging (and re-hosting, sometimes) of someone else's content on your own site

              The Internet is a series of webs discusses some ideas and best practices for amplification

              To ensure the rehosted content actually came from the claimed author and was not tampered with, all content should be signed using The IndieWeb/Signature Blocks

              + \ No newline at end of file diff --git a/garden/the-indieweb/signature-blocks/index.html b/garden/the-indieweb/signature-blocks/index.html index d050b762..ffb98b40 100644 --- a/garden/the-indieweb/signature-blocks/index.html +++ b/garden/the-indieweb/signature-blocks/index.html @@ -6,14 +6,14 @@ The IndieWeb/Signature Blocks | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              The IndieWeb___Signature Blocks

              14 words, ~0 minute read. Planted +

              Skip to content

              The IndieWeb___Signature Blocks

              14 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              A proposal I want to write for posting signed content on your IndieWeb website

              - +.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              A proposal I want to write for posting signed content on your IndieWeb website

              + \ No newline at end of file diff --git a/garden/the-small-web/index.html b/garden/the-small-web/index.html index 4588414f..96da4282 100644 --- a/garden/the-small-web/index.html +++ b/garden/the-small-web/index.html @@ -6,14 +6,14 @@ The Small Web | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              The Small Web

              778 words, ~4 minute read. Planted +

              Skip to content

              The Small Web

              778 words, ~4 minute read. Planted . Last tended to -.


              Referenced by:CommuneFederated IdentityFedi v2My Personal Website/nowThe IndieWeb/Signature BlocksThis Knowledge HubWebringsWeird

              The small web (also known as the indie web, personal web, the web revival movement, and other terms) refers to small, personal, independent websites. It is seen as a direct alternative to the centralized and homogenized websites like X, Meta, and TikTok. My Personal Website is part of the small web!

              Motivation behind the small web

              The modern web is bad

              The small web is, at its roots, a direct response to the issues with the modern web:

              The modern web is dominated by a handful of large websites, sometimes referred to as the "corporate web". These websites limit personalization, how you can use the website, and are filled with ads, marketers, and influencers.

              The corporate web is designed for consuming content created by a few large/popular creators. This manifests in the near-ubiquitous infinitely scrolling feed of algorithmically chosen posts, optimized to keep you on the site for as long as possible, to the detriment of society.

              Websites this large are expensive and, due to Capitalism, must forever be making more money than before - which means if they're not growing users, they must grow how much money they're making per user. This process typically means corporate websites become worse for their users over time, and was coined as Enshittification by Cory Doctorow.

              The old web was good

              In contrast to the above, the classic web was filled with many diverse sites that typically represented a single person or organization, who were able to fully tailor their site to what they wanted it to be. Websites would be more unique and interesting, since the creator would have full control over them. This also makes the whole web feel more personal and intimate, as you're looking at a closer representation of how someone chooses to portray themselves online, in a way a profile page on X or Meta cannot be.

              There are still lessons we've learned over time that can apply to modern "small web" pages, like accessible design and how to be more inclusive.

              The small web is anti-corporate

              Small static websites are very cheap to host, making anti-features like ads unnecessary and therefore rare. In general small websites are cheap enough to avoid needing to think about monetization entirely, let alone worrying about how to perpetually make more money. This lack of profit motive behind most small websites contributes to a culture of not just being "not corporate", but "anti-corporate".

              In general, the corporate web seems to have values that align with those of authoritarianism - control, surveillance, and hierarchy, whereas the small web aligns with anarchist values - autonomy, cooperation, and egalitarianism.

              Further reading

              These are videos and articles that continue expanding on the values and motivations behind the small web as an alternative to the corporate web:

              Browsing the small web

              Follow Webrings or other links from known small websites.

              Marginalia is a search engine for non-commercial content with a "random" button and filters for the small web explicitly (amongst other useful filters!)

              The Tildeverse contains a large set of personal websites.

              • Pick one of the member sites, and they'll have a list of all their users, who each have a custom page. Some may also list most recently updated pages, which is a good way of filtering out default pages.
              • You may also consider joining one of these communities. They're effectively shared Linux computers, with a focus on small tight knit communities as an alternative to social media. Great if you're interested in learning Linux and command line utilities!

              Building personal websites

              IndieWeb contains various information and resources on building personal websites that use open standards to better interact with readers and other sites consistently. Check out IndieWebify Me to get assistance implementing their standards.

              Free hosting for static websites:

              Other resources:

              Streams

              Microsub is a proposed protocol to support hosting streams of content on personal websites in a way they can be consistently ingested by microsub clients. This way, people could subscribe to multiple streams on independent websites and get them in one feed. Through this, the indie web becomes a Federated Social Media.

              Streams also allow your personal website to be the one source of truth for your posted content, in a concept called POSSE - Publish (on your) Own Site, Syndicate Elsewhere (other social media sites). This would effectively solve the problems described in Hey Creators, Please Make Firehoses!

              Multiple streams can be hosted by one site/person so people can subscribe to the kind of content they're interested in.

              Digital Gardens

              These sites may be useful to occasionally check up on rather than get notifications from on every post/change

              • Although Garden-RSS could allow those who want to receive notifications to do so

              The future

              The Internet is a series of webs talks about transitioning from our current consolidated web back to the indie web

              - +.


              Referenced by:CommuneFederated IdentityFedi v2My Personal Website/nowThe IndieWeb/Signature BlocksThis Knowledge HubWebringsWeird

              The small web (also known as the indie web, personal web, the web revival movement, and other terms) refers to small, personal, independent websites. It is seen as a direct alternative to the centralized and homogenized websites like X, Meta, and TikTok. My Personal Website is part of the small web!

              Motivation behind the small web

              The modern web is bad

              The small web is, at its roots, a direct response to the issues with the modern web:

              The modern web is dominated by a handful of large websites, sometimes referred to as the "corporate web". These websites limit personalization, how you can use the website, and are filled with ads, marketers, and influencers.

              The corporate web is designed for consuming content created by a few large/popular creators. This manifests in the near-ubiquitous infinitely scrolling feed of algorithmically chosen posts, optimized to keep you on the site for as long as possible, to the detriment of society.

              Websites this large are expensive and, due to Capitalism, must forever be making more money than before - which means if they're not growing users, they must grow how much money they're making per user. This process typically means corporate websites become worse for their users over time, and was coined as Enshittification by Cory Doctorow.

              The old web was good

              In contrast to the above, the classic web was filled with many diverse sites that typically represented a single person or organization, who were able to fully tailor their site to what they wanted it to be. Websites would be more unique and interesting, since the creator would have full control over them. This also makes the whole web feel more personal and intimate, as you're looking at a closer representation of how someone chooses to portray themselves online, in a way a profile page on X or Meta cannot be.

              There are still lessons we've learned over time that can apply to modern "small web" pages, like accessible design and how to be more inclusive.

              The small web is anti-corporate

              Small static websites are very cheap to host, making anti-features like ads unnecessary and therefore rare. In general small websites are cheap enough to avoid needing to think about monetization entirely, let alone worrying about how to perpetually make more money. This lack of profit motive behind most small websites contributes to a culture of not just being "not corporate", but "anti-corporate".

              In general, the corporate web seems to have values that align with those of authoritarianism - control, surveillance, and hierarchy, whereas the small web aligns with anarchist values - autonomy, cooperation, and egalitarianism.

              Further reading

              These are videos and articles that continue expanding on the values and motivations behind the small web as an alternative to the corporate web:

              Browsing the small web

              Follow Webrings or other links from known small websites.

              Marginalia is a search engine for non-commercial content with a "random" button and filters for the small web explicitly (amongst other useful filters!)

              The Tildeverse contains a large set of personal websites.

              • Pick one of the member sites, and they'll have a list of all their users, who each have a custom page. Some may also list most recently updated pages, which is a good way of filtering out default pages.
              • You may also consider joining one of these communities. They're effectively shared Linux computers, with a focus on small tight knit communities as an alternative to social media. Great if you're interested in learning Linux and command line utilities!

              Building personal websites

              IndieWeb contains various information and resources on building personal websites that use open standards to better interact with readers and other sites consistently. Check out IndieWebify Me to get assistance implementing their standards.

              Free hosting for static websites:

              Other resources:

              Streams

              Microsub is a proposed protocol to support hosting streams of content on personal websites in a way they can be consistently ingested by microsub clients. This way, people could subscribe to multiple streams on independent websites and get them in one feed. Through this, the indie web becomes a Federated Social Media.

              Streams also allow your personal website to be the one source of truth for your posted content, in a concept called POSSE - Publish (on your) Own Site, Syndicate Elsewhere (other social media sites). This would effectively solve the problems described in Hey Creators, Please Make Firehoses!

              Multiple streams can be hosted by one site/person so people can subscribe to the kind of content they're interested in.

              Digital Gardens

              These sites may be useful to occasionally check up on rather than get notifications from on every post/change

              • Although Garden-RSS could allow those who want to receive notifications to do so

              The future

              The Internet is a series of webs talks about transitioning from our current consolidated web back to the indie web

              + \ No newline at end of file diff --git a/garden/this-knowledge-hub/index.html b/garden/this-knowledge-hub/index.html index b7172c30..3fc3a384 100644 --- a/garden/this-knowledge-hub/index.html +++ b/garden/this-knowledge-hub/index.html @@ -6,14 +6,14 @@ This Knowledge Hub | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              This Knowledge Hub

              135 words, ~1 minute read. Planted +

              Skip to content

              This Knowledge Hub

              135 words, ~1 minute read. Planted . Last tended to -.


              Referenced by:Digital Gardens

              This is my knowledge hub!

              • It's a Digital Garden collecting my thoughts in varying levels of completeness on basically anything I have interest in

              This is not Wikipedia. My thoughts are biased and argumentative, but to the best of my ability based on fact and expertise

              I'm writing on something essentially every day

              • Most of my pages are private, especially the journal pages
              • I'll only push updates to this site every so often (not an automatic process)
              • Until something like Garden-RSS exists, we'll have to make do with /changelog which gives a git diff summary for every pushed change, in the form of a The IndieWeb stream as well as an RSS feed

              Written in Logseq and rendered with Vitepress

              I want to utilize the strategies described in Andy's working notes to help improve my digital garden

              Suggested pages:

              - +.


              Referenced by:Digital Gardens

              This is my knowledge hub!

              • It's a Digital Garden collecting my thoughts in varying levels of completeness on basically anything I have interest in

              This is not Wikipedia. My thoughts are biased and argumentative, but to the best of my ability based on fact and expertise

              I'm writing on something essentially every day

              • Most of my pages are private, especially the journal pages
              • I'll only push updates to this site every so often (not an automatic process)
              • Until something like Garden-RSS exists, we'll have to make do with /changelog which gives a git diff summary for every pushed change, in the form of a The IndieWeb stream as well as an RSS feed

              Written in Logseq and rendered with Vitepress

              I want to utilize the strategies described in Andy's working notes to help improve my digital garden

              Suggested pages:

              + \ No newline at end of file diff --git a/garden/v-ecs/index.html b/garden/v-ecs/index.html index 2a85898a..beaabedb 100644 --- a/garden/v-ecs/index.html +++ b/garden/v-ecs/index.html @@ -6,14 +6,14 @@ V-ecs | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              V-ecs

              209 words, ~1 minute read. Planted +

              Skip to content

              V-ecs

              209 words, ~1 minute read. Planted . Last tended to -.


              Tags:My Projects

              V-ecs (pronounced "Vex") is a Vulkan-based engine I made for making highly moddable games and tools in Lua centered around the ECS design pattern and a work-stealing job system.

              The engine works with "worlds", which are collections of systems and renderers. The engine comes with several worlds using systems and renderers I made, including a voxel world, an incremental game, and some test scenes. All of these include systems to render the fps as well as show a debug console by typing the grave key (`). The default world is a title screen that detects any worlds in the "worlds" folder and displays a button for each of them.

              The original plans were to eventually put it on the steam workshop so people could more easily share their creations amongst each other, but I never became happy enough with the performance of the engine - the parallelization of the lua code involved a lot of overhead that severely limited performance.

              Instead, I made a couple of worlds by myself - an infinite procedurally generated voxel world, a simple incremental game, and a more complex incremental game I call "Sands of Time".

              The gameplay of Sands of Time was replicated in Kronos Chapter 2!

              - +.


              Tags:My Projects

              V-ecs (pronounced "Vex") is a Vulkan-based engine I made for making highly moddable games and tools in Lua centered around the ECS design pattern and a work-stealing job system.

              The engine works with "worlds", which are collections of systems and renderers. The engine comes with several worlds using systems and renderers I made, including a voxel world, an incremental game, and some test scenes. All of these include systems to render the fps as well as show a debug console by typing the grave key (`). The default world is a title screen that detects any worlds in the "worlds" folder and displays a button for each of them.

              The original plans were to eventually put it on the steam workshop so people could more easily share their creations amongst each other, but I never became happy enough with the performance of the engine - the parallelization of the lua code involved a lot of overhead that severely limited performance.

              Instead, I made a couple of worlds by myself - an infinite procedurally generated voxel world, a simple incremental game, and a more complex incremental game I call "Sands of Time".

              The gameplay of Sands of Time was replicated in Kronos Chapter 2!

              + \ No newline at end of file diff --git a/garden/video-game-monetization/index.html b/garden/video-game-monetization/index.html index ac7fd2fc..17c58bb1 100644 --- a/garden/video-game-monetization/index.html +++ b/garden/video-game-monetization/index.html @@ -6,14 +6,14 @@ Video Game Monetization | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Video Game Monetization

              250 words, ~1 minute read. Planted +

              Skip to content

              Video Game Monetization

              250 words, ~1 minute read. Planted . Last tended to -.


              Referenced by:Life is Strange

              AAA games

              They Clcost a lot of money to make, mostly due to the graphics arms race. The price required to make these games profitable would be much higher than the current price of AAA games.

              Graphics would not justify significantly higher prices, and AAA studios know this. So instead they use the techniques to make more money without raising the base price:

              Free-to-play games

              Typically utilize MTX and ads in order to profit. Often extreme cases of designing games to compell players to spend money.

              Indie developers

              Trying to make a sustainable living as an indie developer is hard. The industry is packed with lots of competition, and drive prices people are willing to pay very low. Therefore, I don't blame indies for their monetization strategies, even if I consider them unethical or tainting the game design.

              Ethical game monetization

              Requirements:

              • Free demo
              • Paid base game
              • No MTX
              • Paid content expansions

              The goal of the above is to allow players to determine if they enjoy the game without putting money down, and to ensure the game design cannot be tainted by the monetization.

              I think having the gameplay affected by transactions of any kind taints the game design. This is a particularly controversial take in the context of communal benefits (e.g. one person donates and all players get a 2x buff for an hour, or a persistent buff based on number of patrons), which are generally seen as ethical.

              - +.


              Referenced by:Life is Strange

              AAA games

              They Clcost a lot of money to make, mostly due to the graphics arms race. The price required to make these games profitable would be much higher than the current price of AAA games.

              Graphics would not justify significantly higher prices, and AAA studios know this. So instead they use the techniques to make more money without raising the base price:

              Free-to-play games

              Typically utilize MTX and ads in order to profit. Often extreme cases of designing games to compell players to spend money.

              Indie developers

              Trying to make a sustainable living as an indie developer is hard. The industry is packed with lots of competition, and drive prices people are willing to pay very low. Therefore, I don't blame indies for their monetization strategies, even if I consider them unethical or tainting the game design.

              Ethical game monetization

              Requirements:

              • Free demo
              • Paid base game
              • No MTX
              • Paid content expansions

              The goal of the above is to allow players to determine if they enjoy the game without putting money down, and to ensure the game design cannot be tainted by the monetization.

              I think having the gameplay affected by transactions of any kind taints the game design. This is a particularly controversial take in the context of communal benefits (e.g. one person donates and all players get a 2x buff for an hour, or a persistent buff based on number of patrons), which are generally seen as ethical.

              + \ No newline at end of file diff --git a/garden/vitepress/index.html b/garden/vitepress/index.html index 4256f887..6db4efbf 100644 --- a/garden/vitepress/index.html +++ b/garden/vitepress/index.html @@ -6,14 +6,14 @@ Vitepress | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Vitepress

              4 words, ~0 minute read. Planted +

              Skip to content

              Vitepress

              4 words, ~0 minute read. Planted . Last tended to -.


              Referenced by:My Personal WebsiteThis Knowledge Hub

              Vitepress is an Open Source static site generator

              - +.


              Referenced by:My Personal WebsiteThis Knowledge Hub

              Vitepress is an Open Source static site generator

              + \ No newline at end of file diff --git a/garden/wanderstop/index.html b/garden/wanderstop/index.html index 757b9d65..8715fddc 100644 --- a/garden/wanderstop/index.html +++ b/garden/wanderstop/index.html @@ -6,14 +6,14 @@ Wanderstop | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Wanderstop

              8 words, ~0 minute read. Planted +

              Skip to content

              Wanderstop

              8 words, ~0 minute read. Planted . Last tended to -.


              Tags:Davey Wreden

              Wanderstop is the first game by Ivy Road. It's a narrative focused cozy game

              - +.


              Tags:Davey Wreden

              Wanderstop is the first game by Ivy Road. It's a narrative focused cozy game

              + \ No newline at end of file diff --git a/garden/webrings/index.html b/garden/webrings/index.html index 62ec3ec3..dd14c8de 100644 --- a/garden/webrings/index.html +++ b/garden/webrings/index.html @@ -6,14 +6,14 @@ Webrings | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Webrings

              139 words, ~1 minute read. Planted +

              Skip to content

              Webrings

              139 words, ~1 minute read. Planted . Last tended to -.


              Referenced by:The Small Web

              A collection of Personal Websites that link to each other

              • These websites are all endorsing each other
              • They form a network of related sites readers might be interested in
              • Built on human trust rather than algorithms

              Commune has a vision for modern webrings

              • Have communities set up matrix spaces for chatting
              • Multiple spaces can contain the same room
              • Related communities can share a room about a relevant topic
                • e.g. a bunch of game development libraries shared a "Game Design" room
              • This allows smaller communities to grow from cross-pollinating with other related communities
              • Could Incremental Social host a shared "Incremental Games" room?
                • How to bridge one channel to multiple discord servers, since that's where most incremental games communities are
                • Would this be appealing to already large communities?
                • Would this be overwhelming to smaller communities?
                • Who would moderate?
              - +.


              Referenced by:The Small Web

              A collection of Personal Websites that link to each other

              • These websites are all endorsing each other
              • They form a network of related sites readers might be interested in
              • Built on human trust rather than algorithms

              Commune has a vision for modern webrings

              • Have communities set up matrix spaces for chatting
              • Multiple spaces can contain the same room
              • Related communities can share a room about a relevant topic
                • e.g. a bunch of game development libraries shared a "Game Design" room
              • This allows smaller communities to grow from cross-pollinating with other related communities
              • Could Incremental Social host a shared "Incremental Games" room?
                • How to bridge one channel to multiple discord servers, since that's where most incremental games communities are
                • Would this be appealing to already large communities?
                • Would this be overwhelming to smaller communities?
                • Who would moderate?
              + \ No newline at end of file diff --git a/garden/weird/index.html b/garden/weird/index.html index 8e5626bc..9e15cdfd 100644 --- a/garden/weird/index.html +++ b/garden/weird/index.html @@ -6,14 +6,14 @@ Weird | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Weird

              114 words, ~1 minute read. Planted +

              Skip to content

              Weird

              114 words, ~1 minute read. Planted . Last tended to -.


              Referenced by:CommuneFedi v2My Personal WebsiteThe Small Web

              Weird is an Open Source project by the Commune team currently in development

              Aims to make creating Personal Websites with Federated Identity available to everyone

              • Also plans on having paid tiers for giving people access to single user instances of various Fediverse tools

              Long term, Weird wants to build a new better fediverse

              - +.


              Referenced by:CommuneFedi v2My Personal WebsiteThe Small Web

              Weird is an Open Source project by the Commune team currently in development

              Aims to make creating Personal Websites with Federated Identity available to everyone

              • Also plans on having paid tiers for giving people access to single user instances of various Fediverse tools

              Long term, Weird wants to build a new better fediverse

              + \ No newline at end of file diff --git a/guide-to-incrementals/design/criticism/index.html b/guide-to-incrementals/design/criticism/index.html index ca99e774..223c4f49 100644 --- a/guide-to-incrementals/design/criticism/index.html +++ b/guide-to-incrementals/design/criticism/index.html @@ -6,14 +6,14 @@ Guide to Incrementals/Navigating Criticism | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Guide to Incrementals___Navigating Criticism

              747 words, ~4 minute read. Planted +

              Skip to content

              Guide to Incrementals___Navigating Criticism

              747 words, ~4 minute read. Planted . Last tended to -.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              Developing games is fun and exciting and teaches a lot of wonderful skills - I enthusiastically encourage anyone with an interest in game development to try it out - and incremental games are a wonderful way to get started. However, there are many challenges young and inexperienced developers have to face, and I think the hardest one - harder than coding, debugging, balancing, etc. - is handling criticism. When you put your heart and soul into a game it is natural to feel very vulnerable. While I think there's a lot communities can do to ensure they're welcoming, positive and constructive with their criticisms, inevitably you will eventually read some, and potentially a lot, of comments that can deeply affect you. No one is immune to this, from young incremental game developers to the largest content creators you can think of. That's why it's important to be able to process and navigate criticism, because ultimately collecting feedback is essential to the journey to becoming a better developer. On this page, we'll explore how to embrace criticism, grow from it, and continue to post your games publicly with confidence.

              Reading Feedback

              Game development is a skill that takes time and practice to get truly great at. Criticism and other constructive feedback are vital to continually improving. It's useful to look at the criticism as solely a tool for improving this game and future games - that is to say, it should never be used against you as a person. Insults towards the developer(s) themselves are never okay and should not be allowed within whatever community you're sharing your works in. If you do come across a comment you interpret as an attack upon your person, you should report it. For other negative comments, try not to internalize them; instead, focus on improving the game. By distancing your own identity from your work emotionally, you can better analyze the game and use the feedback to your advantage.

              Not all feedback is made equal, and you don't need to feel compelled to read and obey every piece of feedback you receive. Learn to distinguish between constructive feedback and unhelpful comments. Constructive feedback typically offers specific suggestions for improvement, while unhelpful comments are often vague or hurtful. Prioritize the former and disregard the latter. That said, most feedback you get will not be from game developers, so take specific suggestions with a grain of salt. Determine the actual problem they're experiencing, and design what you believe the best solution to that problem would be, regardless if that's the specific solution the player asked for. And keep in mind, due to different player preferences you'll never satisfy everyone, and you don't need to. Ultimately if even just you find the game fun, then that's a success.

              Seeking Feedback

              When deciding where to share your game, consider the type of players you anticipate getting, and the kind of feedback you can anticipate receiving. Different communities will have different levels of support for learning developers, and certain communities may prefer certain types of games or mechanics. It's important to get a diverse set of feedback focused on players you think will enjoy the specific game you're making.

              Collecting feedback from other game developers is incredibly helpful. They've trained themselves to recognize good and bad game design and how to articulate the differences, and from my experience are much more likely to leave positive and constructive comments since they've been in your shoes before! They understand the struggles and can offer guidance and emotional support.

              Responding to Feedback

              Negative feedback can naturally feel like an attack, and it's okay to get angry. However, lashing back is never the appropriate response. It's best to cool off IRL, and keep in mind all the positive comments you've received. There's a concept in Psychology called negative bias that explains how negative feedback tends to stick with us much more prominently than positive feedback, so it's useful to regularly remind yourself of all the positive feedback you've received. Celebrate your successes, no matter how small they may seem - getting a game to a state you can publicly share it with people is an accomplishment in and of itself!

              Remember your passion and your initial reasons for getting into game development. The journey will have its ups and downs, but staying true to your vision and passion will keep you motivated.

              - +.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              Developing games is fun and exciting and teaches a lot of wonderful skills - I enthusiastically encourage anyone with an interest in game development to try it out - and incremental games are a wonderful way to get started. However, there are many challenges young and inexperienced developers have to face, and I think the hardest one - harder than coding, debugging, balancing, etc. - is handling criticism. When you put your heart and soul into a game it is natural to feel very vulnerable. While I think there's a lot communities can do to ensure they're welcoming, positive and constructive with their criticisms, inevitably you will eventually read some, and potentially a lot, of comments that can deeply affect you. No one is immune to this, from young incremental game developers to the largest content creators you can think of. That's why it's important to be able to process and navigate criticism, because ultimately collecting feedback is essential to the journey to becoming a better developer. On this page, we'll explore how to embrace criticism, grow from it, and continue to post your games publicly with confidence.

              Reading Feedback

              Game development is a skill that takes time and practice to get truly great at. Criticism and other constructive feedback are vital to continually improving. It's useful to look at the criticism as solely a tool for improving this game and future games - that is to say, it should never be used against you as a person. Insults towards the developer(s) themselves are never okay and should not be allowed within whatever community you're sharing your works in. If you do come across a comment you interpret as an attack upon your person, you should report it. For other negative comments, try not to internalize them; instead, focus on improving the game. By distancing your own identity from your work emotionally, you can better analyze the game and use the feedback to your advantage.

              Not all feedback is made equal, and you don't need to feel compelled to read and obey every piece of feedback you receive. Learn to distinguish between constructive feedback and unhelpful comments. Constructive feedback typically offers specific suggestions for improvement, while unhelpful comments are often vague or hurtful. Prioritize the former and disregard the latter. That said, most feedback you get will not be from game developers, so take specific suggestions with a grain of salt. Determine the actual problem they're experiencing, and design what you believe the best solution to that problem would be, regardless if that's the specific solution the player asked for. And keep in mind, due to different player preferences you'll never satisfy everyone, and you don't need to. Ultimately if even just you find the game fun, then that's a success.

              Seeking Feedback

              When deciding where to share your game, consider the type of players you anticipate getting, and the kind of feedback you can anticipate receiving. Different communities will have different levels of support for learning developers, and certain communities may prefer certain types of games or mechanics. It's important to get a diverse set of feedback focused on players you think will enjoy the specific game you're making.

              Collecting feedback from other game developers is incredibly helpful. They've trained themselves to recognize good and bad game design and how to articulate the differences, and from my experience are much more likely to leave positive and constructive comments since they've been in your shoes before! They understand the struggles and can offer guidance and emotional support.

              Responding to Feedback

              Negative feedback can naturally feel like an attack, and it's okay to get angry. However, lashing back is never the appropriate response. It's best to cool off IRL, and keep in mind all the positive comments you've received. There's a concept in Psychology called negative bias that explains how negative feedback tends to stick with us much more prominently than positive feedback, so it's useful to regularly remind yourself of all the positive feedback you've received. Celebrate your successes, no matter how small they may seem - getting a game to a state you can publicly share it with people is an accomplishment in and of itself!

              Remember your passion and your initial reasons for getting into game development. The journey will have its ups and downs, but staying true to your vision and passion will keep you motivated.

              + \ No newline at end of file diff --git a/guide-to-incrementals/index.html b/guide-to-incrementals/index.html index 8f1fba30..38206e32 100644 --- a/guide-to-incrementals/index.html +++ b/guide-to-incrementals/index.html @@ -6,14 +6,14 @@ Guide to Incrementals | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Guide to Incrementals

              230 words, ~1 minute read. Planted +

              Skip to content

              Guide to Incrementals

              230 words, ~1 minute read. Planted . Last tended to -.


              Referenced by:My Personal Website

              This is a comprehensive guide to Incremental Games, a genre of video games. It will explore defining the genre, why it's appealing, and how to design and build your own incremental game. Along the way will be interactive examples, snippets from other creators, and relevant material to contextualize everything.

              Note: This is an incomplete document. I want to keep adding opinions and opposing views from other incremental games developers, and add interactive examples to illustrate various points regarding game design and balancing. Consider this a living document - and see the changelog at the end.

              Why am I making this?

              That's a good question! What authority do I have to be making this guide? I haven't made the best incremental games, nor the most incremental games, certainly not the most popular ones either. But I do have some formal education in game development, know a lot of incremental game devs (as well as other game devs), and have a passionate interest in ludology, classifying genres, etc. I've also made a couple of incremental games) myself.

              If you have any additional questions about my credentials or anything on this site, feel free to reach out!

              Ludology

              Making an Incremental

              - +.


              Referenced by:My Personal Website

              This is a comprehensive guide to Incremental Games, a genre of video games. It will explore defining the genre, why it's appealing, and how to design and build your own incremental game. Along the way will be interactive examples, snippets from other creators, and relevant material to contextualize everything.

              Note: This is an incomplete document. I want to keep adding opinions and opposing views from other incremental games developers, and add interactive examples to illustrate various points regarding game design and balancing. Consider this a living document - and see the changelog at the end.

              Why am I making this?

              That's a good question! What authority do I have to be making this guide? I haven't made the best incremental games, nor the most incremental games, certainly not the most popular ones either. But I do have some formal education in game development, know a lot of incremental game devs (as well as other game devs), and have a passionate interest in ludology, classifying genres, etc. I've also made a couple of incremental games) myself.

              If you have any additional questions about my credentials or anything on this site, feel free to reach out!

              Ludology

              Making an Incremental

              + \ No newline at end of file diff --git a/guide-to-incrementals/ludology/appeal-developers/index.html b/guide-to-incrementals/ludology/appeal-developers/index.html index abb5e1dd..71b20341 100644 --- a/guide-to-incrementals/ludology/appeal-developers/index.html +++ b/guide-to-incrementals/ludology/appeal-developers/index.html @@ -6,14 +6,14 @@ Guide to Incrementals/Appeal to Developers | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Guide to Incrementals___Appeal to Developers

              636 words, ~3 minute read. Planted +

              Skip to content

              Guide to Incrementals___Appeal to Developers

              636 words, ~3 minute read. Planted . Last tended to -.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              There are a lot of developers in the incremental games community - the genre seems to draw them in, and convert a lot of players into developers. Let's explore the reasons why this genre appeals to developers.

              Incrementals are Easy to Make

              Compared to other genres, incrementals have quite low expectations. You don't need to make fancy art, or music, or lay things out nicely. If you can make a button and learn the few lines of code necessary to make a number go up, you can make an incremental. This low threshold makes the genre perfect for those who are actively learning to code and haven't developed any gamedev-related skills yet.

              Additionally, unlike other genres incrementals are uniquely easy to implement in a normal web page - no need to worry about rendering sprites, moving them around, implementing physics, etc. New developers can just use HTML to add a button, and the game is now available in your browser. You don't need to choose an engine, have admin privileges, or hell for the dedicated you don't even need a computer - there are tools for web development that run in the browser itself, so you can technically use your phone if that's all you have.

              Javascript is a perfectly viable language for making web games, whereas other genres are typically going to require using other more difficult languages to learn. There are countless javascript tutorials that start from 0 knowledge of programming, making it incredibly accessible to beginners.

              Players are Easy to Find

              Once you've finished your game and uploaded it on github pages or itch or just copied the link if you're using glitch or replit (all of which are easy to do), anyone can now play the game in their browser. This low barrier to entry has shown tremendous success in getting completely unknown developers to have thousands of plays.

              The incremental games community, which mostly centers around r/incremental_games, is always looking for new games and tends to flood any new ones posted with initial players.

              Having your games be played can be incredibly motivating, and the community makes it quite clear that you can expect players to play your game. These communities - both for incremental games in general as well as game-specific communities - tend to be very developer friendly as well. A lot of the developers know each other, and welcome new developers with open arms, often with dedicated channels for programming help and discussions.

              Monetization

              I'd like to clarify that everything I've said above mainly applies to web-based incrementals. Incremental games are also incredibly popular on mobile, but with a much different culture and community. Many mobile gamers will still participate in the web-focused community for the culture. This web-focused community has a culture that has been criticized for being "anti-monetization". Ads, IAPs, and similar forms of monetization are often criticized, mainly due to the abundance of completely non-monetized games available from hobbyist developers. There are exceptions, like paid games often being considered fine, like Increlution or Stuck in Time, or donation ware games like kittens game, but even popular games that have IAP see some level of regular criticism, like NGU Idle, Idle Skilling, or Idle Pins. A large part of this can be explained by the community being hyper-aware of the addictive) nature of this genre and its susceptibility to exploiting players.

              On mobile, however, monetization is the norm and expected. If an incremental game is available on mobile, it almost certainly will be monetized, and mobile players are aware and accepting of that. Mobile incremental games, due to their addictive nature, tend to make a lot of money. It's very lucrative, and therefore these games are quite abundant on mobile storefronts.

              - +.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              There are a lot of developers in the incremental games community - the genre seems to draw them in, and convert a lot of players into developers. Let's explore the reasons why this genre appeals to developers.

              Incrementals are Easy to Make

              Compared to other genres, incrementals have quite low expectations. You don't need to make fancy art, or music, or lay things out nicely. If you can make a button and learn the few lines of code necessary to make a number go up, you can make an incremental. This low threshold makes the genre perfect for those who are actively learning to code and haven't developed any gamedev-related skills yet.

              Additionally, unlike other genres incrementals are uniquely easy to implement in a normal web page - no need to worry about rendering sprites, moving them around, implementing physics, etc. New developers can just use HTML to add a button, and the game is now available in your browser. You don't need to choose an engine, have admin privileges, or hell for the dedicated you don't even need a computer - there are tools for web development that run in the browser itself, so you can technically use your phone if that's all you have.

              Javascript is a perfectly viable language for making web games, whereas other genres are typically going to require using other more difficult languages to learn. There are countless javascript tutorials that start from 0 knowledge of programming, making it incredibly accessible to beginners.

              Players are Easy to Find

              Once you've finished your game and uploaded it on github pages or itch or just copied the link if you're using glitch or replit (all of which are easy to do), anyone can now play the game in their browser. This low barrier to entry has shown tremendous success in getting completely unknown developers to have thousands of plays.

              The incremental games community, which mostly centers around r/incremental_games, is always looking for new games and tends to flood any new ones posted with initial players.

              Having your games be played can be incredibly motivating, and the community makes it quite clear that you can expect players to play your game. These communities - both for incremental games in general as well as game-specific communities - tend to be very developer friendly as well. A lot of the developers know each other, and welcome new developers with open arms, often with dedicated channels for programming help and discussions.

              Monetization

              I'd like to clarify that everything I've said above mainly applies to web-based incrementals. Incremental games are also incredibly popular on mobile, but with a much different culture and community. Many mobile gamers will still participate in the web-focused community for the culture. This web-focused community has a culture that has been criticized for being "anti-monetization". Ads, IAPs, and similar forms of monetization are often criticized, mainly due to the abundance of completely non-monetized games available from hobbyist developers. There are exceptions, like paid games often being considered fine, like Increlution or Stuck in Time, or donation ware games like kittens game, but even popular games that have IAP see some level of regular criticism, like NGU Idle, Idle Skilling, or Idle Pins. A large part of this can be explained by the community being hyper-aware of the addictive) nature of this genre and its susceptibility to exploiting players.

              On mobile, however, monetization is the norm and expected. If an incremental game is available on mobile, it almost certainly will be monetized, and mobile players are aware and accepting of that. Mobile incremental games, due to their addictive nature, tend to make a lot of money. It's very lucrative, and therefore these games are quite abundant on mobile storefronts.

              + \ No newline at end of file diff --git a/guide-to-incrementals/ludology/appeal-gamers/index.html b/guide-to-incrementals/ludology/appeal-gamers/index.html index 4fbf129d..35622a4a 100644 --- a/guide-to-incrementals/ludology/appeal-gamers/index.html +++ b/guide-to-incrementals/ludology/appeal-gamers/index.html @@ -6,14 +6,14 @@ Guide to Incrementals/Appeal to Players | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Guide to Incrementals___Appeal to Players

              2166 words, ~12 minute read. Planted +

              Skip to content

              Guide to Incrementals___Appeal to Players

              2166 words, ~12 minute read. Planted . Last tended to -.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              This is something that has been discussed and analyzed by many people, and to some extent, I feel like everything that can be said on the topic already has. However, a lot of these analyses are from the perspective of those with not as much experience and involvement within the genre as I'd argue would be necessary for a fully contextualized answer. I'm interested in ludology and part of that includes interpreting games as art, and to that end what constitutes a game, let alone a "good game". Incremental games are oft criticized, unfairly in my biased opinion, of not even constituting games, such as was posited by this polygon article.

              Numbers Going Up

              This is a very common response to why people enjoy incremental games, although it's not one I find compels me personally, and I suspect it might be a stand-in for progression) or Guide to Incrementals/What is Content?. But reportedly, some people do just like seeing big numbers. I must reiterate I suspect the actual cause is seeing big numbers in context though - if you start at 1e1000 of a currency and get to 1e1001, that isn't going to feel as satisfying as going from 1e10 to 1e100, and in any case, I don't think a button that just adds a zero to your number will feel quite satisfying - I believe its the sense of having made progress, and comparing where you are to where you started and feeling like you've earned your way here that is enjoyable.

              Progression

              I think a strong sense of progression is seen as very enjoyable to many players of all sorts of genres - engine builder board games, RPGs, rogue_lites_, etc. Incremental games tend to have an extremely exaggerated sense of progression, which makes them very appealing.

              Meta-progression is when games have some sort of progression that persists when other progress gets lost - for example, upgrades that persist between runs of a roguelite game. These are common mechanics in incremental games - in fact, its not uncommon to have multiple of these reset mechanics nested on top of each other, each with their own meta-progression. These are satisfying to players, although they can be a bit controversial. These mechanics can often be seen as an optional crutch, and in roguelite games, players often challenge themselves to win without any meta progression. Essentially these challenges argue that meta-progression de-emphasizes player skill by replacing it with time served. Incremental games, through their exaggerated progression, eschew that possibility though - they make it impossible to beat without the meta progression systems, as the meta-progression becomes an entire chapter of the gameplay. I'd argue this does not detract from the game, however, and is actually a part of what makes incremental games, and roguelikes, enjoyable to many players: meta-progression augments the increases in skill the player is naturally gaining as they play. In effect, it's not replacing the skill increase, but exaggerating it to make it feel more real to the player.

              Effortlessness

              Incremental games are so easy, a lot of them even have you progress while you're not playing! Part of the appeal is being able to feel like you're making progress while doing something actually productive - multitasking, in a way. In this sense, the game is more of a fidget toy - not something to think hard about and play actively, but something to click a few buttons every so often while you're paying attention to a lecture or studying or working. Of course, not all incremental games lend themselves to being played this way - it's specifically "idle" games that work like this. These are games that take an incredibly long amount of time to see all the content, stretching it as thin as possible, but they aren't expecting you to be sitting at your device playing it the entire time. They expect you to leave and come back later to make a bit of progress and repeat the cycle.

              If you look at the higher-level play of most games, you'll see them perform difficult feats with ease and speed. They'll achieve a "flow state" that takes all their knowledge and experience of the game and uses it to play the game as instinctively as possible. It's incredible to watch things like Slay the Spire speed runs or competitive DDR-likes. I'd argue the goal of a lot of games with a competitive scene is to get so good that the game becomes effortless. In that sense, a game that allows you to reach that point earlier isn't any less legitimate, but rather lowers the barrier to entry by allowing more people to get "really good" at the game. And to be clear, (most) incremental games aren't trivially easy - they, and to an extent, every game will have some level of learning and improvement over time.

              Addiction

              A lot of these reasons for why incremental games appeal may have reminded you of why gambling appeals to people, particularly those prone to addiction. Indeed, incremental games are quite often criticized for their similarity to a skinner box. Some have gone as far as to say incremental games as a genre are commenting that all games are skinner boxes). The argument goes that some games are not fun, but rather condition players into continuing to play without actually getting anything from the experience. When tied to real-world money this is seen as predatory, and to a lesser extent, even free games may be feeding the addictive sides of people and making them more prone to seek out gambling or micro-transaction heavy games.

              While incremental games can be fun and even healthy in certain contexts, they can exacerbate video game addiction more than other genres. If you feel like playing incremental games is taking priority over other things in your life, or manipulating your sleep schedule, it may be prudent to seek help. See r/StopGaming for resources.

              Since incremental games are often built on extrinsic motivations in the form of progression systems, it's hard to argue whether players continue to play because they are enjoying the gameplay, or if they are just conditioned to keep doing it because the game keeps rewarding them. Unfortunately, it can often feel like it's the latter, as there isn't typically anything compelling about the "gameplay" of clicking a button and waiting. There may be a significant overlap between those who enjoy incremental games and those who are most prone to addiction, and there are often posts on r/incremental_games about someone either struggling with or overcoming video game addiction.

              Strategy

              Incremental games could be considered a subset of strategy games), and inherit the appeals of strategy games. This includes the appeal of feeling like you've found a good solution to a puzzle, or that you're learning more about the game and are improving at making decisions within it.

              Note that strategy games are not all the same difficulty, as well. Cookie Clicker is probably easier than Starcraft 2 (although late game may beg to differ). Plenty of incremental games can be used as evidence that "easier" strategies may have their separate appeal to harder strategy games - players like to feel smart and that they figured the game out and have optimized or mastered it, and the game being easier doesn't detract from that sense of accomplishment as much as it allows more and more users to be able to reach the point where they gain that sense.

              Avoiding Staleness

              Incremental games tend to have "paradigm shifts", where the gameplay changes in a meaningful way at various times throughout the progression of the game. These upset and change the gameplay loop, which helps keep them from stagnating. This constant "freshness" to the gameplay can keep players engaged for longer, compared to a game with a repetitive and static gameplay loop.

              Good Game Design

              Incremental games tend to show their game design "plainly", so it's more readily apparent if a game has good game design while playing, even if you're not looking for it. While different players have different preferences and might enjoy different types of games more than others, there are underlying good and bad game design principles that players will notice the effects of. To be clear, this isn't talking about stuff like big numbers being enjoyable, where I can comfortably agree to disagree with other players. They don't intrinsically make my experience better, but I'm aware of those for whom it does and I won't argue against their feelings. However, the game designer in me does feel like there are some extremely clear-cut examples of good and bad game design philosophies.

              Let's start by giving an example of a mechanic I think can be easily and strongly argued is good game design. There are of course many examples, but a personal favorite of mine is how DOOM encourages aggressive gameplay by linking health drops to melee attacks. It has an intended experience it's trying to give the player - immersing themselves as DOOM guy, who would not hide behind cover when low on health - and this mechanic does a great job at encouraging and effectively teaching players to behave properly. This is in sharp contrast to shooters like Call of Duty, which have you regen health passively, encouraging players to hide behind cover and wait after getting hit. Note that I'm not arguing CoD is poorly designed, as the games have different intended experiences. I'm specifically praising DOOM for having a mechanic that does a good job at ensuring the player has that intended experience.

              To contrast with an example I think is bad game design, let's talk about shields in souls-likes. This is a bit of a famous example, and I highly recommend this video essay which spends quite a good bit of time on this topic. Essentially, the argument boils down to players of earlier games in the souls games using shields too much - playing slowly, conservatively, and ultimately having less fun. Players wanted to feel safe, so they ended up playing in a way that ruined the experience for them. The developers solved this by removing shields, apart from an intentionally bad one effectively mocking the playstyle, and it did its job at getting players to play more aggressively, and often have more fun.

              To bring the conversation back to incrementals, I'm incredibly opinionated on what makes a good incremental game, which I'll discuss in the game design section. Suffice it to say, incremental games rely more on good game design than other genres, due to not having much to distract from bad game design. This helps (although imperfectly - gamers are a bit too tolerant of bad game design!) well-designed games rise to the top within the genre.

              Artistic Merit

              The discussion of whether video games are art has resulted in a pretty universal "yes, they are", but with some games the argument may still crop up. The reason why Incremental games are sometimes questioned is due to their perceived lack of complexity. However, even setting aside the fact that if players are having fun then it's not time wasted, I think games can have artistic merit that supersedes the necessity of having (any / engaging / "deep") gameplay. Incremental games are no less legitimate of a game or the "art" label because of any lack perceived lack of depth. For what it's worth, most art can be consumed with more ease than any video game - any painting, movie, sculpture, etc.

              A lot of incrementals have a narrative context that can similarly qualify them as art. Cookie Clicker is, as has been pointed out numerous times before, commenting on excess and increasing production beyond any reasonable limits - devolving into increasing production for its own sake. Indeed, a lot of incremental games are written to comment upon various concepts like capitalism or tropes in games, as discussed when defining Incrementals). However, I'd like to argue most incremental games are still art, even without any narrative context. "Art" as a concept is pretty nebulous already, but I personally like those who define it as an act of expression more than any physical result. The creator and the context within which they created the art, and any meaning they put into it, are all relevant and a part of the art itself. Most incremental games have artistic merit from things like why the creator made it, why they chose to make it an incremental game, and why they made any particular design decision. Hell, even if you play through an entire incremental game without a single thought or feeling, that very fact it elicited nothing can itself be artistic merit!

              I'm not an art major, and I may be taking a somewhat extreme take on what is art and what has artistic merit, but I'd argue the overall point stands that games, and incremental games specifically, can have artistic merit, which appeals to many gamers.

              - +.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              This is something that has been discussed and analyzed by many people, and to some extent, I feel like everything that can be said on the topic already has. However, a lot of these analyses are from the perspective of those with not as much experience and involvement within the genre as I'd argue would be necessary for a fully contextualized answer. I'm interested in ludology and part of that includes interpreting games as art, and to that end what constitutes a game, let alone a "good game". Incremental games are oft criticized, unfairly in my biased opinion, of not even constituting games, such as was posited by this polygon article.

              Numbers Going Up

              This is a very common response to why people enjoy incremental games, although it's not one I find compels me personally, and I suspect it might be a stand-in for progression) or Guide to Incrementals/What is Content?. But reportedly, some people do just like seeing big numbers. I must reiterate I suspect the actual cause is seeing big numbers in context though - if you start at 1e1000 of a currency and get to 1e1001, that isn't going to feel as satisfying as going from 1e10 to 1e100, and in any case, I don't think a button that just adds a zero to your number will feel quite satisfying - I believe its the sense of having made progress, and comparing where you are to where you started and feeling like you've earned your way here that is enjoyable.

              Progression

              I think a strong sense of progression is seen as very enjoyable to many players of all sorts of genres - engine builder board games, RPGs, rogue_lites_, etc. Incremental games tend to have an extremely exaggerated sense of progression, which makes them very appealing.

              Meta-progression is when games have some sort of progression that persists when other progress gets lost - for example, upgrades that persist between runs of a roguelite game. These are common mechanics in incremental games - in fact, its not uncommon to have multiple of these reset mechanics nested on top of each other, each with their own meta-progression. These are satisfying to players, although they can be a bit controversial. These mechanics can often be seen as an optional crutch, and in roguelite games, players often challenge themselves to win without any meta progression. Essentially these challenges argue that meta-progression de-emphasizes player skill by replacing it with time served. Incremental games, through their exaggerated progression, eschew that possibility though - they make it impossible to beat without the meta progression systems, as the meta-progression becomes an entire chapter of the gameplay. I'd argue this does not detract from the game, however, and is actually a part of what makes incremental games, and roguelikes, enjoyable to many players: meta-progression augments the increases in skill the player is naturally gaining as they play. In effect, it's not replacing the skill increase, but exaggerating it to make it feel more real to the player.

              Effortlessness

              Incremental games are so easy, a lot of them even have you progress while you're not playing! Part of the appeal is being able to feel like you're making progress while doing something actually productive - multitasking, in a way. In this sense, the game is more of a fidget toy - not something to think hard about and play actively, but something to click a few buttons every so often while you're paying attention to a lecture or studying or working. Of course, not all incremental games lend themselves to being played this way - it's specifically "idle" games that work like this. These are games that take an incredibly long amount of time to see all the content, stretching it as thin as possible, but they aren't expecting you to be sitting at your device playing it the entire time. They expect you to leave and come back later to make a bit of progress and repeat the cycle.

              If you look at the higher-level play of most games, you'll see them perform difficult feats with ease and speed. They'll achieve a "flow state" that takes all their knowledge and experience of the game and uses it to play the game as instinctively as possible. It's incredible to watch things like Slay the Spire speed runs or competitive DDR-likes. I'd argue the goal of a lot of games with a competitive scene is to get so good that the game becomes effortless. In that sense, a game that allows you to reach that point earlier isn't any less legitimate, but rather lowers the barrier to entry by allowing more people to get "really good" at the game. And to be clear, (most) incremental games aren't trivially easy - they, and to an extent, every game will have some level of learning and improvement over time.

              Addiction

              A lot of these reasons for why incremental games appeal may have reminded you of why gambling appeals to people, particularly those prone to addiction. Indeed, incremental games are quite often criticized for their similarity to a skinner box. Some have gone as far as to say incremental games as a genre are commenting that all games are skinner boxes). The argument goes that some games are not fun, but rather condition players into continuing to play without actually getting anything from the experience. When tied to real-world money this is seen as predatory, and to a lesser extent, even free games may be feeding the addictive sides of people and making them more prone to seek out gambling or micro-transaction heavy games.

              While incremental games can be fun and even healthy in certain contexts, they can exacerbate video game addiction more than other genres. If you feel like playing incremental games is taking priority over other things in your life, or manipulating your sleep schedule, it may be prudent to seek help. See r/StopGaming for resources.

              Since incremental games are often built on extrinsic motivations in the form of progression systems, it's hard to argue whether players continue to play because they are enjoying the gameplay, or if they are just conditioned to keep doing it because the game keeps rewarding them. Unfortunately, it can often feel like it's the latter, as there isn't typically anything compelling about the "gameplay" of clicking a button and waiting. There may be a significant overlap between those who enjoy incremental games and those who are most prone to addiction, and there are often posts on r/incremental_games about someone either struggling with or overcoming video game addiction.

              Strategy

              Incremental games could be considered a subset of strategy games), and inherit the appeals of strategy games. This includes the appeal of feeling like you've found a good solution to a puzzle, or that you're learning more about the game and are improving at making decisions within it.

              Note that strategy games are not all the same difficulty, as well. Cookie Clicker is probably easier than Starcraft 2 (although late game may beg to differ). Plenty of incremental games can be used as evidence that "easier" strategies may have their separate appeal to harder strategy games - players like to feel smart and that they figured the game out and have optimized or mastered it, and the game being easier doesn't detract from that sense of accomplishment as much as it allows more and more users to be able to reach the point where they gain that sense.

              Avoiding Staleness

              Incremental games tend to have "paradigm shifts", where the gameplay changes in a meaningful way at various times throughout the progression of the game. These upset and change the gameplay loop, which helps keep them from stagnating. This constant "freshness" to the gameplay can keep players engaged for longer, compared to a game with a repetitive and static gameplay loop.

              Good Game Design

              Incremental games tend to show their game design "plainly", so it's more readily apparent if a game has good game design while playing, even if you're not looking for it. While different players have different preferences and might enjoy different types of games more than others, there are underlying good and bad game design principles that players will notice the effects of. To be clear, this isn't talking about stuff like big numbers being enjoyable, where I can comfortably agree to disagree with other players. They don't intrinsically make my experience better, but I'm aware of those for whom it does and I won't argue against their feelings. However, the game designer in me does feel like there are some extremely clear-cut examples of good and bad game design philosophies.

              Let's start by giving an example of a mechanic I think can be easily and strongly argued is good game design. There are of course many examples, but a personal favorite of mine is how DOOM encourages aggressive gameplay by linking health drops to melee attacks. It has an intended experience it's trying to give the player - immersing themselves as DOOM guy, who would not hide behind cover when low on health - and this mechanic does a great job at encouraging and effectively teaching players to behave properly. This is in sharp contrast to shooters like Call of Duty, which have you regen health passively, encouraging players to hide behind cover and wait after getting hit. Note that I'm not arguing CoD is poorly designed, as the games have different intended experiences. I'm specifically praising DOOM for having a mechanic that does a good job at ensuring the player has that intended experience.

              To contrast with an example I think is bad game design, let's talk about shields in souls-likes. This is a bit of a famous example, and I highly recommend this video essay which spends quite a good bit of time on this topic. Essentially, the argument boils down to players of earlier games in the souls games using shields too much - playing slowly, conservatively, and ultimately having less fun. Players wanted to feel safe, so they ended up playing in a way that ruined the experience for them. The developers solved this by removing shields, apart from an intentionally bad one effectively mocking the playstyle, and it did its job at getting players to play more aggressively, and often have more fun.

              To bring the conversation back to incrementals, I'm incredibly opinionated on what makes a good incremental game, which I'll discuss in the game design section. Suffice it to say, incremental games rely more on good game design than other genres, due to not having much to distract from bad game design. This helps (although imperfectly - gamers are a bit too tolerant of bad game design!) well-designed games rise to the top within the genre.

              Artistic Merit

              The discussion of whether video games are art has resulted in a pretty universal "yes, they are", but with some games the argument may still crop up. The reason why Incremental games are sometimes questioned is due to their perceived lack of complexity. However, even setting aside the fact that if players are having fun then it's not time wasted, I think games can have artistic merit that supersedes the necessity of having (any / engaging / "deep") gameplay. Incremental games are no less legitimate of a game or the "art" label because of any lack perceived lack of depth. For what it's worth, most art can be consumed with more ease than any video game - any painting, movie, sculpture, etc.

              A lot of incrementals have a narrative context that can similarly qualify them as art. Cookie Clicker is, as has been pointed out numerous times before, commenting on excess and increasing production beyond any reasonable limits - devolving into increasing production for its own sake. Indeed, a lot of incremental games are written to comment upon various concepts like capitalism or tropes in games, as discussed when defining Incrementals). However, I'd like to argue most incremental games are still art, even without any narrative context. "Art" as a concept is pretty nebulous already, but I personally like those who define it as an act of expression more than any physical result. The creator and the context within which they created the art, and any meaning they put into it, are all relevant and a part of the art itself. Most incremental games have artistic merit from things like why the creator made it, why they chose to make it an incremental game, and why they made any particular design decision. Hell, even if you play through an entire incremental game without a single thought or feeling, that very fact it elicited nothing can itself be artistic merit!

              I'm not an art major, and I may be taking a somewhat extreme take on what is art and what has artistic merit, but I'd argue the overall point stands that games, and incremental games specifically, can have artistic merit, which appeals to many gamers.

              + \ No newline at end of file diff --git a/guide-to-incrementals/ludology/content/index.html b/guide-to-incrementals/ludology/content/index.html index 18512051..8c5c22e8 100644 --- a/guide-to-incrementals/ludology/content/index.html +++ b/guide-to-incrementals/ludology/content/index.html @@ -6,14 +6,14 @@ Guide to Incrementals/What is Content? | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Guide to Incrementals___What is Content?

              2092 words, ~11 minute read. Planted +

              Skip to content

              Guide to Incrementals___What is Content?

              2092 words, ~11 minute read. Planted . Last tended to -.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              If you've been in the incremental games community for any amount of time, you'll quickly find the number one thing players want is content. They want as much of it as possible! The most popular incremental games have tons of content, so they just keep stretching on and on and on, introducing mechanic after mechanic, and players love it. In fact, players seem to value the amount of content over the quality of any specific content. However, there's a bit of a lack of understanding concerning what content is, and I'd like to explore what counts as content, and how we measure it. As a baseline definition, I think "content" can just be described as the parts of the game that engage the player, but to truly understand it we need to contextualize what that means and how it affects the gameplay experience.

              To clarify the purpose of this page, my goal is not to get (too) nitpicky or to attack games with "low content". There's nothing wrong with short / low-content games - I'm quite a big fan of those games myself! This is mostly targeted toward those who ask for content and settle for "long" games, and those who want to provide content but want to make sure they're not just artificially inflating the game. Ultimately, I suppose the goal is to just reduce the amount of artificially inflated content for the sake of having a "longer" game.

              Interaction

              I think it should be a fairly non-controversial opinion that time spent solely waiting should not count towards content. That is not including the time reading various effects or making decisions in your head, but rather time spent waiting for a condition to be met so you can re-engage with the game.

              That is not to say games should necessarily try to minimize this time. Plenty of games lead towards more infrequent interaction and still get popular. In fact, these games appeal to many gamers who want to have something to check up on in between bursts of working on some other activity. These games seem to have fallen slightly out of fashion amongst modern incremental games, but they're still fully valid. The point I'm trying to make here is just that this time is not content. As an extreme example, a game with no interactions and just a counter that goes up every second could safely be said to have 0 content beyond the time it takes to understand what's going on. If it has a list of "goals" to hit, then the time understanding those goals and a short time after achieving each one could be considered content, but not the idle times in between.

              Let's take a look at the opposite end of the spectrum - interaction that is so frequent as to become mindless. This is any mechanic where you need to spam-click something to progress. This may be a more controversial take, but I do not believe this constitutes content either. It does not engage the player, because each consecutive click blends together and they do not individually change the gameplay experience. That is to say, a single click and 100 clicks are not meaningfully different in terms of engaging the player. I'd go as far as to say clicking 100 times would be actively worse, as it's artificially delaying the next piece of actual content, alongside the issues of accessibility and potentially causing RSI.

              Repeatable Purchases

              Imagine an entity in a game that you can purchase multiple times, each time it performs the same thing but for a higher cost. These are incredibly common, from the buildings in cookie clicker to the units in swarm sim to the IP and EP multipliers in antimatter dimensions. However, how much content is each specific purchase? Is it content beyond the first purchase? Does it have diminishing returns? What if you are oscillating between two different repeatable purchases? How much content is lost when you automate) away a repeatable purchase?

              I don't want to take too harsh a stance against repeatable purchases. They're useful tools and can be used in a myriad of interesting ways. I feel they do become "stale" or less meaningful content over time, and this happens exponentially quickly the more frequently it can be purchased. A classic example that I believe goes too far is the IP/EP multipliers in Antimatter Dimensions. I would go as far as to say they are a chore and do not provide any meaningful content after you've bought them a couple of times. It's a method for inflating numbers (effectively making every OOM a 5x step instead of 10x), that punishes the player progression-wise whenever they forget to max it again, and eventually gets automated away as a reward to the player for making enough progress.

              Just to voice the other side of this argument, Acamaeda defended the IP multiplier as giving the player a "good" upgrade every OOM. I can understand that to a point and need to clarify I'm mainly criticizing IP/EP multipliers after they've been introduced for a while. In fact, I would defend the multipliers for a short while after they're introduced using the same logic I would use to defend normal dimensions as repeatable purchases, at least pre-infinity. There's "content" to be had in looking at what dimensions will become affordable next, and then choosing which to buy amongst those. The IP/EP multipliers, early into infinity or eternity respectively, provide another option that gets put into that mental queue of things to buy with each OOM reached - although the optimal order is often quite trivial and not particularly engaging.

              The IP/EP multipliers are not the only repeatable purchase in antimatter dimensions I take offense to. The time dimensions are also a series of repeatable purchases, that are all so similar and static that it doesn't take long before you never need to put any thought into buying them, how much you're buying at once, or the order you buy them in - you just press max all and move on. The entire tab could've been just the max all button and it would not have made a difference beyond the start of the eternity layer. The normal dimensions technically have this problem as well, but since you're constantly getting antimatter the order feels like it has a larger impact and it's more meaningful content, right up until they're automated away. Infinity dimensions are a compromise between the two, so I'm highlighting time dimensions here as the most egregious.

              Following Instructions

              We're getting more and more controversial as we go along! Let's talk about how linear content is not content now (in some circumstances). A trend in incremental games is adding difficulty by adding a web of effects that abstract the true change you can expect from any specific purchase or decision you make. If a game is both linear and sufficiently abstracts the effect of player decisions, then the player will no longer be engaging with the content - they'll simply be clicking on things as they become available. This isn't necessarily a bad thing, as plenty of players don't mind this style of gameplay, but I'd argue once you reach a point where players don't bother reading the effects, those interactions are no longer truly content. Note that unlike the previous qualifiers mentioned, this qualifier is based on the player, and therefore subjective. In effect, it's a spectrum where the more complicated the web of effects becomes, the more likely it is to disengage the player.

              This over-complicatedness leading to disengaging the player can also happen from non-linear gameplay. If the web of effects becomes sufficiently complicated and finding the optimal progression route too time-consuming to discover, players will seek out guides from other players who've completed the game. The second they do this, the game effectively becomes linearly following the instructions of the guide and all the above criticisms apply. Similarly to as before, though, this is a spectrum and not everyone will seek out a guide at the same level of difficulty.

              Automation

              Automation is a staple of the genre, but it has certain implications for the design of the game. Why, when new content is introduced, must the older content be automated away - why is it a chore and it feels rewarding to not have to do it again? Why does the new mechanic have such appeal if we know it too will just be automated away later on, and we'll be happy when that happens? It honestly begs the question of why this framework of introducing content and automating the old content is even enjoyable - and nearly nonexistent in other genres. You're not going to reach a point in a platformer game where they just automate the jumping part - that's the core mechanic! Instead, platformers either add new mechanics that build on the core mechanic or at least re-contextualize the core mechanic. However, in incremental games new content very frequently means replacing older content, as opposed to augmenting it.

              Admittedly, the above paragraph ignores the obvious answer that separates incremental games in this regard. These mechanics become chores as their frequency increases. The frequency increases to give a sense of progression, and automation is seen as a reward because it now manages what was becoming unmanageable. The new content then comes in and continues the loop to give a stronger sense of progression. That's all good and a fine justification for automating content instead of building upon the base mechanic. It's also much easier to design, as each layer essentially lets you start over instead of needing to think of ideas that conform to the original core mechanic.

              So, what's the problem? Even if this trend is justified and easy to implement, there are some other effects it has on the game design. First off, and this is probably a neutral point, incremental games with this cycle of replacing old mechanics with new ones trend towards more and more abstract and further away from any narrative throughline as they add layers. There are only so many justifications for resetting progress, so if a game wants to have several of these layers they're inevitably going to become generic or increasingly loosely associated with the original content. It's most unfortunate, in my opinion when an interesting or innovative core mechanic gets fully automated once a generic "prestige" layer is unlocked.

              A recent example is Really Grass Cutting Incremental, an incremental game about cutting grass (although I'm really criticizing the Roblox game it's based on). Except, it doesn't continue to be about cutting grass. After you buy enough upgrades to increase your grass cutting and level up sufficiently you "prestige", an abstract term that in this case means you reset all your progress to get some currency to buy upgrades that do the same things as the original upgrades, but these won't reset on future prestiges. You'll eventually be able to "crystallize", which means you reset all your progress to get some currency to buy upgrades that do the same things as the original upgrades (and a couple of new ones) and won't reset on future crystallizes. Fine. You'll progress a bit, complete some challenges, and finally get to... grasshop? Grasshopping is this mechanic where you reset all your progress to get some resource that isn't for buying upgrades - this time you just unlock different modifiers on everything based on their amount. You may have gotten the point by now, but there are also "steelie" resets which give you steel for some reason, before unlocking a factory with various machines - none of which are directly tied to cutting grass, and start gathering things like oil and reset for rocket parts and reset to go to space and so on and so on. Throughout all of this there is absolutely no narrative justification or throughline for the direction the game is going, or why cutting grass is still relevant when we're collecting things like rocket parts. I may be going a little hard on GCI, but it is far from alone.

              Tips for Developers

              If you're a developer, by this point you should have a pretty decent idea of how to create "true" content in your game. Here are some other specific tips I'd suggest:

              An upgrade that simply unlocks another upgrade trivially isn't content. However, many games have an upgrade that just unlocks a feature, which then has a wait or other requirements before it can be used. Try to make sure when you unlock a feature, there is immediately something to do with the feature - for example, perhaps give them a small amount of the new currency it unlocks, if applicable.

              If you don't have a large web of effects, and can definitively say the impact of a purchase is to multiply the gain of the cost currency by N, and the next purchase costs N times the amount of that same currency, then this purchase effectively made no difference and it may have made more sense to just go directly to the next upgrade. That said, having effects based on things like the number of purchases made will quickly invalidate this tip.

              - +.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              If you've been in the incremental games community for any amount of time, you'll quickly find the number one thing players want is content. They want as much of it as possible! The most popular incremental games have tons of content, so they just keep stretching on and on and on, introducing mechanic after mechanic, and players love it. In fact, players seem to value the amount of content over the quality of any specific content. However, there's a bit of a lack of understanding concerning what content is, and I'd like to explore what counts as content, and how we measure it. As a baseline definition, I think "content" can just be described as the parts of the game that engage the player, but to truly understand it we need to contextualize what that means and how it affects the gameplay experience.

              To clarify the purpose of this page, my goal is not to get (too) nitpicky or to attack games with "low content". There's nothing wrong with short / low-content games - I'm quite a big fan of those games myself! This is mostly targeted toward those who ask for content and settle for "long" games, and those who want to provide content but want to make sure they're not just artificially inflating the game. Ultimately, I suppose the goal is to just reduce the amount of artificially inflated content for the sake of having a "longer" game.

              Interaction

              I think it should be a fairly non-controversial opinion that time spent solely waiting should not count towards content. That is not including the time reading various effects or making decisions in your head, but rather time spent waiting for a condition to be met so you can re-engage with the game.

              That is not to say games should necessarily try to minimize this time. Plenty of games lead towards more infrequent interaction and still get popular. In fact, these games appeal to many gamers who want to have something to check up on in between bursts of working on some other activity. These games seem to have fallen slightly out of fashion amongst modern incremental games, but they're still fully valid. The point I'm trying to make here is just that this time is not content. As an extreme example, a game with no interactions and just a counter that goes up every second could safely be said to have 0 content beyond the time it takes to understand what's going on. If it has a list of "goals" to hit, then the time understanding those goals and a short time after achieving each one could be considered content, but not the idle times in between.

              Let's take a look at the opposite end of the spectrum - interaction that is so frequent as to become mindless. This is any mechanic where you need to spam-click something to progress. This may be a more controversial take, but I do not believe this constitutes content either. It does not engage the player, because each consecutive click blends together and they do not individually change the gameplay experience. That is to say, a single click and 100 clicks are not meaningfully different in terms of engaging the player. I'd go as far as to say clicking 100 times would be actively worse, as it's artificially delaying the next piece of actual content, alongside the issues of accessibility and potentially causing RSI.

              Repeatable Purchases

              Imagine an entity in a game that you can purchase multiple times, each time it performs the same thing but for a higher cost. These are incredibly common, from the buildings in cookie clicker to the units in swarm sim to the IP and EP multipliers in antimatter dimensions. However, how much content is each specific purchase? Is it content beyond the first purchase? Does it have diminishing returns? What if you are oscillating between two different repeatable purchases? How much content is lost when you automate) away a repeatable purchase?

              I don't want to take too harsh a stance against repeatable purchases. They're useful tools and can be used in a myriad of interesting ways. I feel they do become "stale" or less meaningful content over time, and this happens exponentially quickly the more frequently it can be purchased. A classic example that I believe goes too far is the IP/EP multipliers in Antimatter Dimensions. I would go as far as to say they are a chore and do not provide any meaningful content after you've bought them a couple of times. It's a method for inflating numbers (effectively making every OOM a 5x step instead of 10x), that punishes the player progression-wise whenever they forget to max it again, and eventually gets automated away as a reward to the player for making enough progress.

              Just to voice the other side of this argument, Acamaeda defended the IP multiplier as giving the player a "good" upgrade every OOM. I can understand that to a point and need to clarify I'm mainly criticizing IP/EP multipliers after they've been introduced for a while. In fact, I would defend the multipliers for a short while after they're introduced using the same logic I would use to defend normal dimensions as repeatable purchases, at least pre-infinity. There's "content" to be had in looking at what dimensions will become affordable next, and then choosing which to buy amongst those. The IP/EP multipliers, early into infinity or eternity respectively, provide another option that gets put into that mental queue of things to buy with each OOM reached - although the optimal order is often quite trivial and not particularly engaging.

              The IP/EP multipliers are not the only repeatable purchase in antimatter dimensions I take offense to. The time dimensions are also a series of repeatable purchases, that are all so similar and static that it doesn't take long before you never need to put any thought into buying them, how much you're buying at once, or the order you buy them in - you just press max all and move on. The entire tab could've been just the max all button and it would not have made a difference beyond the start of the eternity layer. The normal dimensions technically have this problem as well, but since you're constantly getting antimatter the order feels like it has a larger impact and it's more meaningful content, right up until they're automated away. Infinity dimensions are a compromise between the two, so I'm highlighting time dimensions here as the most egregious.

              Following Instructions

              We're getting more and more controversial as we go along! Let's talk about how linear content is not content now (in some circumstances). A trend in incremental games is adding difficulty by adding a web of effects that abstract the true change you can expect from any specific purchase or decision you make. If a game is both linear and sufficiently abstracts the effect of player decisions, then the player will no longer be engaging with the content - they'll simply be clicking on things as they become available. This isn't necessarily a bad thing, as plenty of players don't mind this style of gameplay, but I'd argue once you reach a point where players don't bother reading the effects, those interactions are no longer truly content. Note that unlike the previous qualifiers mentioned, this qualifier is based on the player, and therefore subjective. In effect, it's a spectrum where the more complicated the web of effects becomes, the more likely it is to disengage the player.

              This over-complicatedness leading to disengaging the player can also happen from non-linear gameplay. If the web of effects becomes sufficiently complicated and finding the optimal progression route too time-consuming to discover, players will seek out guides from other players who've completed the game. The second they do this, the game effectively becomes linearly following the instructions of the guide and all the above criticisms apply. Similarly to as before, though, this is a spectrum and not everyone will seek out a guide at the same level of difficulty.

              Automation

              Automation is a staple of the genre, but it has certain implications for the design of the game. Why, when new content is introduced, must the older content be automated away - why is it a chore and it feels rewarding to not have to do it again? Why does the new mechanic have such appeal if we know it too will just be automated away later on, and we'll be happy when that happens? It honestly begs the question of why this framework of introducing content and automating the old content is even enjoyable - and nearly nonexistent in other genres. You're not going to reach a point in a platformer game where they just automate the jumping part - that's the core mechanic! Instead, platformers either add new mechanics that build on the core mechanic or at least re-contextualize the core mechanic. However, in incremental games new content very frequently means replacing older content, as opposed to augmenting it.

              Admittedly, the above paragraph ignores the obvious answer that separates incremental games in this regard. These mechanics become chores as their frequency increases. The frequency increases to give a sense of progression, and automation is seen as a reward because it now manages what was becoming unmanageable. The new content then comes in and continues the loop to give a stronger sense of progression. That's all good and a fine justification for automating content instead of building upon the base mechanic. It's also much easier to design, as each layer essentially lets you start over instead of needing to think of ideas that conform to the original core mechanic.

              So, what's the problem? Even if this trend is justified and easy to implement, there are some other effects it has on the game design. First off, and this is probably a neutral point, incremental games with this cycle of replacing old mechanics with new ones trend towards more and more abstract and further away from any narrative throughline as they add layers. There are only so many justifications for resetting progress, so if a game wants to have several of these layers they're inevitably going to become generic or increasingly loosely associated with the original content. It's most unfortunate, in my opinion when an interesting or innovative core mechanic gets fully automated once a generic "prestige" layer is unlocked.

              A recent example is Really Grass Cutting Incremental, an incremental game about cutting grass (although I'm really criticizing the Roblox game it's based on). Except, it doesn't continue to be about cutting grass. After you buy enough upgrades to increase your grass cutting and level up sufficiently you "prestige", an abstract term that in this case means you reset all your progress to get some currency to buy upgrades that do the same things as the original upgrades, but these won't reset on future prestiges. You'll eventually be able to "crystallize", which means you reset all your progress to get some currency to buy upgrades that do the same things as the original upgrades (and a couple of new ones) and won't reset on future crystallizes. Fine. You'll progress a bit, complete some challenges, and finally get to... grasshop? Grasshopping is this mechanic where you reset all your progress to get some resource that isn't for buying upgrades - this time you just unlock different modifiers on everything based on their amount. You may have gotten the point by now, but there are also "steelie" resets which give you steel for some reason, before unlocking a factory with various machines - none of which are directly tied to cutting grass, and start gathering things like oil and reset for rocket parts and reset to go to space and so on and so on. Throughout all of this there is absolutely no narrative justification or throughline for the direction the game is going, or why cutting grass is still relevant when we're collecting things like rocket parts. I may be going a little hard on GCI, but it is far from alone.

              Tips for Developers

              If you're a developer, by this point you should have a pretty decent idea of how to create "true" content in your game. Here are some other specific tips I'd suggest:

              An upgrade that simply unlocks another upgrade trivially isn't content. However, many games have an upgrade that just unlocks a feature, which then has a wait or other requirements before it can be used. Try to make sure when you unlock a feature, there is immediately something to do with the feature - for example, perhaps give them a small amount of the new currency it unlocks, if applicable.

              If you don't have a large web of effects, and can definitively say the impact of a purchase is to multiply the gain of the cost currency by N, and the next purchase costs N times the amount of that same currency, then this purchase effectively made no difference and it may have made more sense to just go directly to the next upgrade. That said, having effects based on things like the number of purchases made will quickly invalidate this tip.

              + \ No newline at end of file diff --git a/guide-to-incrementals/ludology/definition/index.html b/guide-to-incrementals/ludology/definition/index.html index 70defb22..9e5be4fa 100644 --- a/guide-to-incrementals/ludology/definition/index.html +++ b/guide-to-incrementals/ludology/definition/index.html @@ -6,14 +6,14 @@ Guide to Incrementals/Defining the Genre | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              Guide to Incrementals___Defining the Genre

              3429 words, ~19 minute read. Planted +

              Skip to content

              Guide to Incrementals___Defining the Genre

              3429 words, ~19 minute read. Planted . Last tended to -.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              Video games are placed into genres for a variety of reasons. They can give a mental shorthand to set the player's expectations up, they can help a game market itself by its similarities to other, already popular games, and honestly, people just love categorization for its own sake. For this guide, it's important to define the genre so it is clear what games it's even talking about.

              This poses a problem. "Incremental" is a horribly vague way to define games. Most games have numbers going up in some form or another. We need a more specific definition - similar to how "strategy" can't just mean any game with any amount of strategy because that would be most games. What specifically differentiates incremental games from the rest?

              "Incremental" implies it's a genre defined by a game mechanic, but all those game mechanics it could imply exist in many other games. Having a skill tree or upgrades doesn't make you incremental, and if a reset mechanic is all it takes then every roguelite would be an incremental as well. So clearly there's more to it than that - what makes an incremental an incremental?

              I'd like to go over a couple of popular suggestions I've seen on defining the genre here. I have my personal preferences and will state them here, but I don't think there's a truly perfect answer here.

              Disclaimer: I mostly play incremental games on my computer, and my definitions will be heavily biased towards the games I'm familiar with.

              Incrementals vs Idlers vs Clickers

              Oftentimes people refer to this genre as idle games and/or clicker games. You'll even find a trend of oxymoronic game titles that contain both terms. "Incremental games" is the umbrella term both those terms fall under. However, I'd like to argue that not only is it better to just use the term "incremental games", but calling them "idle games" or "clicker games" is wrong. Almost universally, these terms are used interchangeably to refer to the same kind of game, where you start the game click spamming and eventually automate the process. Frankly, that kind of game deserves neither title, and the genre of incremental games has trended away from ever requiring click spamming, as it's a bad mechanic, anyways.

              While these games do span a spectrum of how active it requires you to be, and sorting games by that metric can be useful for those looking for a particular experience, the borders of when an incremental game counts as an "idler" is too blurry for the term to be useful. "Incremental games" may not be a great descriptive term for the genre (hence this many thousands of words long page on defining what the genre even is), but it's strictly better than calling them "idler" or "clicker" games. This guide will always use the term "incremental games" unless quoting someone else, as it is the term you typically see on all modern games in the genre.

              Incrementals as Parodies

              Let's start with one of the most interesting definitions of incremental games. Incremental games appear to be distilled versions of games or genres, "revealing" the naked game design at the core of these games or genres not unlike how parodies comment upon their source material.

              To understand what that means, think of how a casino uses skinner boxes to emotionally manipulate its customers to keep playing, but "dressing" up the skinner box with tons of stimuli to hide that ultimately the goal is to condition you into coming back compulsively. The idea that incremental games are parodies means taking the stance that at some level all games are similarly manipulating you, giving dopamine rewards in a way that manipulates you to keep playing while not necessarily giving you any value or fulfillment. Incremental games, then, are any games that plainly display the skinner box, and the manipulative core of the game, at the forefront of the experience.

              While incremental games can be fun and even healthy in certain contexts, they can exacerbate video game addiction more than other genres. If you feel like playing incremental games is taking priority over other things in your life, or manipulating your sleep schedule, it may be prudent to seek help. See r/StopGaming for resources.

              This "undressing" tends to go hand in hand with a reduced focus on aesthetics, often just printing the game state directly to the screen as text. This makes incremental games much easier to develop, particularly for those with programming skills but not art skills, but that's a tangent for why Incremental Games Guide to Incrementals/Appeal to Developers.

              Before I continue, I'd like to make my stance clear that I love games and incremental games, and do not think they should be considered inherently bad or manipulative with the above logic. Skinner boxes are just a way of manipulating behavior via rewards. The games are still fun - that's the reward! I'd believe the real criticism here is that it is "empty fun", or "empty dopamine", that doesn't offer any additional value or sense of fulfillment. I don't think that's inherently bad in moderation, although it can become a problem if the game is manipulating you for profit-seeking, or if you play the game to the detriment of the other parts of your life.

              Another interpretation of incremental games as parodies comes from several mainstream incremental games that are also parodies of capitalism, such as cookie clicker and adventure capitalist. It's a very common framework for incremental games to portray the ever-increasing numbers as an insatiable hunger for resources, like the ones observed within capitalism. Therefore, these games are used as evidence that the genre as a whole is about parody and commentary.

              Popular videos on incremental games that portray the genre as parodies are Why Idle games make good satire, and how it was ruined. and Bad Game Design - Clicker Games. You may also be interested in this response to the latter video from a fan of incremental games: BadGood Game Design - Clicker Games.

              I think that this definition ultimately ascribes a motive to the genre as a whole that only happens to apply to some of the more mainstream titles. There certainly are incremental games commenting on different things, including the genre itself as in the case of The Prestige Tree Classic, The Ascension Tree, or Omega Layers, but certainly not all. And of course, not all games that comment on something or parody something are incremental games! Additionally, a very large majority of incremental games are mobile games using these manipulative strategies to get players to spend as much money as possible - hell, Adventure Capitalist is ostensibly a critique on capitalism but features microtransactions and gameplay that manipulates you into buying them! These profit-seeking incremental games certainly belong within the genre but are hardly parodies when they too use manipulation to serve their interests. Also, from my own anecdotal experience, those who use this definition seem to do so from a fairly surface-level familiarity with the genre, and often in the context of criticizing the genre or the fans thereof.

              Incrementals as NGU

              Another broad definition often used is that incremental games are games where the focus of the game is "numbers going up". This definition proposes that other genres simply use increasing numbers as a means to an end, but incremental games uniquely only care about the numbers themselves going up. Put another way, it implies there should be no narrative justification for the numbers going up other than "why shouldn't they be going up?"

              While this definition is common because it feels easy to understand, it is difficult to formally define. Often phrases are used to describe games using this framework, such as having an "exaggerated sense of progression" or "big" numbers. These terms are vague and don't demonstrate an actual threshold between non-incrementals and incrementals. Most games have a sense of progression, so when is it "exaggerated"? How big are "big" numbers? Most notably, RPGs that are typically not considered incrementals will often pass this definition.

              Additionally, a lot of incrementals tend to have some theme guiding the gameplay, or at least the names of mechanics. This makes the line blurred between when numbers are going up for their own sake versus for a contextual reason. I believe this point is best illustrated that, while most RPGs are not considered incremental games, there is a sub-genre of "incremental RPGs" that typically relates to RPGs that perform combat automatically. This definition of incremental games does not support RPGs and "incremental RPGs" being on distinct sides of the line if the only difference between them is manual vs automatic combat.

              Incrementals as Strategies

              This is a rarer interpretation, but there are similarities between incremental games and strategy games, implying incrementals might just be a sub-genre of strategy games. By this approach, incremental games would be defined by their relation to strategy games, and how they involve player strategy. Incremental games are often large optimization problems - above all else, the actual gameplay the player is performing is deciding what to do next. The consequences of wrong decisions are typically more lenient in incremental games - such as just not making optimal progress - but they certainly get complex.

              So if we accept the premise that incrementals could fall under strategy, we still need to define what makes a strategy game an incremental versus some other strategy sub-genre. This is a bit tricky due to one particular sub-genre of strategy games: Factory Builders.

              Factory builders, such as Factorio or Satisfactory, are games about gaining ever increasing resources, optimizing production, and expanding more and more. That... sounds pretty similar, doesn't it? In fact, there's been some debate on whether factory builders would fall under the "incremental" umbrella. I think it's safe to say the two are certainly related, and probably have quite a bit of overlap in playerbase.

              Roguelites as Incrementals?

              Earlier on, I mentioned reset mechanics shouldn't be used in the definition because that could make all roguelites incrementals... But what if it does? A lot of incrementals can be described as games with a strong sense of progression, often with layers of meta-progression. Roguelites fit that bill to a T. What would make roguelites not incremental? I honestly don't think there's a good explanation here, but many fans of incremental games will state they do believe the two genres to be unrelated, even if there's a significant overlap between their player bases due to having similar appealing traits.

              At this point, it'd be appropriate to consider what part of the definition of roguelites precludes them from also being incrementals, but that reveals a new problem: What are roguelites? They're usually defined as rogue_likes with meta-progression, but that just pushes the problem back a step: Incrementals aren't the only genre to have difficulties defining themselves, it seems! Roguelikes are another genre where the community argues over the formal definition of their genre, although that means we can borrow from their process of coming to a consensus, and maybe come across a viable definition for incremental games.

              The Berlin Interpretation

              By far the most popular way of defining roguelikes is the "Berlin Interpretation", which acknowledged the diversity of games within the genre and argued the definition should not be based on any ideals about what the genre ought to be, but rather defined by "its canon". They argued there are a handful of games that can be used to define the canon for roguelikes, and from those games, a list of factors can be derived to determine a game's "roguelikeness". The more factors a game has, the more of a roguelike it is. This strategy is very lenient, allowing a game to not present any specific factor so long as it shows enough, and accounts for the blurriness of any genre definition by not explicitly stating how many factors a game must have to qualify as a definite roguelike.

              I believe this strategy for defining genres can be applied to other genres as well. A handful of games can be argued to be the incremental games canon, and a list of factors derived from them can be used to judge any game based on its "incrementalness". I'll propose such a canon and list of factors here, but by no means should it be considered the end-all-be-all.

              Note: The "Temple of the roguelike", an authority within the genre, has since replaced the Berlin Interpretation with a new set of factors here: https://blog.roguetemple.com/what-is-a-traditional-roguelike/

              The Incremental Games Canon

              Alright, time to get controversial. Up til now, I've been trying my best to stay objective and analytical, but now it's time to start making some opinionated decisions. Here is a list of games I think could justifiably make up an Incremental Games Canon:

              I chose a variety of games here, biasing towards newer games, purposefully to avoid making a narrow or "traditional" definition. The genre is growing and shouldn't be constrained by the traits of the early popular titles. A lot of these could easily be replaced with other games that are mechanically congruent, so ultimately I'm sure if you asked 10 people for their canon list you'd just get 10 different answers, but I think this should sufficiently allow us to determine what factors make a game have higher "incrementalness".

              The Paradigm Shift

              The Paradigm Shift is probably the highest possible value factor for an incremental. It's so common that for a while people referred to incrementals that exhibit this trait as "unfolding" games, to the point of trying to replace the term incremental due to their popularity. Paradigm shifts refer to when the gameplay significantly changes. There are too many examples to list here, but notably, every single reset mechanic is typically going to be a paradigm shift. Examples of games with paradigm shifts that aren't tied to reset mechanics include Universal Paperclips and A Dark Room.

              There are many reasons for the appeal of paradigm shifts. Oftentimes each mechanic builds on top of the existing mechanics, increasing the complexity of the game in steps so the player can follow along. They provide a sense of mystery, with the player anticipating what will happen next. They shake up the gameplay before it gets too stale - allowing the game to entertain for longer before the sense of Guide to Incrementals/What is Content? dissipates. Of the canon games selected above, I would argue every single one contains a paradigm shift (although I could see someone disagreeing with that statement wrt Increlution).

              I should take a moment to say that while I'm hyping up this specific factor, we cannot just reduce the genre definition to "does it have paradigm shifts". Many games have paradigm shifts that are not incremental, so it's just an indicator of incrementalness. Additionally, it can become quite hard to determine how large of a shift is a "paradigm" shift. Take, for example, any game with a skill tree. In some games, each skill node might have a large impact on how you play with the game, and qualify as a paradigm shift for some players. In other games, each skill node might just be a small percentage modifier on some stat that doesn't really impact much more than a slight bias towards an already established mechanic that's newly buffed. Every single canon game may show that it's common amongst incremental games, but could just as easily indicate that they're common in games in general.

              High-Value Factors

              I won't take as long to discuss the high and low-value factors, as you've already seen most of them brought up earlier on this page. As a reminder, a game does NOT need all of these to be an incremental game, but these are factors that each indicate a strong possibility the game is an incremental, so having several of these means they probably are. These factors apply to most of the canon incremental games.

              "Pure UI" Display. Incrementals typically have a textual presentation of the game state - there isn't a visual representation of the entities within the game. The interface is closer to what would be just the UI of a game in another genre or the control panel of a plane. If there is a visual representation, the player is often still interacting with non-diegetic game elements.

              Reduced Consequences. Incrementals tend to have reduced repurcussions for misplaying. They very rarely have fail states, where often the largest consequence is simply not progressing - never losing progress.

              Optimization Problems. The predominant gameplay of incrementals is typically solving optimization problems, from deciding which purchase to save up for to reasoning and deciding between different mutually exclusive options the game presents.

              Resource Management. Incrementals tend to have a lot of resources within the game to keep track of.

              Low-Value Factors

              These are low-value factors, meaning they aren't as strongly correlated with incremental games. Incremental games may have none of these, and non-incrementals may have several of these - if a game only has low-value factors, they're probably not an incremental.

              Fast Numeric Growth. Numbers in incremental games tend to grow faster than in other genres. There are more instances of superlinear growth. The larger the numbers get, the stronger of a signal this factor is.

              Automation. As an incremental game progresses, the player often no longer has to deal with earlier mechanics, by having them either happen automatically or otherwise be replaced with an alternative that requires less player interaction.

              Goal-Oriented. Incrementals are often heavily reliant on extrinsic motivation to guide the player. Typically this is through some sort of in-game goal to work towards, such as a certain amount of a resource being required to unlock or purchase something new.

              Waiting is a Mechanic. In incremental games, the player may come across times where there is no action they can take, and the game will progress automatically instead. The player must wait for some amount of this automatic progress to occur before they can resume interaction with the game.

              Are Roguelites Incrementals?

              Having made our variation of the Berlin Interpretation for incremental games, we can compare it to the Berlin Interpretation to determine if there's enough overlap that any game that "passes" the Berlin Interpretation would also pass the incremental variant. That is to say, whether any roguelite would also be considered an incremental game.

              The meta-progression of an incremental game could arguably be considered a paradigm shift, and certainly adds some resource management. Goal-oriented would probably also apply. I think anything other than those would be a stretch, and in my opinion that just isn't enough to qualify. To be totally honest, I was never expecting to conclude otherwise though 😉

              Sub-Genres

              There are some trends in incremental games that go beyond just being a commonly used mechanic, such that they deeply affect the rest of the game design. These trends can be used to determine sub-genres within the incremental games umbrella:

              Loops games are a sub-genre defined by having a core mechanic related to a loop, where the player is deciding the actions taken per loop. Notable examples include Idle Loops, Stuck in Time, Cavernous II, and Increlution. You may also argue Groundhog Life and Progress Knight fall into this sub-genre.

              ITRTG-like games are a sub-genre defined by having a core mechanic based on clearing increasingly difficult battles and often tend to have a lot of different mechanics to become progressively stronger. Notable examples include Idling to Rule the Gods, NGU Idle, and Wizard and Minion Idle.

              Polynomial Growth games are a sub-genre defined by having a core mechanic related to a higher degree polynomial. Notable examples include the base layer of Antimatter Dimensions and Swarm Simulator.

              Upgrades Games is a category popular on flash games websites that featured games focused on buying upgrades that would allow you to attain more currency in some sort of minigame that would earn you more money to buy more upgrades, which I'd argue now belong under the fold of incremental games. Notable examples include the Learn to Fly series and Upgrade Complete.

              Cultivation RPGs are a genre of games, books, and anime popular in China that center around being in a fantasy world with characters getting stronger over time. While few of them get translated into English, a fan of incremental games may find the available games interesting.

              - +.


              Referenced by:Digital GardensIncremental SocialKronosMy Personal WebsiteSocial Media

              Video games are placed into genres for a variety of reasons. They can give a mental shorthand to set the player's expectations up, they can help a game market itself by its similarities to other, already popular games, and honestly, people just love categorization for its own sake. For this guide, it's important to define the genre so it is clear what games it's even talking about.

              This poses a problem. "Incremental" is a horribly vague way to define games. Most games have numbers going up in some form or another. We need a more specific definition - similar to how "strategy" can't just mean any game with any amount of strategy because that would be most games. What specifically differentiates incremental games from the rest?

              "Incremental" implies it's a genre defined by a game mechanic, but all those game mechanics it could imply exist in many other games. Having a skill tree or upgrades doesn't make you incremental, and if a reset mechanic is all it takes then every roguelite would be an incremental as well. So clearly there's more to it than that - what makes an incremental an incremental?

              I'd like to go over a couple of popular suggestions I've seen on defining the genre here. I have my personal preferences and will state them here, but I don't think there's a truly perfect answer here.

              Disclaimer: I mostly play incremental games on my computer, and my definitions will be heavily biased towards the games I'm familiar with.

              Incrementals vs Idlers vs Clickers

              Oftentimes people refer to this genre as idle games and/or clicker games. You'll even find a trend of oxymoronic game titles that contain both terms. "Incremental games" is the umbrella term both those terms fall under. However, I'd like to argue that not only is it better to just use the term "incremental games", but calling them "idle games" or "clicker games" is wrong. Almost universally, these terms are used interchangeably to refer to the same kind of game, where you start the game click spamming and eventually automate the process. Frankly, that kind of game deserves neither title, and the genre of incremental games has trended away from ever requiring click spamming, as it's a bad mechanic, anyways.

              While these games do span a spectrum of how active it requires you to be, and sorting games by that metric can be useful for those looking for a particular experience, the borders of when an incremental game counts as an "idler" is too blurry for the term to be useful. "Incremental games" may not be a great descriptive term for the genre (hence this many thousands of words long page on defining what the genre even is), but it's strictly better than calling them "idler" or "clicker" games. This guide will always use the term "incremental games" unless quoting someone else, as it is the term you typically see on all modern games in the genre.

              Incrementals as Parodies

              Let's start with one of the most interesting definitions of incremental games. Incremental games appear to be distilled versions of games or genres, "revealing" the naked game design at the core of these games or genres not unlike how parodies comment upon their source material.

              To understand what that means, think of how a casino uses skinner boxes to emotionally manipulate its customers to keep playing, but "dressing" up the skinner box with tons of stimuli to hide that ultimately the goal is to condition you into coming back compulsively. The idea that incremental games are parodies means taking the stance that at some level all games are similarly manipulating you, giving dopamine rewards in a way that manipulates you to keep playing while not necessarily giving you any value or fulfillment. Incremental games, then, are any games that plainly display the skinner box, and the manipulative core of the game, at the forefront of the experience.

              While incremental games can be fun and even healthy in certain contexts, they can exacerbate video game addiction more than other genres. If you feel like playing incremental games is taking priority over other things in your life, or manipulating your sleep schedule, it may be prudent to seek help. See r/StopGaming for resources.

              This "undressing" tends to go hand in hand with a reduced focus on aesthetics, often just printing the game state directly to the screen as text. This makes incremental games much easier to develop, particularly for those with programming skills but not art skills, but that's a tangent for why Incremental Games Guide to Incrementals/Appeal to Developers.

              Before I continue, I'd like to make my stance clear that I love games and incremental games, and do not think they should be considered inherently bad or manipulative with the above logic. Skinner boxes are just a way of manipulating behavior via rewards. The games are still fun - that's the reward! I'd believe the real criticism here is that it is "empty fun", or "empty dopamine", that doesn't offer any additional value or sense of fulfillment. I don't think that's inherently bad in moderation, although it can become a problem if the game is manipulating you for profit-seeking, or if you play the game to the detriment of the other parts of your life.

              Another interpretation of incremental games as parodies comes from several mainstream incremental games that are also parodies of capitalism, such as cookie clicker and adventure capitalist. It's a very common framework for incremental games to portray the ever-increasing numbers as an insatiable hunger for resources, like the ones observed within capitalism. Therefore, these games are used as evidence that the genre as a whole is about parody and commentary.

              Popular videos on incremental games that portray the genre as parodies are Why Idle games make good satire, and how it was ruined. and Bad Game Design - Clicker Games. You may also be interested in this response to the latter video from a fan of incremental games: BadGood Game Design - Clicker Games.

              I think that this definition ultimately ascribes a motive to the genre as a whole that only happens to apply to some of the more mainstream titles. There certainly are incremental games commenting on different things, including the genre itself as in the case of The Prestige Tree Classic, The Ascension Tree, or Omega Layers, but certainly not all. And of course, not all games that comment on something or parody something are incremental games! Additionally, a very large majority of incremental games are mobile games using these manipulative strategies to get players to spend as much money as possible - hell, Adventure Capitalist is ostensibly a critique on capitalism but features microtransactions and gameplay that manipulates you into buying them! These profit-seeking incremental games certainly belong within the genre but are hardly parodies when they too use manipulation to serve their interests. Also, from my own anecdotal experience, those who use this definition seem to do so from a fairly surface-level familiarity with the genre, and often in the context of criticizing the genre or the fans thereof.

              Incrementals as NGU

              Another broad definition often used is that incremental games are games where the focus of the game is "numbers going up". This definition proposes that other genres simply use increasing numbers as a means to an end, but incremental games uniquely only care about the numbers themselves going up. Put another way, it implies there should be no narrative justification for the numbers going up other than "why shouldn't they be going up?"

              While this definition is common because it feels easy to understand, it is difficult to formally define. Often phrases are used to describe games using this framework, such as having an "exaggerated sense of progression" or "big" numbers. These terms are vague and don't demonstrate an actual threshold between non-incrementals and incrementals. Most games have a sense of progression, so when is it "exaggerated"? How big are "big" numbers? Most notably, RPGs that are typically not considered incrementals will often pass this definition.

              Additionally, a lot of incrementals tend to have some theme guiding the gameplay, or at least the names of mechanics. This makes the line blurred between when numbers are going up for their own sake versus for a contextual reason. I believe this point is best illustrated that, while most RPGs are not considered incremental games, there is a sub-genre of "incremental RPGs" that typically relates to RPGs that perform combat automatically. This definition of incremental games does not support RPGs and "incremental RPGs" being on distinct sides of the line if the only difference between them is manual vs automatic combat.

              Incrementals as Strategies

              This is a rarer interpretation, but there are similarities between incremental games and strategy games, implying incrementals might just be a sub-genre of strategy games. By this approach, incremental games would be defined by their relation to strategy games, and how they involve player strategy. Incremental games are often large optimization problems - above all else, the actual gameplay the player is performing is deciding what to do next. The consequences of wrong decisions are typically more lenient in incremental games - such as just not making optimal progress - but they certainly get complex.

              So if we accept the premise that incrementals could fall under strategy, we still need to define what makes a strategy game an incremental versus some other strategy sub-genre. This is a bit tricky due to one particular sub-genre of strategy games: Factory Builders.

              Factory builders, such as Factorio or Satisfactory, are games about gaining ever increasing resources, optimizing production, and expanding more and more. That... sounds pretty similar, doesn't it? In fact, there's been some debate on whether factory builders would fall under the "incremental" umbrella. I think it's safe to say the two are certainly related, and probably have quite a bit of overlap in playerbase.

              Roguelites as Incrementals?

              Earlier on, I mentioned reset mechanics shouldn't be used in the definition because that could make all roguelites incrementals... But what if it does? A lot of incrementals can be described as games with a strong sense of progression, often with layers of meta-progression. Roguelites fit that bill to a T. What would make roguelites not incremental? I honestly don't think there's a good explanation here, but many fans of incremental games will state they do believe the two genres to be unrelated, even if there's a significant overlap between their player bases due to having similar appealing traits.

              At this point, it'd be appropriate to consider what part of the definition of roguelites precludes them from also being incrementals, but that reveals a new problem: What are roguelites? They're usually defined as rogue_likes with meta-progression, but that just pushes the problem back a step: Incrementals aren't the only genre to have difficulties defining themselves, it seems! Roguelikes are another genre where the community argues over the formal definition of their genre, although that means we can borrow from their process of coming to a consensus, and maybe come across a viable definition for incremental games.

              The Berlin Interpretation

              By far the most popular way of defining roguelikes is the "Berlin Interpretation", which acknowledged the diversity of games within the genre and argued the definition should not be based on any ideals about what the genre ought to be, but rather defined by "its canon". They argued there are a handful of games that can be used to define the canon for roguelikes, and from those games, a list of factors can be derived to determine a game's "roguelikeness". The more factors a game has, the more of a roguelike it is. This strategy is very lenient, allowing a game to not present any specific factor so long as it shows enough, and accounts for the blurriness of any genre definition by not explicitly stating how many factors a game must have to qualify as a definite roguelike.

              I believe this strategy for defining genres can be applied to other genres as well. A handful of games can be argued to be the incremental games canon, and a list of factors derived from them can be used to judge any game based on its "incrementalness". I'll propose such a canon and list of factors here, but by no means should it be considered the end-all-be-all.

              Note: The "Temple of the roguelike", an authority within the genre, has since replaced the Berlin Interpretation with a new set of factors here: https://blog.roguetemple.com/what-is-a-traditional-roguelike/

              The Incremental Games Canon

              Alright, time to get controversial. Up til now, I've been trying my best to stay objective and analytical, but now it's time to start making some opinionated decisions. Here is a list of games I think could justifiably make up an Incremental Games Canon:

              I chose a variety of games here, biasing towards newer games, purposefully to avoid making a narrow or "traditional" definition. The genre is growing and shouldn't be constrained by the traits of the early popular titles. A lot of these could easily be replaced with other games that are mechanically congruent, so ultimately I'm sure if you asked 10 people for their canon list you'd just get 10 different answers, but I think this should sufficiently allow us to determine what factors make a game have higher "incrementalness".

              The Paradigm Shift

              The Paradigm Shift is probably the highest possible value factor for an incremental. It's so common that for a while people referred to incrementals that exhibit this trait as "unfolding" games, to the point of trying to replace the term incremental due to their popularity. Paradigm shifts refer to when the gameplay significantly changes. There are too many examples to list here, but notably, every single reset mechanic is typically going to be a paradigm shift. Examples of games with paradigm shifts that aren't tied to reset mechanics include Universal Paperclips and A Dark Room.

              There are many reasons for the appeal of paradigm shifts. Oftentimes each mechanic builds on top of the existing mechanics, increasing the complexity of the game in steps so the player can follow along. They provide a sense of mystery, with the player anticipating what will happen next. They shake up the gameplay before it gets too stale - allowing the game to entertain for longer before the sense of Guide to Incrementals/What is Content? dissipates. Of the canon games selected above, I would argue every single one contains a paradigm shift (although I could see someone disagreeing with that statement wrt Increlution).

              I should take a moment to say that while I'm hyping up this specific factor, we cannot just reduce the genre definition to "does it have paradigm shifts". Many games have paradigm shifts that are not incremental, so it's just an indicator of incrementalness. Additionally, it can become quite hard to determine how large of a shift is a "paradigm" shift. Take, for example, any game with a skill tree. In some games, each skill node might have a large impact on how you play with the game, and qualify as a paradigm shift for some players. In other games, each skill node might just be a small percentage modifier on some stat that doesn't really impact much more than a slight bias towards an already established mechanic that's newly buffed. Every single canon game may show that it's common amongst incremental games, but could just as easily indicate that they're common in games in general.

              High-Value Factors

              I won't take as long to discuss the high and low-value factors, as you've already seen most of them brought up earlier on this page. As a reminder, a game does NOT need all of these to be an incremental game, but these are factors that each indicate a strong possibility the game is an incremental, so having several of these means they probably are. These factors apply to most of the canon incremental games.

              "Pure UI" Display. Incrementals typically have a textual presentation of the game state - there isn't a visual representation of the entities within the game. The interface is closer to what would be just the UI of a game in another genre or the control panel of a plane. If there is a visual representation, the player is often still interacting with non-diegetic game elements.

              Reduced Consequences. Incrementals tend to have reduced repurcussions for misplaying. They very rarely have fail states, where often the largest consequence is simply not progressing - never losing progress.

              Optimization Problems. The predominant gameplay of incrementals is typically solving optimization problems, from deciding which purchase to save up for to reasoning and deciding between different mutually exclusive options the game presents.

              Resource Management. Incrementals tend to have a lot of resources within the game to keep track of.

              Low-Value Factors

              These are low-value factors, meaning they aren't as strongly correlated with incremental games. Incremental games may have none of these, and non-incrementals may have several of these - if a game only has low-value factors, they're probably not an incremental.

              Fast Numeric Growth. Numbers in incremental games tend to grow faster than in other genres. There are more instances of superlinear growth. The larger the numbers get, the stronger of a signal this factor is.

              Automation. As an incremental game progresses, the player often no longer has to deal with earlier mechanics, by having them either happen automatically or otherwise be replaced with an alternative that requires less player interaction.

              Goal-Oriented. Incrementals are often heavily reliant on extrinsic motivation to guide the player. Typically this is through some sort of in-game goal to work towards, such as a certain amount of a resource being required to unlock or purchase something new.

              Waiting is a Mechanic. In incremental games, the player may come across times where there is no action they can take, and the game will progress automatically instead. The player must wait for some amount of this automatic progress to occur before they can resume interaction with the game.

              Are Roguelites Incrementals?

              Having made our variation of the Berlin Interpretation for incremental games, we can compare it to the Berlin Interpretation to determine if there's enough overlap that any game that "passes" the Berlin Interpretation would also pass the incremental variant. That is to say, whether any roguelite would also be considered an incremental game.

              The meta-progression of an incremental game could arguably be considered a paradigm shift, and certainly adds some resource management. Goal-oriented would probably also apply. I think anything other than those would be a stretch, and in my opinion that just isn't enough to qualify. To be totally honest, I was never expecting to conclude otherwise though 😉

              Sub-Genres

              There are some trends in incremental games that go beyond just being a commonly used mechanic, such that they deeply affect the rest of the game design. These trends can be used to determine sub-genres within the incremental games umbrella:

              Loops games are a sub-genre defined by having a core mechanic related to a loop, where the player is deciding the actions taken per loop. Notable examples include Idle Loops, Stuck in Time, Cavernous II, and Increlution. You may also argue Groundhog Life and Progress Knight fall into this sub-genre.

              ITRTG-like games are a sub-genre defined by having a core mechanic based on clearing increasingly difficult battles and often tend to have a lot of different mechanics to become progressively stronger. Notable examples include Idling to Rule the Gods, NGU Idle, and Wizard and Minion Idle.

              Polynomial Growth games are a sub-genre defined by having a core mechanic related to a higher degree polynomial. Notable examples include the base layer of Antimatter Dimensions and Swarm Simulator.

              Upgrades Games is a category popular on flash games websites that featured games focused on buying upgrades that would allow you to attain more currency in some sort of minigame that would earn you more money to buy more upgrades, which I'd argue now belong under the fold of incremental games. Notable examples include the Learn to Fly series and Upgrade Complete.

              Cultivation RPGs are a genre of games, books, and anime popular in China that center around being in a fantasy world with characters getting stronger over time. While few of them get translated into English, a fan of incremental games may find the available games interesting.

              + \ No newline at end of file diff --git a/hashmap.json b/hashmap.json index bce6d306..002a110b 100644 --- a/hashmap.json +++ b/hashmap.json @@ -1 +1 @@ -{"public_gamedevtree_docs_custom-tab-layouts.md":"oOQumDgW","garden_advent-incremental_index.md":"CbzLDkso","garden_artificial-intelligence_index.md":"BevJsmT8","garden_atproto_index.md":"DS2dsksJ","garden_babble-buds_index.md":"D-MhN_8s","public_gamedevtree_2.0-format-changes.md":"DWZ5VgEH","guide-to-incrementals_ludology_content_index.md":"CIJoP_r0","garden_cinny_index.md":"Ch9QVly5","garden_profectus_index.md":"BmLQh2zb","guide-to-incrementals_index.md":"BcJvnxZ-","garden_this-knowledge-hub_index.md":"BeloVRmr","public_gamedevtree_changelog.md":"BFpQdU6f","garden_webrings_index.md":"D5KgyhV9","public_gamedevtree_docs_!general-info.md":"B4kcWpV-","garden_vitepress_index.md":"BwIztJxS","garden_wanderstop_index.md":"-GaIeUe_","garden_kronos_index.md":"DWmqXBaE","garden_planar-pioneers_index.md":"CrWQHny8","garden_the-indieweb_amplification_index.md":"CdpguDI2","guide-to-incrementals_ludology_appeal-developers_index.md":"CIgpgpNd","garden_decentralized_index.md":"BThYPn4k","public_gamedevtree_docs_basic-layer-breakdown.md":"DG6Q9mdT","index.md":"BanIo7zz","garden_dice-armor_index.md":"CjnpEGDY","public_gamedevtree_docs_buyables.md":"BWSB6neR","garden_video-game-monetization_index.md":"ClgnBtf0","garden_the-beginner-s-guide_index.md":"Bh4pwbi0","garden_command-palettes_index.md":"Br8Wqkvv","public_gamedevtree_docs_achievements.md":"C6gZOG4E","public_gamedevtree_docs_upgrades.md":"DuL26i8s","public_kronos_readme.md":"DR8w07T9","public_kronos_docs_!general-info.md":"Dr4UpP6q","garden_synapse_index.md":"BkDI3Nqf","public_kronos_old things_2.0-format-changes.md":"DAyzd7AX","public_kronos_changelog.md":"_RxA7rHJ","public_kronos_docs_layer-features.md":"DJjusT4t","public_kronos_docs_updating-tmt.md":"yvj4vsSM","public_kronos_docs_main-mod-info.md":"DYKIKxsS","public_kronos_docs_milestones.md":"Ce7tGr8C","public_kronos_docs_particles.md":"CgdBAXsD","public_lit_old things_2.0-format-changes.md":"aA7GK9Ns","public_lit_changelog.md":"D7wPxHZ1","public_kronos_docs_achievements.md":"BQdSRHBr","public_kronos_docs_upgrades.md":"BY_E6naZ","public_kronos_docs_subtabs-and-microtabs.md":"BSv4TpNt","public_lit_readme.md":"Dp_XDgLr","public_lit_docs_buyables.md":"Cr6AwZWn","public_lit_docs_!general-info.md":"DwyPmy7N","public_lit_docs_custom-tab-layouts.md":"CHYKKeeX","public_lit_docs_achievements.md":"DaBdzZ0g","public_lit_docs_bars.md":"CnS5IMvm","public_lit_docs_basic-layer-breakdown.md":"B_DwLl-5","public_lit_docs_clickables.md":"DQD4wzqI","garden_activitypub_index.md":"DLZvHPXj","public_kronos_docs_getting-started.md":"qT4YQHFa","about_index.md":"p-omr8fP","public_gamedevtree_docs_clickables.md":"DlF0g6fO","public_kronos_docs_custom-tab-layouts.md":"B34ACqtp","public_kronos_docs_challenges.md":"C8-cN764","public_kronos_docs_clickables.md":"Dpdgv1J5","public_kronos_docs_infoboxes.md":"Bc-XXHMa","public_kronos_docs_basic-layer-breakdown.md":"DHJLymK0","public_lit_docs_getting-started.md":"BoU9JbJY","public_lit_docs_challenges.md":"BXbZcSAe","public_lit_docs_layer-features.md":"FrysJ_Sk","changelog_index.md":"BVGEmP78","public_kronos_docs_grids.md":"dbyCMqJD","public_lit_docs_subtabs-and-microtabs.md":"DkrjReOt","public_lit_docs_updating-tmt.md":"CjXsxPz8","garden_open-source_index.md":"D7bOPf6D","garden_chronological_index.md":"Du31gSeZ","garden_premium-currency_index.md":"DnHfK06C","garden_the-indieweb_signature-blocks_index.md":"ZTvTccur","garden_guide-to-incrementals_defining-the-genre_index.md":"CnpSquU9","public_lit_docs_infoboxes.md":"71lto7Te","public_gamedevtree_readme.md":"B6IoVQ-I","public_lit_docs_milestones.md":"CKbDaByO","garden_capture-the-citadel_index.md":"B81Zl3jT","garden_chat-glue_index.md":"DrB0BEZa","public_gamedevtree_docs_bars.md":"1NZ3Fz1N","garden_weird_index.md":"CVpFc8I8","garden_life-is-strange_index.md":"Cvu7AqjX","garden_federated-identity_index.md":"Czr5VTIi","garden_logseq_index.md":"CGpHVto-","garden_guide-to-incrementals_appeal-to-players_index.md":"tNU97J-Z","garden_guide-to-incrementals_index.md":"DEblpv1O","garden_incremental-social_index.md":"B1XcCjeN","garden_matrix_index.md":"BuCnqAik","garden_guide-to-incrementals_what-is-content_index.md":"BdP15SmB","garden_freeform-vs-chronological-dichotomy_index.md":"D64deYnh","garden_digital-gardens_index.md":"BTOMV_DV","garden_my-projects_index.md":"BTL4J3HO","public_lit_docs_upgrades.md":"DCCBwvKJ","public_lit_docs_trees-and-tree-customization.md":"D-rEc1nB","garden_my-personal-website_index.md":"B7pFBXsd","garden_forgejo_index.md":"DjFZ67LJ","public_lit_docs_main-mod-info.md":"B2Wd3G2L","garden_social-media_index.md":"DYnTYuzx","garden_fediverse_index.md":"BoF29t1o","garden_v-ecs_index.md":"DYGQYRv1","garden_the-small-web_index.md":"C-NKW4Ch","public_gamedevtree_docs_getting-started.md":"DZiPQZAv","garden_game-dev-tree_index.md":"DYS7_xxo","garden_commune_index.md":"VBDo-SJ7","public_gamedevtree_docs_infoboxes.md":"BtrpL17l","garden_guide-to-incrementals_navigating-criticism_index.md":"CvIMd3Io","public_gamedevtree_docs_main-mod-info.md":"DGfpmFPw","garden_nostr_index.md":"DuRG5Z1P","public_gamedevtree_docs_layer-features.md":"DAMp8TY6","guide-to-incrementals_design_criticism_index.md":"B84_a_FO","garden_mtx_index.md":"BrTCy3ds","public_gamedevtree_docs_milestones.md":"C9u7zdbl","garden_the-cozy-web_index.md":"Dphn0Ga1","public_gamedevtree_docs_challenges.md":"DJU5H6Rk","garden_guide-to-incrementals_appeal-to-developers_index.md":"C9QEK0j6","garden_pre-order-bonuses_index.md":"CCGmxPHN","garden_ivy-road_index.md":"DEFjS1hP","garden_garden-rss_index.md":"FzV6pCp6","public_gamedevtree_docs_updating-tmt.md":"B1_CRXZy","garden_davey-wreden_index.md":"Bxj_Btrg","public_kronos_docs_bars.md":"DLIjHzcw","guide-to-incrementals_ludology_definition_index.md":"CmTVBDoy","guide-to-incrementals_ludology_appeal-gamers_index.md":"KF6NxDNl","public_gamedevtree_docs_subtabs-and-microtabs.md":"BUkbEA-K","garden_fedi-v2_index.md":"BJxh2Je6","garden_opti-speech_index.md":"VQVokYBw","now_index.md":"CdesjOn4","garden_freeform_index.md":"Cm941aMp","public_kronos_docs_buyables.md":"CZOwuPEI","public_kronos_docs_trees-and-tree-customization.md":"C6vJ-bgs","garden_mbin_index.md":"CsZu6UCI"} +{"garden_matrix_index.md":"DkFciSU3","garden_atproto_index.md":"DGb10zg_","public_gamedevtree_docs_achievements.md":"jhkjuzaR","public_gamedevtree_docs_bars.md":"CBtj98pG","public_gamedevtree_docs_challenges.md":"cvYq35wY","garden_mtx_index.md":"BwWrNpeS","public_gamedevtree_docs_clickables.md":"CwLsimiU","public_gamedevtree_docs_basic-layer-breakdown.md":"Ykqytlzk","guide-to-incrementals_ludology_appeal-developers_index.md":"BdUXpm07","garden_cinny_index.md":"ZTWxRUBw","garden_capture-the-citadel_index.md":"BSzKEtwa","garden_the-beginner-s-guide_index.md":"CaCS8ERA","garden_logseq_index.md":"BtOsUfE8","about_index.md":"DNEsxkhw","garden_the-indieweb_signature-blocks_index.md":"Cb_LJurF","garden_babble-buds_index.md":"Cdl6QJzR","guide-to-incrementals_ludology_appeal-gamers_index.md":"DIzXBzVM","garden_life-is-strange_index.md":"DZxs1spf","garden_pre-order-bonuses_index.md":"shTakEi9","garden_the-indieweb_amplification_index.md":"C7orSKJb","garden_fediverse_index.md":"CexXroKb","garden_kronos_index.md":"Cu7rVJ0m","garden_davey-wreden_index.md":"0Vgk25Ik","garden_mbin_index.md":"DL7RJU0g","public_kronos_docs_challenges.md":"DvQ_P73q","now_index.md":"BMPjLpxb","public_lit_docs_upgrades.md":"D1Ns9VTR","public_gamedevtree_changelog.md":"Bp63oq83","public_gamedevtree_docs_layer-features.md":"I54r8Buk","public_kronos_docs_particles.md":"a4-BPTpH","public_gamedevtree_docs_main-mod-info.md":"SBsEn9C7","public_lit_docs_basic-layer-breakdown.md":"DKkhjhoJ","garden_vitepress_index.md":"Jhyyyy8E","garden_forgejo_index.md":"-Mf7Kiyr","guide-to-incrementals_ludology_content_index.md":"BFqVGpC-","garden_wanderstop_index.md":"DAn8eZ1Y","public_lit_docs_achievements.md":"D0gRoIWt","public_kronos_docs_main-mod-info.md":"TWb3xDwG","public_lit_docs_bars.md":"DFEFprv8","public_gamedevtree_docs_infoboxes.md":"B4DD8BvC","garden_advent-incremental_index.md":"DJsWBIkL","public_kronos_docs_basic-layer-breakdown.md":"BZhX1dEF","garden_command-palettes_index.md":"BrnpBbTf","public_kronos_docs_custom-tab-layouts.md":"D4DCXZo7","public_lit_docs_buyables.md":"DrqS8H2k","public_kronos_docs_layer-features.md":"C1uOzCZ-","garden_guide-to-incrementals_navigating-criticism_index.md":"Cma7NB5L","garden_activitypub_index.md":"CWpyy_YP","garden_freeform-vs-chronological-dichotomy_index.md":"PROF6kb-","guide-to-incrementals_index.md":"D0no5q0d","public_gamedevtree_2.0-format-changes.md":"DRd3bhvM","public_kronos_docs_buyables.md":"0zoux8fQ","public_kronos_docs_clickables.md":"C1ENZgWW","public_lit_old things_2.0-format-changes.md":"BwaKJMKt","public_kronos_docs_upgrades.md":"D1pH3BI1","garden_v-ecs_index.md":"Eos2Bywd","garden_artificial-intelligence_index.md":"B-XBqRL_","garden_synapse_index.md":"BvwgQk4N","garden_nostr_index.md":"DQgV1bMu","garden_guide-to-incrementals_defining-the-genre_index.md":"DwYrHYrF","garden_planar-pioneers_index.md":"Bkbkl8EX","garden_incremental-social_index.md":"CsX_i8Lw","garden_freeform_index.md":"BGHRpas3","garden_profectus_index.md":"upNDNXA9","garden_social-media_index.md":"BdEPqp0F","garden_opti-speech_index.md":"CRwm6q2W","garden_chat-glue_index.md":"BybR6u1O","garden_guide-to-incrementals_index.md":"BQydin-1","garden_decentralized_index.md":"DYgiFscC","garden_federated-identity_index.md":"-RBu4BIs","garden_chronological_index.md":"CwbET-Cb","garden_video-game-monetization_index.md":"CF0Gozbk","garden_guide-to-incrementals_appeal-to-developers_index.md":"BoP7bn3q","guide-to-incrementals_ludology_definition_index.md":"NOaZSuDh","garden_premium-currency_index.md":"C5KciJ55","garden_ivy-road_index.md":"DcoTLA7N","garden_commune_index.md":"V0TqobbD","garden_the-small-web_index.md":"BXEnXP2C","public_lit_docs_!general-info.md":"D2rjMfl1","public_gamedevtree_docs_buyables.md":"C7aL_4eK","public_kronos_docs_bars.md":"DU3nCdnU","garden_this-knowledge-hub_index.md":"BDMSkEmc","public_lit_docs_clickables.md":"CoIWXGHw","public_lit_docs_challenges.md":"DtmSP6zf","guide-to-incrementals_design_criticism_index.md":"BSUq6GVs","garden_guide-to-incrementals_appeal-to-players_index.md":"CXnADb0-","garden_my-personal-website_index.md":"CGVQsQif","public_lit_docs_custom-tab-layouts.md":"C-TlZHYA","public_gamedevtree_docs_getting-started.md":"CyNrXhyL","garden_my-projects_index.md":"pIi7fe_T","public_lit_docs_getting-started.md":"BxRLZ8_n","garden_weird_index.md":"H-M1_Y4d","changelog_index.md":"DFC25qVi","public_gamedevtree_docs_subtabs-and-microtabs.md":"BhlicLTn","public_gamedevtree_docs_updating-tmt.md":"Clk0TMnI","garden_open-source_index.md":"D0998lGJ","public_gamedevtree_docs_upgrades.md":"BspSzPzA","public_kronos_docs_updating-tmt.md":"BxVzngxM","public_kronos_old things_2.0-format-changes.md":"BM0FXptY","public_lit_docs_main-mod-info.md":"CcRWcMdS","public_kronos_readme.md":"zcQPLTsl","public_kronos_docs_milestones.md":"BqiEbWx4","public_kronos_changelog.md":"BB6U1JML","public_kronos_docs_!general-info.md":"jKiOCSlr","public_lit_docs_trees-and-tree-customization.md":"C8iASWgy","public_kronos_docs_achievements.md":"CWA5xmwG","public_lit_docs_updating-tmt.md":"C3AjdOjF","garden_dice-armor_index.md":"BE5P-PMF","garden_garden-rss_index.md":"DGe30PZV","public_gamedevtree_docs_custom-tab-layouts.md":"DIYFlfWc","garden_the-cozy-web_index.md":"BlzW7dqM","public_lit_docs_infoboxes.md":"C0nPRfky","garden_digital-gardens_index.md":"CWPuJsJg","public_lit_docs_milestones.md":"CGwN80sv","public_lit_docs_subtabs-and-microtabs.md":"BQEflp-r","index.md":"DTY4Urhb","public_lit_readme.md":"84-k6GVT","public_lit_docs_layer-features.md":"DF81fjyw","garden_fedi-v2_index.md":"BPYmNsKX","garden_webrings_index.md":"CopTyfrh","public_kronos_docs_getting-started.md":"N-haPVCK","public_gamedevtree_docs_!general-info.md":"DK2xr3yI","public_kronos_docs_grids.md":"DGDenQsi","garden_game-dev-tree_index.md":"NAi3ceZ1","garden_guide-to-incrementals_what-is-content_index.md":"DXGnOHrD","public_kronos_docs_infoboxes.md":"BXXHzXvY","public_kronos_docs_subtabs-and-microtabs.md":"B3i34UtK","public_kronos_docs_trees-and-tree-customization.md":"bHBppIK5","public_lit_changelog.md":"BAnHXxRw","public_gamedevtree_docs_milestones.md":"Idyk5tE3","public_gamedevtree_readme.md":"DVS2_5Qr"} diff --git a/index.html b/index.html index 6971a6e7..bb02048f 100644 --- a/index.html +++ b/index.html @@ -6,13 +6,13 @@ Hello! | The Paper Pilot - + - + - - - + + + @@ -34,8 +34,8 @@ -
              Skip to content

              Hello!

              I'm Anthony, or The Paper Pilot, and welcome to my digital garden!

              This is a public website collecting all my (public) thoughts and projects all in one place. There are a lot of pages here, that link to each other wiki-style. I suggest starting your browsing with one of the recommended pages that most closely align with your interests 😃.

              - +
              Skip to content

              Hello!

              I'm Anthony, or The Paper Pilot, and welcome to my digital garden!

              This is a public website collecting all my (public) thoughts and projects all in one place. There are a lot of pages here, that link to each other wiki-style. I suggest starting your browsing with one of the recommended pages that most closely align with your interests 😃.

              + \ No newline at end of file diff --git a/now/index.html b/now/index.html index 8de7faa5..c6a21c1d 100644 --- a/now/index.html +++ b/now/index.html @@ -6,14 +6,14 @@ /now | The Paper Pilot - + - + - - + + - + @@ -35,10 +35,10 @@ -
              Skip to content

              /now

              181 words, ~1 minute read. Planted +

              Skip to content

              /now

              181 words, ~1 minute read. Planted . Last tended to -.


              This "now page" offers a big picture glimpse into what I’m focused on at this point in my life. What is a now page?

              IndieWeb

              I've been learning a lot about The Small Web (or the various other names it goes by). I've been working on this website and implementing the various IndieWeb building blocks

              I'm also working on a proposal for adding The IndieWeb/Signature Blocks to your notes

              Commune

              While I'm not contributing to the project directly, I'm following along and participating with the discussions and designs of Commune.

              I'm working on a mockup of what an app could look like that treats incoming messages, emails, etc. differently based on user defined rules, with a focus on moving them into personal or communal digital gardens.

              Incremental Social

              I'm running and improving the social media site Incremental Social, along with CardboardEmpress.

              Chromatic Lattice

              I'm working on a multiplayer incremental game. That's all that's known publicly for now 😜.

              Kronos

              I'm working on a long single player narratively driven incremental game. This is a very long-term project.

              - +.


              This "now page" offers a big picture glimpse into what I’m focused on at this point in my life. What is a now page?

              IndieWeb

              I've been learning a lot about The Small Web (or the various other names it goes by). I've been working on this website and implementing the various IndieWeb building blocks

              I'm also working on a proposal for adding The IndieWeb/Signature Blocks to your notes

              Commune

              While I'm not contributing to the project directly, I'm following along and participating with the discussions and designs of Commune.

              I'm working on a mockup of what an app could look like that treats incoming messages, emails, etc. differently based on user defined rules, with a focus on moving them into personal or communal digital gardens.

              Incremental Social

              I'm running and improving the social media site Incremental Social, along with CardboardEmpress.

              Chromatic Lattice

              I'm working on a multiplayer incremental game. That's all that's known publicly for now 😜.

              Kronos

              I'm working on a long single player narratively driven incremental game. This is a very long-term project.

              + \ No newline at end of file diff --git a/public/gamedevtree/2.0-format-changes.html b/public/gamedevtree/2.0-format-changes.html index e422641f..a200ffd9 100644 --- a/public/gamedevtree/2.0-format-changes.html +++ b/public/gamedevtree/2.0-format-changes.html @@ -6,13 +6,13 @@ 2.0 format changes | The Paper Pilot - + - + - - - + + + @@ -34,8 +34,8 @@ -
              Skip to content

              2.0 format changes

              • Temp format is changed from temp.something[layer] to temp[layer].something, for consistency
              • Challenges are now saved as an object with the amount of completions in each spot. (This will break saves.)
              • effectDisplay in Challenges and Upgrades no longer takes an argument, and neither does effect for Buyables
              • Buyable cost can take an argument for amount of buyables, but it needs to function if no argument is supplied (it should do the cost for the next purchase).
              • Generation of Points now happens in the main game loop (not in a layer update function), enabled by canGenPoints in game.js.
              • Changed fullLayerReset to layerDataReset, which takes an array of names of values to keep

              In addition, many names were changed, mostly expanding abbreviations:

              All instances of:

              • chall -> challenge
              • unl -> unlocked
              • upg -> upgrade (besides CSS)
              • amt -> amount
              • desc -> description
              • resCeil -> roundUpCost
              • order -> unlockOrder
              • incr_order -> increaseUnlockOrder

              Challenges:

              • desc -> challengeDescription
              • reward -> rewardDescription
              • effect -> rewardEffect
              • effectDisplay -> rewardDisplay
              • active -> challengeActive
              - +
              Skip to content

              2.0 format changes

              • Temp format is changed from temp.something[layer] to temp[layer].something, for consistency
              • Challenges are now saved as an object with the amount of completions in each spot. (This will break saves.)
              • effectDisplay in Challenges and Upgrades no longer takes an argument, and neither does effect for Buyables
              • Buyable cost can take an argument for amount of buyables, but it needs to function if no argument is supplied (it should do the cost for the next purchase).
              • Generation of Points now happens in the main game loop (not in a layer update function), enabled by canGenPoints in game.js.
              • Changed fullLayerReset to layerDataReset, which takes an array of names of values to keep

              In addition, many names were changed, mostly expanding abbreviations:

              All instances of:

              • chall -> challenge
              • unl -> unlocked
              • upg -> upgrade (besides CSS)
              • amt -> amount
              • desc -> description
              • resCeil -> roundUpCost
              • order -> unlockOrder
              • incr_order -> increaseUnlockOrder

              Challenges:

              • desc -> challengeDescription
              • reward -> rewardDescription
              • effect -> rewardEffect
              • effectDisplay -> rewardDisplay
              • active -> challengeActive
              + \ No newline at end of file diff --git a/public/gamedevtree/README.html b/public/gamedevtree/README.html index 10002863..6c15ff78 100644 --- a/public/gamedevtree/README.html +++ b/public/gamedevtree/README.html @@ -6,13 +6,13 @@ The-Modding-Tree | The Paper Pilot - + - + - - - + + + @@ -34,8 +34,8 @@ -
              Skip to content

              The-Modding-Tree

              A modified version of The Prestige Tree that is much easier to mod. It still requires programming knowledge, but it's mostly pretty easy things and copy/pasting.

              Look here for a tutorial on getting started with modding with TMT

              You can look in the documentation for more information on how it all works, or look at the code in layers.js to see what it all looks like.

              - +
              Skip to content

              The-Modding-Tree

              A modified version of The Prestige Tree that is much easier to mod. It still requires programming knowledge, but it's mostly pretty easy things and copy/pasting.

              Look here for a tutorial on getting started with modding with TMT

              You can look in the documentation for more information on how it all works, or look at the code in layers.js to see what it all looks like.

              + \ No newline at end of file diff --git a/public/gamedevtree/changelog.html b/public/gamedevtree/changelog.html index 5068978f..12679945 100644 --- a/public/gamedevtree/changelog.html +++ b/public/gamedevtree/changelog.html @@ -6,13 +6,13 @@ The Game Dev Tree changelog: | The Paper Pilot - + - + - - - + + + @@ -34,8 +34,8 @@ -
              Skip to content

              The Game Dev Tree changelog:

              v1.0.4 Version Bump [rebalanced,debuggedx3] - 2020-11-09

              • Fixed refactorings 2, 3, and 4 not actually affecting productivity

              v1.0.3 Version Bump [rebalanced,debuggedx2] - 2020-11-08

              • Fixed API milestone 4 not working

              v1.0.2 Version Bump [rebalanced,debugged] - 2020-11-08

              • Fixed tree lines being hidden after hitting "keepGoing" in the victory screen

              v1.0.1 Version Bump [rebalanced] - 2020-11-08

              • Buffed several TAs

              v1.0 Version Bump - 2020-11-08

              • Finished row 4
              • Added colored text to lore
              • Fixed some visual bugs with milestones
              • Probably other stuff lol its been a week

              v0.2.3 Stylish - 2020-10-30

              • Re-styled basically everything
              • Added favicon
              • Added header bar
              • Added changelog

              v0.2.2 Row 3 - 2020-10-22

              • Removed debug statement
              • Moved milestones in F layer beneath the buyables

              v0.2.1 Row 3 - 2020-10-21

              • Fixed layers hiding
              • Fixed typos/minor issues
              • Fixed S layer being highlighted before you can unlock the layer

              v0.2 Row 3 - 2020-10-21

              • Implemented row 3

              v0.1.1 Cash Influx [rebalanced] - 2020-10-19

              • Fixed notification issue
              • Rebalanced to make early game faster and late game slower
              • Fixed other minor issues

              v0.1 Cash Influx - 2020-10-19

              • Implemented row 2

              v0.0 Initial Commit - 2020-10-18

              • Implemented row 1
              - +
              Skip to content

              The Game Dev Tree changelog:

              v1.0.4 Version Bump [rebalanced,debuggedx3] - 2020-11-09

              • Fixed refactorings 2, 3, and 4 not actually affecting productivity

              v1.0.3 Version Bump [rebalanced,debuggedx2] - 2020-11-08

              • Fixed API milestone 4 not working

              v1.0.2 Version Bump [rebalanced,debugged] - 2020-11-08

              • Fixed tree lines being hidden after hitting "keepGoing" in the victory screen

              v1.0.1 Version Bump [rebalanced] - 2020-11-08

              • Buffed several TAs

              v1.0 Version Bump - 2020-11-08

              • Finished row 4
              • Added colored text to lore
              • Fixed some visual bugs with milestones
              • Probably other stuff lol its been a week

              v0.2.3 Stylish - 2020-10-30

              • Re-styled basically everything
              • Added favicon
              • Added header bar
              • Added changelog

              v0.2.2 Row 3 - 2020-10-22

              • Removed debug statement
              • Moved milestones in F layer beneath the buyables

              v0.2.1 Row 3 - 2020-10-21

              • Fixed layers hiding
              • Fixed typos/minor issues
              • Fixed S layer being highlighted before you can unlock the layer

              v0.2 Row 3 - 2020-10-21

              • Implemented row 3

              v0.1.1 Cash Influx [rebalanced] - 2020-10-19

              • Fixed notification issue
              • Rebalanced to make early game faster and late game slower
              • Fixed other minor issues

              v0.1 Cash Influx - 2020-10-19

              • Implemented row 2

              v0.0 Initial Commit - 2020-10-18

              • Implemented row 1
              + \ No newline at end of file diff --git a/public/gamedevtree/docs/!general-info.html b/public/gamedevtree/docs/!general-info.html index 8d97a9be..23265df0 100644 --- a/public/gamedevtree/docs/!general-info.html +++ b/public/gamedevtree/docs/!general-info.html @@ -6,13 +6,13 @@ The-Modding-Tree | The Paper Pilot - + - + - - - + + + @@ -34,8 +34,8 @@ -
              Skip to content

              The-Modding-Tree

              The main way to add content is through creating layers. You can either add a layer directly in the layers object in layersSupportjs, or declare it in another file and then do "addLayer(layername, layerdata)" (good for breaking things up into smaller files). The existing layers are just examples and can be freely deleted. You can also use them as references and a base for your own layers.

              The first thing you need to do is to edit the modInfo at the top of game.js to set your modID (a string). A unique modId will prevent your mod's saves from conflicting with other mods.

              Most of the time, you won't need to dive deep into the code to create things, but you still can if you really want to.

              The Modding Tree uses break_eternity.js to store large values. This means that many numbers are Decimal objects, and must be treated differently. For example, you have to use new Decimal(x) to create a Decimal value instead of a plain number, and perform operations on them by calling functions. e.g, instead of x = x + y, use x = x.add(y).

              Almost all values can be either a constant value, or a dynamic value. Dynamic values are defined by putting a function that returns what the value should be at any given time.

              All display text can be basic HTML instead (But you can't use most Vue features there).

              Table of Contents:

              General:

              • Getting Started: Getting your own copy of the code set up with Github Desktop.
              • Main mod info: How to set up general things for your mod in mod.js.
              • Basic layer breakdown: Breaking down the components of a layer with minimal features.
              • Layer features: Explanations of all of the different properties that you can give a layer.
              • Custom Tab Layouts: An optional way to give your tabs a different layout. You can even create entirely new components to use.
              • Updating TMT: Using Github Desktop to update your mod's version of TMT.

              Common components

              • Upgrades: How to create upgrades for a layer.
              • Milestones: How to create milestones for a layer.
              • Buyables: Create rebuyable upgrades for your layer (with the option to make them respec-able). Can be used to make Enhancers or Space Buildings.
              • Clickables: A more generalized variant of buyables, for any kind of thing that is sometimes clickable. Between these and Buyables, you can do just about anything.

              Other components

              • Challenges: How to create challenges for a layer.
              • Bars: Display some information as a progress bar, gague, or similar. They are highly customizable, and can be horizontal and vertical as well.
              • Subtabs and Microtabs: Create subtabs for your tabs, as well as "microtab" components that you can put inside the tabs.
              • Achievements: How to create achievements for a layer (or for the whole game).
              • Infoboxes: Boxes containing text that can be shown or hidden.
              - +
              Skip to content

              The-Modding-Tree

              The main way to add content is through creating layers. You can either add a layer directly in the layers object in layersSupportjs, or declare it in another file and then do "addLayer(layername, layerdata)" (good for breaking things up into smaller files). The existing layers are just examples and can be freely deleted. You can also use them as references and a base for your own layers.

              The first thing you need to do is to edit the modInfo at the top of game.js to set your modID (a string). A unique modId will prevent your mod's saves from conflicting with other mods.

              Most of the time, you won't need to dive deep into the code to create things, but you still can if you really want to.

              The Modding Tree uses break_eternity.js to store large values. This means that many numbers are Decimal objects, and must be treated differently. For example, you have to use new Decimal(x) to create a Decimal value instead of a plain number, and perform operations on them by calling functions. e.g, instead of x = x + y, use x = x.add(y).

              Almost all values can be either a constant value, or a dynamic value. Dynamic values are defined by putting a function that returns what the value should be at any given time.

              All display text can be basic HTML instead (But you can't use most Vue features there).

              Table of Contents:

              General:

              • Getting Started: Getting your own copy of the code set up with Github Desktop.
              • Main mod info: How to set up general things for your mod in mod.js.
              • Basic layer breakdown: Breaking down the components of a layer with minimal features.
              • Layer features: Explanations of all of the different properties that you can give a layer.
              • Custom Tab Layouts: An optional way to give your tabs a different layout. You can even create entirely new components to use.
              • Updating TMT: Using Github Desktop to update your mod's version of TMT.

              Common components

              • Upgrades: How to create upgrades for a layer.
              • Milestones: How to create milestones for a layer.
              • Buyables: Create rebuyable upgrades for your layer (with the option to make them respec-able). Can be used to make Enhancers or Space Buildings.
              • Clickables: A more generalized variant of buyables, for any kind of thing that is sometimes clickable. Between these and Buyables, you can do just about anything.

              Other components

              • Challenges: How to create challenges for a layer.
              • Bars: Display some information as a progress bar, gague, or similar. They are highly customizable, and can be horizontal and vertical as well.
              • Subtabs and Microtabs: Create subtabs for your tabs, as well as "microtab" components that you can put inside the tabs.
              • Achievements: How to create achievements for a layer (or for the whole game).
              • Infoboxes: Boxes containing text that can be shown or hidden.
              + \ No newline at end of file diff --git a/public/gamedevtree/docs/achievements.html b/public/gamedevtree/docs/achievements.html index 41286eb3..5460f83c 100644 --- a/public/gamedevtree/docs/achievements.html +++ b/public/gamedevtree/docs/achievements.html @@ -6,13 +6,13 @@ Achievements | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
              Skip to content

              Achievements

              Achievements are awarded to the player when they meet a certain goal, and give some benefit. Currently, they are pretty basic, but additional features will be added later to help.

              You can make global achievements by putting them in a side layer (make its row "side" instead of a number)

              Useful functions for dealing with achievements and implementing their effects:

              • hasAchievement(layer, id): determine if the player has the Achievement
              • achievementEffect(layer, id): Returns the current effects of the achievement, if any

              Achievements should be formatted like this:

              js
                  achievements: {
              +    
              Skip to content

              Achievements

              Achievements are awarded to the player when they meet a certain goal, and give some benefit. Currently, they are pretty basic, but additional features will be added later to help.

              You can make global achievements by putting them in a side layer (make its row "side" instead of a number)

              Useful functions for dealing with achievements and implementing their effects:

              • hasAchievement(layer, id): determine if the player has the Achievement
              • achievementEffect(layer, id): Returns the current effects of the achievement, if any

              Achievements should be formatted like this:

              js
                  achievements: {
                       rows: # of rows
                       cols: # of columns
                       11: {
              @@ -42,8 +42,8 @@
                           more features
                       }
                       etc
              -    }

              Each achievement should have an id where the first digit is the row and the second digit is the column. Individual achievement can have these features:

              • name: optional, displayed at the top of the achievement. The only visible text. It can also be a function that returns updating text. Can use basic HTML.

              • done(): A function returning a boolean to determine if the achievement should be awarded.

              • tooltip: Default tooltip for the achievement, appears when it is hovered over. Should convey the goal and any reward for completing the achievement. It can also be a function that returns updating text. Can use basic HTML.

              • effect(): optional, A function that calculates and returns the current values of any bonuses from the achievement. Can return a value or an object containing multiple values.

              • unlocked(): optional, A function returning a bool to determine if the achievement is visible or not. Default is unlocked.

              • onComplete() - optional, this function will be called when the achievement is completed.

              • style: Optional, Applies CSS to this achievement, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings)

              • layer: Assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar

              • id: Assigned automagically. It's the "key" which the achievement was stored under, for convenient access. The achievement in the example's id is 11.

              • goalTooltip: optional, depracated Appears when the achievement is hovered over and locked, overrides the basic tooltip. This is to display the goal (or a hint). It can also be a function that returns updating text. Can use basic HTML.

              • doneTooltip: optional, depracated Appears when the achievement is hovered over and completed, overrides the basic tooltip. This can display what the player achieved (the goal), and the rewards, if any. It can also be a function that returns updating text. Can use basic HTML.

              - + }

              Each achievement should have an id where the first digit is the row and the second digit is the column. Individual achievement can have these features:

              • name: optional, displayed at the top of the achievement. The only visible text. It can also be a function that returns updating text. Can use basic HTML.

              • done(): A function returning a boolean to determine if the achievement should be awarded.

              • tooltip: Default tooltip for the achievement, appears when it is hovered over. Should convey the goal and any reward for completing the achievement. It can also be a function that returns updating text. Can use basic HTML.

              • effect(): optional, A function that calculates and returns the current values of any bonuses from the achievement. Can return a value or an object containing multiple values.

              • unlocked(): optional, A function returning a bool to determine if the achievement is visible or not. Default is unlocked.

              • onComplete() - optional, this function will be called when the achievement is completed.

              • style: Optional, Applies CSS to this achievement, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings)

              • layer: Assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar

              • id: Assigned automagically. It's the "key" which the achievement was stored under, for convenient access. The achievement in the example's id is 11.

              • goalTooltip: optional, depracated Appears when the achievement is hovered over and locked, overrides the basic tooltip. This is to display the goal (or a hint). It can also be a function that returns updating text. Can use basic HTML.

              • doneTooltip: optional, depracated Appears when the achievement is hovered over and completed, overrides the basic tooltip. This can display what the player achieved (the goal), and the rewards, if any. It can also be a function that returns updating text. Can use basic HTML.

              + \ No newline at end of file diff --git a/public/gamedevtree/docs/bars.html b/public/gamedevtree/docs/bars.html index 21da0b6a..a017b839 100644 --- a/public/gamedevtree/docs/bars.html +++ b/public/gamedevtree/docs/bars.html @@ -6,13 +6,13 @@ Bars | The Paper Pilot - + - + - - - + + + @@ -34,14 +34,14 @@ -
              Skip to content

              Bars

              Bars let you display information in a more direct way. It can be a progress bar, health bar, capacity gague, or anything else.

              Bars are defined like other Big Features:

              js
                  bars: {
              +    
              Skip to content

              Bars

              Bars let you display information in a more direct way. It can be a progress bar, health bar, capacity gague, or anything else.

              Bars are defined like other Big Features:

              js
                  bars: {
                       bigBar: {
                           display() {return "Blah"},
                           etc
                       }
                       etc
              -    }

              Features:

              • direction: UP, DOWN, LEFT, or RIGHT (not Strings). Determines the direction that the bar is filled as it progresses. RIGHT means from left to right.

              • width, height: The size in pixels of the bar, but as Numbers (no "px" at the end)

              • progress(): A function that returns the portion of the bar that is filled, from "empty" at 0 to "full" at 1. (Nothing bad happens if the value goes out of these bounds, and it can be a number or Decimal).

              • display(): optional, A function that returns text to be displayed on top of the bar, can use HTML.

              • unlocked(): optional, A function returning a bool to determine if the bar is visible or not. Default is unlocked.

              • baseStyle, fillStyle, borderStyle, textStyle: Optional, Apply CSS to the unfilled portion, filled portion, border, and display text on the bar, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

              • layer: Assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar

              • id: Assigned automagically. It's the "key" which the bar was stored under, for convenient access. The bar in the example's id is "bigBar".

              - + }

              Features:

              • direction: UP, DOWN, LEFT, or RIGHT (not Strings). Determines the direction that the bar is filled as it progresses. RIGHT means from left to right.

              • width, height: The size in pixels of the bar, but as Numbers (no "px" at the end)

              • progress(): A function that returns the portion of the bar that is filled, from "empty" at 0 to "full" at 1. (Nothing bad happens if the value goes out of these bounds, and it can be a number or Decimal).

              • display(): optional, A function that returns text to be displayed on top of the bar, can use HTML.

              • unlocked(): optional, A function returning a bool to determine if the bar is visible or not. Default is unlocked.

              • baseStyle, fillStyle, borderStyle, textStyle: Optional, Apply CSS to the unfilled portion, filled portion, border, and display text on the bar, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

              • layer: Assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar

              • id: Assigned automagically. It's the "key" which the bar was stored under, for convenient access. The bar in the example's id is "bigBar".

              + \ No newline at end of file diff --git a/public/gamedevtree/docs/basic-layer-breakdown.html b/public/gamedevtree/docs/basic-layer-breakdown.html index d59a43d9..3ec9ff34 100644 --- a/public/gamedevtree/docs/basic-layer-breakdown.html +++ b/public/gamedevtree/docs/basic-layer-breakdown.html @@ -6,13 +6,13 @@ Basic layer breakdown | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
              Skip to content

              Basic layer breakdown

              This is a very minimal layer with minimal features. Most things will require additional features.

              js
                  p: {
              +    
              Skip to content

              Basic layer breakdown

              This is a very minimal layer with minimal features. Most things will require additional features.

              js
                  p: {
                       startData() { return {                  // startData is a function that returns default data for a layer. 
                           unlocked: false,                    // You can add more variables here to add them to your layer.
                           points: new Decimal(0),             // "points" is the internal name for the main resource of the layer.
              @@ -61,8 +61,8 @@
                       },
               
                       layerShown() {return true},             // Returns a bool for if this layer's node should be visible in the tree.
              -    },
              - + },
              + \ No newline at end of file diff --git a/public/gamedevtree/docs/buyables.html b/public/gamedevtree/docs/buyables.html index 21bf6727..02bc7a9e 100644 --- a/public/gamedevtree/docs/buyables.html +++ b/public/gamedevtree/docs/buyables.html @@ -6,13 +6,13 @@ Buyables | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
              Skip to content

              Buyables

              Buyables are usually things that can be bought multiple times with scaling costs. If you set a respec function, the player can reset the purchases to get their currency back.

              The amount of a buyable owned is a Decimal. You can get or set the amount of a buyable with getBuyableAmt(layer, id) and setBuyableAmt(layer, id, amt). You can use buyableEffect(layer, id) to get the current effects of a buyable.

              Buyables should be formatted like this:

              js
                  buyables: {
              +    
              Skip to content

              Buyables

              Buyables are usually things that can be bought multiple times with scaling costs. If you set a respec function, the player can reset the purchases to get their currency back.

              The amount of a buyable owned is a Decimal. You can get or set the amount of a buyable with getBuyableAmt(layer, id) and setBuyableAmt(layer, id, amt). You can use buyableEffect(layer, id) to get the current effects of a buyable.

              Buyables should be formatted like this:

              js
                  buyables: {
                       rows: # of rows
                       cols: # of columns
                       respec() {}, //**optional**, implement it to reset things and give back your currency.
              @@ -47,8 +47,8 @@
                           etc
                       }
                       etc
              -    }

              Features:

              • title: optional, displayed at the top in a larger font It can also be a function that returns updating text.

              • cost(): cost for buying the next buyable. Can have an optional argument "x" to calculate the cost of the x+1th object, but needs to use "current amount" as a default value for x. (x is a Decimal). Can return an object if there are multiple currencies.

              • effect(): optional, A function that calculates and returns the current values of bonuses of this buyable. Can return a value or an object containing multiple values.

              • display(): A function returning everything that should be displayed on the buyable after the title, likely including the description, amount bought, cost, and current effect. Can use basic HTML.

              • unlocked(): optional, A function returning a bool to determine if the buyable is visible or not. Default is unlocked.

              • canAfford(): A function returning a bool to determine if you can buy one of the buyables.

              • buy(): A function that implements buying one of the buyable, including spending the currency.

              • buyMax(): optional, A function that implements buying as many of the buyable as possible.

              • style: Optional, Applies CSS to this buyable, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings)

              • layer: Assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar

              • id: Assigned automagically. It's the "key" which the buyable was stored under, for convenient access. The buyable in the example's id is 11.

              Sell One/Sell All:

              Including a sellOne or sellAll function will cause an additional button to appear beneath the buyable. They are functionally identical, but "sell one" appears above "sell all". You can also use them for other things.

              sellOne/sellAll(): optional, Called when the button is pressed. The standard use would be to decrease/reset the amount of the buyable, And possibly return some currency to the player.

              canSellOne/canSellAll(): optional, booleans determining whether or not to show the buttons. If "canSellOne/All" is absent but "sellOne/All" is present, the appropriate button will always show.

              - + }

              Features:

              • title: optional, displayed at the top in a larger font It can also be a function that returns updating text.

              • cost(): cost for buying the next buyable. Can have an optional argument "x" to calculate the cost of the x+1th object, but needs to use "current amount" as a default value for x. (x is a Decimal). Can return an object if there are multiple currencies.

              • effect(): optional, A function that calculates and returns the current values of bonuses of this buyable. Can return a value or an object containing multiple values.

              • display(): A function returning everything that should be displayed on the buyable after the title, likely including the description, amount bought, cost, and current effect. Can use basic HTML.

              • unlocked(): optional, A function returning a bool to determine if the buyable is visible or not. Default is unlocked.

              • canAfford(): A function returning a bool to determine if you can buy one of the buyables.

              • buy(): A function that implements buying one of the buyable, including spending the currency.

              • buyMax(): optional, A function that implements buying as many of the buyable as possible.

              • style: Optional, Applies CSS to this buyable, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings)

              • layer: Assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar

              • id: Assigned automagically. It's the "key" which the buyable was stored under, for convenient access. The buyable in the example's id is 11.

              Sell One/Sell All:

              Including a sellOne or sellAll function will cause an additional button to appear beneath the buyable. They are functionally identical, but "sell one" appears above "sell all". You can also use them for other things.

              sellOne/sellAll(): optional, Called when the button is pressed. The standard use would be to decrease/reset the amount of the buyable, And possibly return some currency to the player.

              canSellOne/canSellAll(): optional, booleans determining whether or not to show the buttons. If "canSellOne/All" is absent but "sellOne/All" is present, the appropriate button will always show.

              + \ No newline at end of file diff --git a/public/gamedevtree/docs/challenges.html b/public/gamedevtree/docs/challenges.html index a0415059..dc58d9ae 100644 --- a/public/gamedevtree/docs/challenges.html +++ b/public/gamedevtree/docs/challenges.html @@ -6,13 +6,13 @@ Challenges | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
              Skip to content

              Challenges

              Useful functions for dealing with Challenges and implementing their effects:

              • inChallenge(layer, id): determine if the player is in a given challenge (or another challenge on the same layer that counts as this one)
              • hasChallenge(layer, id): determine if the player has completed the challenge
              • challengeCompletions(layer, id): determine how many times the player completed the challenge
              • challEffect(layer, id): Returns the current effects of the challenge, if any

              Challenges are stored in the following format:

              js
                  challenges: {
              +    
              Skip to content

              Challenges

              Useful functions for dealing with Challenges and implementing their effects:

              • inChallenge(layer, id): determine if the player is in a given challenge (or another challenge on the same layer that counts as this one)
              • hasChallenge(layer, id): determine if the player has completed the challenge
              • challengeCompletions(layer, id): determine how many times the player completed the challenge
              • challEffect(layer, id): Returns the current effects of the challenge, if any

              Challenges are stored in the following format:

              js
                  challenges: {
                       rows: # of rows
                       cols: # of columns
                       11: {
              @@ -42,8 +42,8 @@
                           etc
                       }
                       etc
              -    }

              Each challenge should have an id where the first digit is the row and the second digit is the column. Individual Challenges can have these features:

              • name: Name of the challenge, can be a string or a function. Can use basic HTML.

              • challengeDescription: A description of what makes the challenge a challenge. You will need to implement these elsewhere It can also be a function that returns updating text. Can use basic HTML.

              • rewardDescription: A description of the reward's effect. You will also have to implement the effect where it is applied. It can also be a function that returns updating text. Can use basic HTML.

              • rewardEffect(): optional, A function that calculates and returns the current values of any bonuses from the reward. Can return a value or an object containing multiple values. Can use basic HTML.

              • rewardDisplay(): optional, A function that returns a display of the current effects of the reward with formatting. Default behavior is to just display the a number appropriately formatted.

              • goal: A Decimal for the amount of currency required to beat the challenge. By default, the goal is in basic Points. The goal can also be a function if its value changes.

              • unlocked(): optional, A function returning a bool to determine if the challenge is visible or not. Default is unlocked.

              • onComplete() - optional, this function will be called when the challenge is completed when previously incomplete.

              • countsAs: optional, If a challenge combines the effects of other challenges in this layer, you can use this. An array of challenge ids. The player is effectively in all of those challenges when in the current one.

              By default, challenges use basic Points for the goal. You can change that using these features.

              • currencyDisplayName: optional, the name to display for the currency for the goal

              • currencyInternalName: optional, the internal name for that currency

              • currencyLayer: optional, the internal name of the layer that currency is stored in. If it's not in a layer, omit. If it's not stored directly in a layer, instead use the next feature.

              • currencyLocation: optional, if your currency is stored in something inside a layer (e.g. a buyable's amount), you can access it this way. This is a function returning the object in "player" that contains the value (like player[this.layer].buyables)

              • completionLimit: optional, the amount of times you can complete this challenge. Default is 1 completion.

              • style: Optional, Applies CSS to this challenge, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings)

              • layer: Assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar

              • id: Assigned automagically. It's the "key" which the challenge was stored under, for convenient access. The challenge in the example's id is 11.

              - + }

              Each challenge should have an id where the first digit is the row and the second digit is the column. Individual Challenges can have these features:

              • name: Name of the challenge, can be a string or a function. Can use basic HTML.

              • challengeDescription: A description of what makes the challenge a challenge. You will need to implement these elsewhere It can also be a function that returns updating text. Can use basic HTML.

              • rewardDescription: A description of the reward's effect. You will also have to implement the effect where it is applied. It can also be a function that returns updating text. Can use basic HTML.

              • rewardEffect(): optional, A function that calculates and returns the current values of any bonuses from the reward. Can return a value or an object containing multiple values. Can use basic HTML.

              • rewardDisplay(): optional, A function that returns a display of the current effects of the reward with formatting. Default behavior is to just display the a number appropriately formatted.

              • goal: A Decimal for the amount of currency required to beat the challenge. By default, the goal is in basic Points. The goal can also be a function if its value changes.

              • unlocked(): optional, A function returning a bool to determine if the challenge is visible or not. Default is unlocked.

              • onComplete() - optional, this function will be called when the challenge is completed when previously incomplete.

              • countsAs: optional, If a challenge combines the effects of other challenges in this layer, you can use this. An array of challenge ids. The player is effectively in all of those challenges when in the current one.

              By default, challenges use basic Points for the goal. You can change that using these features.

              • currencyDisplayName: optional, the name to display for the currency for the goal

              • currencyInternalName: optional, the internal name for that currency

              • currencyLayer: optional, the internal name of the layer that currency is stored in. If it's not in a layer, omit. If it's not stored directly in a layer, instead use the next feature.

              • currencyLocation: optional, if your currency is stored in something inside a layer (e.g. a buyable's amount), you can access it this way. This is a function returning the object in "player" that contains the value (like player[this.layer].buyables)

              • completionLimit: optional, the amount of times you can complete this challenge. Default is 1 completion.

              • style: Optional, Applies CSS to this challenge, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings)

              • layer: Assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar

              • id: Assigned automagically. It's the "key" which the challenge was stored under, for convenient access. The challenge in the example's id is 11.

              + \ No newline at end of file diff --git a/public/gamedevtree/docs/clickables.html b/public/gamedevtree/docs/clickables.html index 3261e997..f15e8f6d 100644 --- a/public/gamedevtree/docs/clickables.html +++ b/public/gamedevtree/docs/clickables.html @@ -6,13 +6,13 @@ Clickables | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
              Skip to content

              Clickables

              Clickables are any kind of thing that you can click for an effect. They're a more generalized version of Buyables.

              DO NOT USE THESE TO MAKE THINGS THAT YOU CLICK REPEATEDLY FOR A BONUS BECAUSE THOSE ARE AWFUL.

              There are several differences between the two. One is that a buyable's saved data is its amount as a Decimal, while Clickables store a "state" which can be a number or string, but not Decimal, array, or object). Buyables have a number of extra features which you can see on their page. Clickables also have a smaller default size.

              You can get and set a clickable's state with getClickableState(layer, id) and setClickableState(layer, id, state). You can use clickableEffect(layer, id) to get the current effects of a clickable.

              Clickables should be formatted like this:

              js
                  clickables: {
              +    
              Skip to content

              Clickables

              Clickables are any kind of thing that you can click for an effect. They're a more generalized version of Buyables.

              DO NOT USE THESE TO MAKE THINGS THAT YOU CLICK REPEATEDLY FOR A BONUS BECAUSE THOSE ARE AWFUL.

              There are several differences between the two. One is that a buyable's saved data is its amount as a Decimal, while Clickables store a "state" which can be a number or string, but not Decimal, array, or object). Buyables have a number of extra features which you can see on their page. Clickables also have a smaller default size.

              You can get and set a clickable's state with getClickableState(layer, id) and setClickableState(layer, id, state). You can use clickableEffect(layer, id) to get the current effects of a clickable.

              Clickables should be formatted like this:

              js
                  clickables: {
                       rows: # of rows
                       cols: # of columns
                       masterButtonPress() // **optional** If this is present, an additional button will appear above the clickables.
              @@ -46,8 +46,8 @@
                           etc
                       }
                       etc
              -    }

              Features:

              • title: optional, displayed at the top in a larger font It can also be a function that returns updating text.

              • effect(): optional, A function that calculates and returns the current values of bonuses of this clickable. Can return a value or an object containing multiple values.

              • display(): A function returning everything that should be displayed on the clickable after the title, likely changing based on its state. Can use basic HTML.

              • unlocked(): optional, A function returning a bool to determine if the clickable is visible or not. Default is unlocked.

              • canClick(): A function returning a bool to determine if you can click the clickable.

              • onClick(): A function that implements clicking one of the clickable.

              • style: Optional, Applies CSS to this clickable, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings)

              • layer: Assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

              • id: Assigned automagically. It's the "key" which the clickable was stored under, for convenient access. The clickable in the example's id is 11.

              - + }

              Features:

              • title: optional, displayed at the top in a larger font It can also be a function that returns updating text.

              • effect(): optional, A function that calculates and returns the current values of bonuses of this clickable. Can return a value or an object containing multiple values.

              • display(): A function returning everything that should be displayed on the clickable after the title, likely changing based on its state. Can use basic HTML.

              • unlocked(): optional, A function returning a bool to determine if the clickable is visible or not. Default is unlocked.

              • canClick(): A function returning a bool to determine if you can click the clickable.

              • onClick(): A function that implements clicking one of the clickable.

              • style: Optional, Applies CSS to this clickable, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings)

              • layer: Assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

              • id: Assigned automagically. It's the "key" which the clickable was stored under, for convenient access. The clickable in the example's id is 11.

              + \ No newline at end of file diff --git a/public/gamedevtree/docs/custom-tab-layouts.html b/public/gamedevtree/docs/custom-tab-layouts.html index f9f66dad..98ec3a87 100644 --- a/public/gamedevtree/docs/custom-tab-layouts.html +++ b/public/gamedevtree/docs/custom-tab-layouts.html @@ -6,13 +6,13 @@ Custom tab layouts | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
              Skip to content

              Custom tab layouts

              Note: If you are using subtabs, tabFormat is used differently, but you still use the same format within each subtabs. See here for more on subtabs

              Custom tab layouts can be used to do basically anything in a tab window, especially combined with the "style" layer feature. The tabFormat feature is an array of things, like this:

              js
                  tabFormat: ["main-display",
              +    
              Skip to content

              Custom tab layouts

              Note: If you are using subtabs, tabFormat is used differently, but you still use the same format within each subtabs. See here for more on subtabs

              Custom tab layouts can be used to do basically anything in a tab window, especially combined with the "style" layer feature. The tabFormat feature is an array of things, like this:

              js
                  tabFormat: ["main-display",
                           ["prestige-button", function(){return "Melt your points into "}],
                           "blank",
                           ["display-text",
              @@ -42,8 +42,8 @@
                               {"color": "red", "font-size": "32px", "font-family": "Comic Sans MS"}],
                           "blank",
                           ["toggle", ["c", "beep"]],
              -            "milestones", "blank", "blank", "upgrades"]

              It is a list of components, which can be either just a name, or an array with arguments. If it's an array, the first item is the name of the component, the second is the data passed into it, and the third (optional) applies a CSS style to it with a "CSS object", where the keys are CSS attributes.

              These are the existing components, but you can create more in v.js:

              • display-text: Displays some text (can use basic HTML). The argument is the text to display. It can also be a function that returns updating text.

              • raw-html: Displays some basic HTML, can also be a function.

              • blank: Adds empty space. The default dimensions are 8px x 17px. The argument changes the dimensions. If it's a single value (e.g. "20px"), that determines the height. If you have a pair of arguments, the first is width and the second is height.

              • row: Display a list of components horizontally. The argument is an array of components in the tab layout format.

              • column: Display a list of components vertically. The argument is an array of components in the tab layout format. This is useful to display columns within a row.

              • main-display: The text that displays the main currency for the layer and its effects.

              • resource-display: The text that displays the currency that this layer is based on, as well as the best and/or total values for this layer's prestige currency (if they are put in startData for this layer)

              • prestige-button: The argument is a string that the prestige button should say before the amount of currency you will gain. It can also be a function that returns updating text.

              • upgrades, milestones, challs, achievements: Display the upgrades, milestones, and challenges for a layer, as appropriate.

              • buyables, clickables: Display all of the buyables/clickables for this layer, as appropriate. The argument optional, and is the size of the boxes in pixels.

              • microtabs: Display a set of subtabs for an area. The argument is the name of the set of microtabs in the "microtabs" feature.

              • bar: Display a bar. The argument is the id of the bar to display.

              • infobox: Display an infobox. The argument is the id of the infobox to display.

              • toggle: A toggle button that toggles a bool value. The data is a pair that identifies what bool to toggle, [layer, id]

              The rest of the components are sub-components. They can be used just like other components, but are typically part of another component.

              • upgrade, milestone, chall, buyable, clickable, achievement: An individual upgrade, challenge, etc. The argument is the id. This can be used if you want to have upgrades split up across multiple subtabs, for example.

              • respec-button, master-button: The respec and master buttons for buyables and clickables, respectively.

              • sell-one, sell-all: The "sell one" and "sell all" for buyables, respectively. The argument is the id of the buyable.

              - + "milestones", "blank", "blank", "upgrades"]

              It is a list of components, which can be either just a name, or an array with arguments. If it's an array, the first item is the name of the component, the second is the data passed into it, and the third (optional) applies a CSS style to it with a "CSS object", where the keys are CSS attributes.

              These are the existing components, but you can create more in v.js:

              • display-text: Displays some text (can use basic HTML). The argument is the text to display. It can also be a function that returns updating text.

              • raw-html: Displays some basic HTML, can also be a function.

              • blank: Adds empty space. The default dimensions are 8px x 17px. The argument changes the dimensions. If it's a single value (e.g. "20px"), that determines the height. If you have a pair of arguments, the first is width and the second is height.

              • row: Display a list of components horizontally. The argument is an array of components in the tab layout format.

              • column: Display a list of components vertically. The argument is an array of components in the tab layout format. This is useful to display columns within a row.

              • main-display: The text that displays the main currency for the layer and its effects.

              • resource-display: The text that displays the currency that this layer is based on, as well as the best and/or total values for this layer's prestige currency (if they are put in startData for this layer)

              • prestige-button: The argument is a string that the prestige button should say before the amount of currency you will gain. It can also be a function that returns updating text.

              • upgrades, milestones, challs, achievements: Display the upgrades, milestones, and challenges for a layer, as appropriate.

              • buyables, clickables: Display all of the buyables/clickables for this layer, as appropriate. The argument optional, and is the size of the boxes in pixels.

              • microtabs: Display a set of subtabs for an area. The argument is the name of the set of microtabs in the "microtabs" feature.

              • bar: Display a bar. The argument is the id of the bar to display.

              • infobox: Display an infobox. The argument is the id of the infobox to display.

              • toggle: A toggle button that toggles a bool value. The data is a pair that identifies what bool to toggle, [layer, id]

              The rest of the components are sub-components. They can be used just like other components, but are typically part of another component.

              • upgrade, milestone, chall, buyable, clickable, achievement: An individual upgrade, challenge, etc. The argument is the id. This can be used if you want to have upgrades split up across multiple subtabs, for example.

              • respec-button, master-button: The respec and master buttons for buyables and clickables, respectively.

              • sell-one, sell-all: The "sell one" and "sell all" for buyables, respectively. The argument is the id of the buyable.

              + \ No newline at end of file diff --git a/public/gamedevtree/docs/getting-started.html b/public/gamedevtree/docs/getting-started.html index 0578fb39..b4783623 100644 --- a/public/gamedevtree/docs/getting-started.html +++ b/public/gamedevtree/docs/getting-started.html @@ -6,13 +6,13 @@ Getting started | The Paper Pilot - + - + - - - + + + @@ -34,8 +34,8 @@ -
              Skip to content

              Getting started

              Welcome to The Modding Tree!

              Using the Modding Tree, at its simplest level, just requires getting a copy of it onto your computer. However, if you do it the right way, it will help in many ways.

              Don't let the word "Github" scare you away. It's actually much easier to use than most people think, especially because most people use it the hard way. The key is Github Desktop, which lets you do everything you need to, without even touching the command line.

              The benefits of using Github:

              • It makes it much, much easier to update The Modding Tree.
              • You can share your work without any extra effort using githack, or with a bit more effort, set up a github.io site.
              • It lets you undo changes to your code, and to have multiple versions of it.
              • It lets you collaborate with other people, if you want to.

              Getting set up with Github and The Modding Tree:

              1. Install Github Desktop and Visual Studio Code.

              2. Make a Github account. You can handle this on your own.

              3. Log in on your browser, and go back to The Modding Tree page. At the top right, there should be a button that says "fork". Click on it, and then on your username. You now have your own fork, or copy, of The Modding Tree.

              4. Open Github Desktop and log in. Ignore everything else and choose "clone a repository". A "repository" is basically a "Github project", like The Modding Tree. "Cloning" is downloading a copy of the repository to your computer.

              5. Look for The Modding Tree in the list of repositiories (it should be the only one) and click "clone".

              6. Select that you're using it for your own purposes, and click continue. It will download the files and handle everything.

              Using your repository

              1. Click on "show in finder" to the right, and then open index.html. This will let you view and test your project!

              2. To edit your project, click "open in VSCode" in Github Desktop.

              3. Open mod.js in VSCode, and look at the top part where it says "modInfo". On the lines below that, change the mod's name to whatever you want, and change the id as well. (It can be any string value, and it's used to determine where the savefile is. Make it something that's probably unique, and don't change it again later.)

              4. Save game.js, and then reload index.html. The title on the tab, as well as on the info page, will now be the new ones!

              5. Go back to Github Desktop. It's time to save your changes into the git system by making a "commit".

              6. At the bottom right corner, add a summary of your changes, and then click "commit to master".

              7. Finally, at the top middle, click "push origin" to push your changes out onto the online repository.

              8. You can view your project on line, or share it with others, by going to https://raw.githack.com/[YOUR-GITHUB-USERNAME]/The-Modding-Tree/master/index.html

              And now, you have successfully used Github! You can look at the documentation to see how The Modding Tree's system works and to make your mod a reality.

              - +
              Skip to content

              Getting started

              Welcome to The Modding Tree!

              Using the Modding Tree, at its simplest level, just requires getting a copy of it onto your computer. However, if you do it the right way, it will help in many ways.

              Don't let the word "Github" scare you away. It's actually much easier to use than most people think, especially because most people use it the hard way. The key is Github Desktop, which lets you do everything you need to, without even touching the command line.

              The benefits of using Github:

              • It makes it much, much easier to update The Modding Tree.
              • You can share your work without any extra effort using githack, or with a bit more effort, set up a github.io site.
              • It lets you undo changes to your code, and to have multiple versions of it.
              • It lets you collaborate with other people, if you want to.

              Getting set up with Github and The Modding Tree:

              1. Install Github Desktop and Visual Studio Code.

              2. Make a Github account. You can handle this on your own.

              3. Log in on your browser, and go back to The Modding Tree page. At the top right, there should be a button that says "fork". Click on it, and then on your username. You now have your own fork, or copy, of The Modding Tree.

              4. Open Github Desktop and log in. Ignore everything else and choose "clone a repository". A "repository" is basically a "Github project", like The Modding Tree. "Cloning" is downloading a copy of the repository to your computer.

              5. Look for The Modding Tree in the list of repositiories (it should be the only one) and click "clone".

              6. Select that you're using it for your own purposes, and click continue. It will download the files and handle everything.

              Using your repository

              1. Click on "show in finder" to the right, and then open index.html. This will let you view and test your project!

              2. To edit your project, click "open in VSCode" in Github Desktop.

              3. Open mod.js in VSCode, and look at the top part where it says "modInfo". On the lines below that, change the mod's name to whatever you want, and change the id as well. (It can be any string value, and it's used to determine where the savefile is. Make it something that's probably unique, and don't change it again later.)

              4. Save game.js, and then reload index.html. The title on the tab, as well as on the info page, will now be the new ones!

              5. Go back to Github Desktop. It's time to save your changes into the git system by making a "commit".

              6. At the bottom right corner, add a summary of your changes, and then click "commit to master".

              7. Finally, at the top middle, click "push origin" to push your changes out onto the online repository.

              8. You can view your project on line, or share it with others, by going to https://raw.githack.com/[YOUR-GITHUB-USERNAME]/The-Modding-Tree/master/index.html

              And now, you have successfully used Github! You can look at the documentation to see how The Modding Tree's system works and to make your mod a reality.

              + \ No newline at end of file diff --git a/public/gamedevtree/docs/infoboxes.html b/public/gamedevtree/docs/infoboxes.html index 104d7845..10303859 100644 --- a/public/gamedevtree/docs/infoboxes.html +++ b/public/gamedevtree/docs/infoboxes.html @@ -6,13 +6,13 @@ Infoboxes | The Paper Pilot - + - + - - - + + + @@ -34,14 +34,14 @@ -
              Skip to content

              Infoboxes

              Infoboxes are good for displaying "lore", or story elements, as well as for explaining complicated things.

              In the default tab layout, the first infobox will be displayed at the very top of the tab.

              Infoboxes are defined like other Big Features:

              js
                  infoboxes: {
              +    
              Skip to content

              Infoboxes

              Infoboxes are good for displaying "lore", or story elements, as well as for explaining complicated things.

              In the default tab layout, the first infobox will be displayed at the very top of the tab.

              Infoboxes are defined like other Big Features:

              js
                  infoboxes: {
                       infobox: {
                           display() {return "Blah"},
                           etc
                       }
                       etc
              -    }

              Features:

              • title: The text displayed above the main box. Can be a function to be dynamic, and can use basic HTML.

              • body: The text displayed inside the box. Can be a function to be dynamic, and can use basic HTML.

              • style, titleStyle, bodyStyle: Optional, Apply CSS to the infobox, or to the title button or body of the infobox, in the form of an object where the keys are CSS attributes, and the values are the Values for those attributes (both as strings).

              • unlocked(): optional, A function returning a bool to determine if the infobox is visible or not. Default is unlocked.

              • layer: Assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar

              • id: Assigned automagically. It's the "key" which the bar was stored under, for convenient access. The bar in the example's id is "bigBar".

              - + }

              Features:

              • title: The text displayed above the main box. Can be a function to be dynamic, and can use basic HTML.

              • body: The text displayed inside the box. Can be a function to be dynamic, and can use basic HTML.

              • style, titleStyle, bodyStyle: Optional, Apply CSS to the infobox, or to the title button or body of the infobox, in the form of an object where the keys are CSS attributes, and the values are the Values for those attributes (both as strings).

              • unlocked(): optional, A function returning a bool to determine if the infobox is visible or not. Default is unlocked.

              • layer: Assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar

              • id: Assigned automagically. It's the "key" which the bar was stored under, for convenient access. The bar in the example's id is "bigBar".

              + \ No newline at end of file diff --git a/public/gamedevtree/docs/layer-features.html b/public/gamedevtree/docs/layer-features.html index b6c4cbde..32e8331d 100644 --- a/public/gamedevtree/docs/layer-features.html +++ b/public/gamedevtree/docs/layer-features.html @@ -6,13 +6,13 @@ Layer Features | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
              Skip to content

              Layer Features

              This is a more comprehensive list of established features to add to layers. You can add more freely, if you want to have other functions or values associated with your layer. These have special functionality, though.

              You can make almost any value dynamic by using a function in its place, including all display strings and styling/color features.

              Key:

              • No label: This is required and the game will crash if it isn't included.
              • sometimes required: This is may be required, depending on other things in the layer.
              • optional: You can leave this out if you don't intend to use that feature for the layer.

              Layer Definition features

              • layer: Assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar to access the save value. It makes copying code to new layers easier. It is also assigned to all upgrades and buyables and such.

              • name: Optional, used in reset confirmations (and maybe other places). If absent, it just uses the layer's id.

              • startData(): A function to return the default save data for this layer. Add any variables you have to it. Any nonstandard Decimal variables need to be added to convertToDecimal as well. Standard values: Required: unlocked: a bool determining if this layer is unlocked or not points: a Decimal, the main currency for the layer Optional: total: A Decimal, tracks total amount of main prestige currency best: A Decimal, tracks highest amount of main prestige currency unlockOrder: used to keep track of relevant layers unlocked before this one.

              • color: A color associated with this layer, used in many places. (A string in hex format with a #)

              • row: The row of the layer, starting at 0. This affects where the node appears on the tree, and which resets affect the layer.

                 Using "side" instead of a number will cause the layer to appear off to the side as a smaller node (useful for achievements
                +    
                Skip to content

                Layer Features

                This is a more comprehensive list of established features to add to layers. You can add more freely, if you want to have other functions or values associated with your layer. These have special functionality, though.

                You can make almost any value dynamic by using a function in its place, including all display strings and styling/color features.

                Key:

                • No label: This is required and the game will crash if it isn't included.
                • sometimes required: This is may be required, depending on other things in the layer.
                • optional: You can leave this out if you don't intend to use that feature for the layer.

                Layer Definition features

                • layer: Assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar to access the save value. It makes copying code to new layers easier. It is also assigned to all upgrades and buyables and such.

                • name: Optional, used in reset confirmations (and maybe other places). If absent, it just uses the layer's id.

                • startData(): A function to return the default save data for this layer. Add any variables you have to it. Any nonstandard Decimal variables need to be added to convertToDecimal as well. Standard values: Required: unlocked: a bool determining if this layer is unlocked or not points: a Decimal, the main currency for the layer Optional: total: A Decimal, tracks total amount of main prestige currency best: A Decimal, tracks highest amount of main prestige currency unlockOrder: used to keep track of relevant layers unlocked before this one.

                • color: A color associated with this layer, used in many places. (A string in hex format with a #)

                • row: The row of the layer, starting at 0. This affects where the node appears on the tree, and which resets affect the layer.

                   Using "side" instead of a number will cause the layer to appear off to the side as a smaller node (useful for achievements
                    and statistics). Side layers are not affected by resets unless you add a doReset to them.
                   
                • resource: Name of the main currency you gain by resetting on this layer.

                • effect(): optional, A function that calculates and returns the current values of any bonuses inherent to the main currency. Can return a value or an object containing multiple values. You will also have to implement the effect where it is applied.

                • effectDescription: optional, A function that returns a description of this effect. If the text stays constant, it can just be a string.

                • layerShown(): A function returning a bool which determines if this layer's node should be visible on the tree. It can also return "ghost", which will hide the layer, but its node will still take up space in the tree.

                • hotkeys: optional, An array containing information on any hotkeys associated with this layer:

                  js
                  hotkeys: [
                       {key: "p", // What the hotkey button is. Use uppercase if it's combined with shift, or "ctrl+x" if ctrl is.
                  @@ -49,8 +49,8 @@
                   
                • update(diff): optional, this function is called every game tick. Use it for any passive resource production or time-based things. diff is the time since the last tick. Suggestion: use addPoints(layer, gain) when generating points to automatically update the best and total amounts.

                • automate(): optional, this function is called every game tick, after production. Use it to activate any autobuyers or auto-resets or similar on this layer, if appropriate.

                • resetsNothing: optional, returns true if this layer shouldn't trigger any resets when you prestige.

                • increaseUnlockOrder: optional, an array of layer ids. When this layer is unlocked for the first time, the unlockOrder value for any not-yet-unlocked layers in this list increases. This can be used to make them harder to unlock.

                • shouldNotify: optional, a function to return true if this layer should be highlighted in the tree. The layer will automatically be highlighted if you can buy an upgrade whether you have this or not.

                • componentStyles: optional, An object that contains a set of functions returning CSS objects. Each of these will be applied to any components on the layer with the type of its id. Example:

                js
                        componentStyles: {
                             "challenge"() {return {'height': '200px'}},
                             "prestige-button"() {return {'color': '#AA66AA'}},
                -        },

                Custom Prestige type

                • getResetGain(): For custom prestige type, Returns how many points you should get if you reset now. You can call getResetGain(this.layer, useType = "static") or similar to calculate what your gain would be under another prestige type (provided you have all of the required features in the layer.)

                • getNextAt(canMax=false): For custom prestige type, Returns how many of the base currency you need to get to the next point. canMax is an optional variable used with Static-ish layers to differentiate between if it's looking for the first point you can reset at, or the requirement for any gain at all. (Supporting both is good). You can also call getNextAt(this.layer, canMax=false, useType = "static") or similar to calculate what your next at would be under another prestige type (provided you have all of the required features in the layer.)

                • canReset(): For custom prestige type, return true only if you have the resources required to do a prestige here.

                - + },

              Custom Prestige type

              • getResetGain(): For custom prestige type, Returns how many points you should get if you reset now. You can call getResetGain(this.layer, useType = "static") or similar to calculate what your gain would be under another prestige type (provided you have all of the required features in the layer.)

              • getNextAt(canMax=false): For custom prestige type, Returns how many of the base currency you need to get to the next point. canMax is an optional variable used with Static-ish layers to differentiate between if it's looking for the first point you can reset at, or the requirement for any gain at all. (Supporting both is good). You can also call getNextAt(this.layer, canMax=false, useType = "static") or similar to calculate what your next at would be under another prestige type (provided you have all of the required features in the layer.)

              • canReset(): For custom prestige type, return true only if you have the resources required to do a prestige here.

              + \ No newline at end of file diff --git a/public/gamedevtree/docs/main-mod-info.html b/public/gamedevtree/docs/main-mod-info.html index 36350f70..f51a670d 100644 --- a/public/gamedevtree/docs/main-mod-info.html +++ b/public/gamedevtree/docs/main-mod-info.html @@ -6,13 +6,13 @@ mod.js | The Paper Pilot - + - + - - - + + + @@ -34,12 +34,12 @@ -
              Skip to content

              mod.js

              All of the code and data that you're likely to edit is here in mod.js! Everything in mod.js will not be altered by updates, besides the addition of new things.

              Here's a breakdown of what's in it:

              • modInfo is where most of the basic configuration for the mod is. It contains:

                • name: The name of your mod. (a string)
                • id: The id for your mod, a unique string that is used to determine savefile location. Setting it is important!
                • author: The name of the author, displayed in the info tab.
                • pointsName: This changes what is displayed instead of "points" for the main currency. (It does not affect it in the code.)
                • discordName, discordLink: If you have a Discord server or other discussion place, you can add a link to it. "discordName" is the text on the link, and "discordLink" is the url of an invite. If you're using a Discord invite, please make sure it's set to never expire.
                • changelogLink: You can use this to set a link to a page where your changelog for the game is displayed.
                • offlineLimit: The maximum amount of offline time that the player can accumulate, in hours. Any extra time is lost. (a number) This is useful because most of these mods are fast-paced enough that too much offline time ruins the balance, such as the time in between updates. That is why I suggest developers disable offline time on their own savefile.
                • initialStartPoints: A Decimal for the amount of points a new player should start with.
              • VERSION is used to describe the current version of your mod. It contains: num: The mod's version number, displayed at the top right of the tree tab. name: The version's name, displayed alongside the number in the info tab.

              • doNotCallTheseFunctionsEveryTick is very important. TMT calls every function anywhere in "layers" every tick to store the result, unless specifically told not to. Functions that have are used to do an action need to be identified. "Official" functions (those in the documentation) are all fine, but if you make any new ones, add their names to this array.

              js
              // (The ones here are examples, all official functions are already taken care of)
              +    
              Skip to content

              mod.js

              All of the code and data that you're likely to edit is here in mod.js! Everything in mod.js will not be altered by updates, besides the addition of new things.

              Here's a breakdown of what's in it:

              • modInfo is where most of the basic configuration for the mod is. It contains:

                • name: The name of your mod. (a string)
                • id: The id for your mod, a unique string that is used to determine savefile location. Setting it is important!
                • author: The name of the author, displayed in the info tab.
                • pointsName: This changes what is displayed instead of "points" for the main currency. (It does not affect it in the code.)
                • discordName, discordLink: If you have a Discord server or other discussion place, you can add a link to it. "discordName" is the text on the link, and "discordLink" is the url of an invite. If you're using a Discord invite, please make sure it's set to never expire.
                • changelogLink: You can use this to set a link to a page where your changelog for the game is displayed.
                • offlineLimit: The maximum amount of offline time that the player can accumulate, in hours. Any extra time is lost. (a number) This is useful because most of these mods are fast-paced enough that too much offline time ruins the balance, such as the time in between updates. That is why I suggest developers disable offline time on their own savefile.
                • initialStartPoints: A Decimal for the amount of points a new player should start with.
              • VERSION is used to describe the current version of your mod. It contains: num: The mod's version number, displayed at the top right of the tree tab. name: The version's name, displayed alongside the number in the info tab.

              • doNotCallTheseFunctionsEveryTick is very important. TMT calls every function anywhere in "layers" every tick to store the result, unless specifically told not to. Functions that have are used to do an action need to be identified. "Official" functions (those in the documentation) are all fine, but if you make any new ones, add their names to this array.

              js
              // (The ones here are examples, all official functions are already taken care of)
               var doNotCallTheseFunctionsEveryTick = ["doReset", "buy", "onPurchase", "blowUpEverything"]
              • getStartPoints(): A function to determine the amount of points the player starts with after a reset. (returns a Decimal value)

              • canGenPoints(): A function returning a boolean for if points should be generated. Use this if you want an upgrade to unlock generating points.

              • getPointGen(): A function that calculates your points per second. Anything that affects your point gain should go into the calculation here.

              • addedPlayerData(): A function that returns any non-layer-related data that you want to be added to the save data and "player" object.

              js
              function addedPlayerData() { return {
               	weather: "Yes",
               	happiness: new Decimal(72),
              -}}
              • displayThings: An array of functions used to display extra things at the top of the tree tab. Each function returns a string, which is a line to display (with basic HTML support). If a function returns nothing, nothing is displayed (and it doesn't take up a line).

              • isEndgame(): A function to determine if the player has reached the end of the game, at which point the "you win!" screen appears.

              Less important things beyond this point!

              • maxTickLength(): Returns the maximum tick length, in milliseconds. Only really useful if you have something that reduces over time, which long ticks mess up (usually a challenge).
              - +}}
              • displayThings: An array of functions used to display extra things at the top of the tree tab. Each function returns a string, which is a line to display (with basic HTML support). If a function returns nothing, nothing is displayed (and it doesn't take up a line).

              • isEndgame(): A function to determine if the player has reached the end of the game, at which point the "you win!" screen appears.

              Less important things beyond this point!

              • maxTickLength(): Returns the maximum tick length, in milliseconds. Only really useful if you have something that reduces over time, which long ticks mess up (usually a challenge).
              + \ No newline at end of file diff --git a/public/gamedevtree/docs/milestones.html b/public/gamedevtree/docs/milestones.html index 74afa8e0..7e93fac5 100644 --- a/public/gamedevtree/docs/milestones.html +++ b/public/gamedevtree/docs/milestones.html @@ -6,13 +6,13 @@ Milestones | The Paper Pilot - + - + - - - + + + @@ -34,14 +34,14 @@ -
              Skip to content

              Milestones

              Milestones are awarded to the player when they meet a certain goal, and give some benefit. Milestones should be formatted like this:

              js
                  milestones: {
              +    
              Skip to content

              Milestones

              Milestones are awarded to the player when they meet a certain goal, and give some benefit. Milestones should be formatted like this:

              js
                  milestones: {
                       0: {
                           requirementDesc: "123 waffles",
                       }
                       etc
                   }

              You can use hasMilestone(layer, id) to determine if the player has a given milestone

              Milestone features:

              • requirementDesc: A string describing the requirement for unlocking this milestone. Suggestion: Use a "total". It can also be a function that returns updating text. Can use basic HTML.

              • effectDesc: A string describing the reward for having the milestone. You will have to implement the reward elsewhere. It can also be a function that returns updating text. Can use basic HTML.

              • done(): A function returning a boolean to determine if the milestone should be awarded.

              • toggles: optional, Creates toggle buttons that appear on the milestone when it is unlocked. The toggles can toggle a given boolean value in a layer. It is defined as an array of paired items, one pair per toggle. The first is the internal name of the layer the value being toggled is stored in, and the second is the internal name of the variable to toggle. (e.g. [["b", "auto"], ["g", "auto"])

                     **Tip:** Toggles are not de-set if the milestone becomes locked! In this case, you should also check if the player has the milestone.
                -
              • style: Optional, Applies CSS to this milestone, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings)

              • unlocked(): Optional A function returning a boolean to determine if the milestone should be shown. If absent, it is always shown.

              • layer: Assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar

              • id: Assigned automagically. It's the "key" which the milestone was stored under, for convenient access. The milestone in the example's id is 0.

              - +
            • style: Optional, Applies CSS to this milestone, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings)

            • unlocked(): Optional A function returning a boolean to determine if the milestone should be shown. If absent, it is always shown.

            • layer: Assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar

            • id: Assigned automagically. It's the "key" which the milestone was stored under, for convenient access. The milestone in the example's id is 0.

          + \ No newline at end of file diff --git a/public/gamedevtree/docs/subtabs-and-microtabs.html b/public/gamedevtree/docs/subtabs-and-microtabs.html index d83666be..ddcfba52 100644 --- a/public/gamedevtree/docs/subtabs-and-microtabs.html +++ b/public/gamedevtree/docs/subtabs-and-microtabs.html @@ -6,13 +6,13 @@ Subtabs and Microtabs | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
          Skip to content

          Subtabs and Microtabs

          Subtabs are separate sections of a tab that you can view by selecting one at the top of the tab. Microtabs are smaller areas that function in much the same way.

          Subtabs are defined by using the tab format like this, where each element of tabFormat is given the name of that subtab:

          js
              tabFormat: {
          +    
          Skip to content

          Subtabs and Microtabs

          Subtabs are separate sections of a tab that you can view by selecting one at the top of the tab. Microtabs are smaller areas that function in much the same way.

          Subtabs are defined by using the tab format like this, where each element of tabFormat is given the name of that subtab:

          js
              tabFormat: {
                   "Main tab": {
                       *subtab features*
                   },
          @@ -56,8 +56,8 @@
                   otherStuff: {
                       // There could be another set of microtabs here
                   }
          -    },

          Normal subtabs and microtab subtabs both use the same features:

          Features:

          • content: The tab layout code for the subtab, in the tab layout format

          • style: Optional, Applies CSS to the whole subtab when switched to, in the form of an "CSS Object", where the keys are CSS attributes, and the values are the values for those attributes (both as strings)

          • buttonStyle: Optional, A CSS object, which affects the appearance of the button for that subtab.

          • unlocked(): Optional, a function to determine if the button for this subtab should be visible. By default, a subtab is always unlocked. (You can't use the "this" keyword in this function.)

          - + },

          Normal subtabs and microtab subtabs both use the same features:

          Features:

          • content: The tab layout code for the subtab, in the tab layout format

          • style: Optional, Applies CSS to the whole subtab when switched to, in the form of an "CSS Object", where the keys are CSS attributes, and the values are the values for those attributes (both as strings)

          • buttonStyle: Optional, A CSS object, which affects the appearance of the button for that subtab.

          • unlocked(): Optional, a function to determine if the button for this subtab should be visible. By default, a subtab is always unlocked. (You can't use the "this" keyword in this function.)

          + \ No newline at end of file diff --git a/public/gamedevtree/docs/updating-tmt.html b/public/gamedevtree/docs/updating-tmt.html index 061a4192..e8e2e8c3 100644 --- a/public/gamedevtree/docs/updating-tmt.html +++ b/public/gamedevtree/docs/updating-tmt.html @@ -6,13 +6,13 @@ Updating The Modding Tree | The Paper Pilot - + - + - - - + + + @@ -34,8 +34,8 @@ -
          Skip to content

          Updating The Modding Tree

          This tutorial assumes that you have used the Getting Started Tutorial, and are using Github Desktop and VSCode for your mod.

          Here's what you have to do when there's a TMT update:

          1. Look at the changelog. It will warn you if the update will break anything or require any changes. Decide if you want to try to update.

          2. Open Github Desktop, and at the top middle, click "fetch origin". This will make Github Desktop get information about the update.

          3. Click where it says "current branch: master" at the top middle, and at the bottom of the thing that appears, click "choose a branch to merge into master.

          4. Select upstream/master. It will likely say there are conflicts, but you have tools to resolve them. Click "Merge upstream/master into master".

          5. A conflict happens when the things you're trying to merge have both made changes in the same place. Click "open in Visual Studio Code" next to the first file.

          6. Scroll down through the file, and look for the parts highlighted in red and green. One of these is your code, and the other is some code that will be modified by the update. Do your best to try to edit things to keep the updated changes, but keep your content.

          7. Continue to do this for all remaining challenges.

          8. Do any other changes required by the update, run the game, fix issues, etc.

          - +
          Skip to content

          Updating The Modding Tree

          This tutorial assumes that you have used the Getting Started Tutorial, and are using Github Desktop and VSCode for your mod.

          Here's what you have to do when there's a TMT update:

          1. Look at the changelog. It will warn you if the update will break anything or require any changes. Decide if you want to try to update.

          2. Open Github Desktop, and at the top middle, click "fetch origin". This will make Github Desktop get information about the update.

          3. Click where it says "current branch: master" at the top middle, and at the bottom of the thing that appears, click "choose a branch to merge into master.

          4. Select upstream/master. It will likely say there are conflicts, but you have tools to resolve them. Click "Merge upstream/master into master".

          5. A conflict happens when the things you're trying to merge have both made changes in the same place. Click "open in Visual Studio Code" next to the first file.

          6. Scroll down through the file, and look for the parts highlighted in red and green. One of these is your code, and the other is some code that will be modified by the update. Do your best to try to edit things to keep the updated changes, but keep your content.

          7. Continue to do this for all remaining challenges.

          8. Do any other changes required by the update, run the game, fix issues, etc.

          + \ No newline at end of file diff --git a/public/gamedevtree/docs/upgrades.html b/public/gamedevtree/docs/upgrades.html index f69b53f2..3998694f 100644 --- a/public/gamedevtree/docs/upgrades.html +++ b/public/gamedevtree/docs/upgrades.html @@ -6,13 +6,13 @@ Upgrades | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
          Skip to content

          Upgrades

          Useful functions for dealing with Upgrades and implementing their effects:

          • hasUpgrade(layer, id): determine if the player has the upgrade
          • upgradeEffect(layer, id): Returns the current effects of the upgrade, if any
          • buyUpgrade(layer, id): Buys an upgrade directly (if affordable)

          Hint: Basic point gain is calculated in mod.js's "getPointGen".

          Upgrades are stored in the following format:

          js
              upgrades: {
          +    
          Skip to content

          Upgrades

          Useful functions for dealing with Upgrades and implementing their effects:

          • hasUpgrade(layer, id): determine if the player has the upgrade
          • upgradeEffect(layer, id): Returns the current effects of the upgrade, if any
          • buyUpgrade(layer, id): Buys an upgrade directly (if affordable)

          Hint: Basic point gain is calculated in mod.js's "getPointGen".

          Upgrades are stored in the following format:

          js
              upgrades: {
                   rows: # of rows
                   cols: # of columns
                   11: {
          @@ -42,8 +42,8 @@
                       more features
                   }
                   etc
          -    }

          Each upgrade should have an id where the first digit is the row and the second digit is the column. Individual upgrades can have these features:

          • title: optional, displayed at the top in a larger font It can also be a function that returns updating text. Can use basic HTML.

          • description: A description of the upgrade's effect. You will also have to implement the effect where it is applied. It can also be a function that returns updating text. Can use basic HTML.

          • effect(): optional, A function that calculates and returns the current values of any bonuses from the upgrade. Can return a value or an object containing multiple values.

          • effectDisplay(): optional, A function that returns a display of the current effects of the upgrade with formatting. Default behavior is to just display the a number appropriately formatted. Can use basic HTML.

          • cost: A Decimal for the cost of the upgrade. By default, upgrades cost the main prestige currency for the layer.

          • unlocked(): optional, A function returning a bool to determine if the upgrade is visible or not. Default is unlocked.

          • onPurchase() - optional, this function will be called when the upgrade is purchased. Good for upgrades like "makes this layer act like it was unlocked first".

          By default, upgrades use the main prestige currency for the layer. You can include these to change them (but it needs to be a Decimal):

          • currencyDisplayName: optional, the name to display for the currency for the upgrade

          • currencyInternalName: optional, the internal name for that currency

          • currencyLayer: optional, the internal name of the layer that currency is stored in. If it's not in a layer (like Points), omit. If it's not stored directly in a layer, instead use the next feature.

          • currencyLocation: optional, if your currency is stored in something inside a layer (e.g. a buyable's amount), you can access it this way. This is a function returning the object in "player" that contains the value (like player[this.layer].buyables)

          • style: Optional, Applies CSS to this upgrade, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings)

          • layer: Assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar

          • id: Assigned automagically. It's the "key" which the upgrade was stored under, for convenient access. The upgrade in the example's id is 11.

          - + }

          Each upgrade should have an id where the first digit is the row and the second digit is the column. Individual upgrades can have these features:

          • title: optional, displayed at the top in a larger font It can also be a function that returns updating text. Can use basic HTML.

          • description: A description of the upgrade's effect. You will also have to implement the effect where it is applied. It can also be a function that returns updating text. Can use basic HTML.

          • effect(): optional, A function that calculates and returns the current values of any bonuses from the upgrade. Can return a value or an object containing multiple values.

          • effectDisplay(): optional, A function that returns a display of the current effects of the upgrade with formatting. Default behavior is to just display the a number appropriately formatted. Can use basic HTML.

          • cost: A Decimal for the cost of the upgrade. By default, upgrades cost the main prestige currency for the layer.

          • unlocked(): optional, A function returning a bool to determine if the upgrade is visible or not. Default is unlocked.

          • onPurchase() - optional, this function will be called when the upgrade is purchased. Good for upgrades like "makes this layer act like it was unlocked first".

          By default, upgrades use the main prestige currency for the layer. You can include these to change them (but it needs to be a Decimal):

          • currencyDisplayName: optional, the name to display for the currency for the upgrade

          • currencyInternalName: optional, the internal name for that currency

          • currencyLayer: optional, the internal name of the layer that currency is stored in. If it's not in a layer (like Points), omit. If it's not stored directly in a layer, instead use the next feature.

          • currencyLocation: optional, if your currency is stored in something inside a layer (e.g. a buyable's amount), you can access it this way. This is a function returning the object in "player" that contains the value (like player[this.layer].buyables)

          • style: Optional, Applies CSS to this upgrade, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings)

          • layer: Assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar

          • id: Assigned automagically. It's the "key" which the upgrade was stored under, for convenient access. The upgrade in the example's id is 11.

          + \ No newline at end of file diff --git a/public/kronos/Old Things/2.0-format-changes.html b/public/kronos/Old Things/2.0-format-changes.html index ff207252..52a4d246 100644 --- a/public/kronos/Old Things/2.0-format-changes.html +++ b/public/kronos/Old Things/2.0-format-changes.html @@ -6,13 +6,13 @@ 2.0 format changes | The Paper Pilot - + - + - - - + + + @@ -34,8 +34,8 @@ -
          Skip to content

          2.0 format changes

          • Temp format is changed from temp.something[layer] to temp[layer].something, for consistency
          • Challenges are now saved as an object with the amount of completions in each spot. (This will break saves.)
          • effectDisplay in Challenges and Upgrades no longer takes an argument, and neither does effect for Buyables
          • Buyable cost can take an argument for amount of buyables, but it needs to function if no argument is supplied (it should do the cost for the next purchase).
          • Generation of Points now happens in the main game loop (not in a layer update function), enabled by canGenPoints in game.js.
          • Changed fullLayerReset to layerDataReset, which takes an array of names of values to keep

          In addition, many names were changed, mostly expanding abbreviations:

          All instances of:

          • chall -> challenge
          • unl -> unlocked
          • upg -> upgrade (besides CSS)
          • amt -> amount
          • desc -> description
          • resCeil -> roundUpCost
          • order -> unlockOrder
          • incr_order -> increaseUnlockOrder

          Challenges:

          • desc -> challengeDescription
          • reward -> rewardDescription
          • effect -> rewardEffect
          • effectDisplay -> rewardDisplay
          • active -> challengeActive
          - +
          Skip to content

          2.0 format changes

          • Temp format is changed from temp.something[layer] to temp[layer].something, for consistency
          • Challenges are now saved as an object with the amount of completions in each spot. (This will break saves.)
          • effectDisplay in Challenges and Upgrades no longer takes an argument, and neither does effect for Buyables
          • Buyable cost can take an argument for amount of buyables, but it needs to function if no argument is supplied (it should do the cost for the next purchase).
          • Generation of Points now happens in the main game loop (not in a layer update function), enabled by canGenPoints in game.js.
          • Changed fullLayerReset to layerDataReset, which takes an array of names of values to keep

          In addition, many names were changed, mostly expanding abbreviations:

          All instances of:

          • chall -> challenge
          • unl -> unlocked
          • upg -> upgrade (besides CSS)
          • amt -> amount
          • desc -> description
          • resCeil -> roundUpCost
          • order -> unlockOrder
          • incr_order -> increaseUnlockOrder

          Challenges:

          • desc -> challengeDescription
          • reward -> rewardDescription
          • effect -> rewardEffect
          • effectDisplay -> rewardDisplay
          • active -> challengeActive
          + \ No newline at end of file diff --git a/public/kronos/README.html b/public/kronos/README.html index 85dddc78..6b68071f 100644 --- a/public/kronos/README.html +++ b/public/kronos/README.html @@ -6,13 +6,13 @@ Kronos | The Paper Pilot - + - + - - - + + + @@ -34,8 +34,8 @@ -
          Skip to content

          Kronos

          Play here.

          Updating the website:

          • git submodule update --remote
          • git add -A
          • git commit -m "Updated kronos"
          • git push
          - +
          Skip to content

          Kronos

          Play here.

          Updating the website:

          • git submodule update --remote
          • git add -A
          • git commit -m "Updated kronos"
          • git push
          + \ No newline at end of file diff --git a/public/kronos/changelog.html b/public/kronos/changelog.html index d2506cc4..bfac9886 100644 --- a/public/kronos/changelog.html +++ b/public/kronos/changelog.html @@ -6,13 +6,13 @@ The Modding Tree changelog: | The Paper Pilot - + - + - - - + + + @@ -34,8 +34,8 @@ -
          Skip to content

          The Modding Tree changelog:

          v2.5.9.2 - 5/19/21

          • Fixed many issues with things not updating.

          v2.5.9.1 - 5/18/21

          • Made text inputs never give NaNs.

          v2.5.9 - 5/18/21

          • Fixed issue when using text inputs for Numbers.
          • Added particle color feature.
          • Particle speed and dir are updated as it moves.
          • Added setSpeed and setDir for particles.
          • Added more trig functions.

          v2.5.8 - 5/17/21

          • Added makeShinies, which creates a stationary particle in a random spot.
          • Bars will visually update more quickly.
          • Fixed a major particle-related issue.
          • Fixed autoUpgrade.
          • Fixed a minor visual issue with tree nodes.

          v2.5.7 - 5/15/21

          • Added a particle system! Not only can it be used for visual effects, but particles can interact with the mouse. They could be used to create golden cookies or collectables, for example.
          • Added marked feature to buyables, clickables, and challenges. By default, stars multi-completion challenges when maxed.
          • Added 'deactivated' feature to layers, which disables many features.
          • Improved number formatting slightly.

          v2.5.6 - 5/14/21

          • You can now use non-numeric ids for upgrades, buyables, etc.
          • Fixed an exploit that let you buy an extra buyable.
          • Moved basic getter/setter functions to easyAccess.js.

          v2.5.5.2 - 5/12/21

          • Fixed a major issue with buyables.
          • Fixed a variety of tabFormat-related issues.
          • Fixed commas appearing in decimal places (thanks to pg132!)

          v2.5.5.1 - 5/12/21

          • Fixed clickables.

          v2.5.5 - 5/12/21

          • Added grids! They are a grid of buttons which behave the same, but have their own data. Good for inventory grids, map tiles, and more!
          • Added "marked" feature to add a mark to a node. Can be an image instead of a star. (Originally by Jacorb)
          • Added "layer-proxy" component that lets you use components from another layer.
          • Added the ability to display non-whole numbers in main-display.

          v2.5.4 - 5/10/21

          • Added a setting to always use single-tab mode.
          • Added directMult, which multiplies prestige gain after exponents and softcaps. It actually multiplies gain for static layers.
          • Added onEnter and onExit for challenges.
          • Improved displaying numbers between 0.0001 and 0.1.
          • Added documentation on how gainMult/Exp work for static layers.
          • Fixed a visual issue on mobile, thanks to thepaperpilot.
          • Improved documentation in general.

          v2.5.3 - 5/8/21

          • Improved performance of tab formats and bars.
          • Respec confirmation settings are now kept on resets.
          • Improved compatibility with older browsers.
          • Fixed missing pixel on vertical bars.

          v2.5.2.1 - 5/7/21

          • Fixed microtabs making layers highlight incorrectly.

          v2.5.2 - 5/7/21

          • Added glowColor for subtabs.
          • Improved the display for extremely small numbers.
          • Fixed issues in the buyable docs.

          v2.5.1 - 5/7/21

          • Fixed dynamic things in tabFormat not updating.

          v2.5: Dreams Really Do Come True - 5/7/21

          • Optimizations, hopefully a significant amount.
          • Added OOM/s point gen display at high values (thanks to Ducdat!)
          • Only one tab will display if the window is not wide enough (also thanks to Ducdat!)
          • Holding down a buyable's button now buys it continuously.
          • New milestone setting will also show the most recently unlocked milestone. (Also renamed all settings to be clearer)
          • Added an onHold feature for clickables.
          • Layer nodes will be highlighted even if the player is on the same tab.
          • Added customizable node glowColor.
          • Added buyable purchaseLimit.
          • Amount is automatically supplied to buyable cost and effect functions.
          • Locked (not yet visible) milestones no longer take up space. Also fixed hidden milestones taking a tiny bit of space.
          • Re-centered respec buttons.
          • Force-displayed tooltips are not hidden by resets.
          • Added formatting support for very small numbers. Disabled in most places by default because rounding errors might cause issues. Access it with formatSmall, or enable it globally by adding "allowSmall: true" to modInfo.

          v2.4.1 - 4/29/21

          • A number of minor fixes, many thanks to thepaperpilot.
          • The respec confirmation checkbox is now part of the respec-button component. (This also fixes the checkbox appearing when there is no respec button)
          • Added a few undocumented changes to the 2.4 changelog (the two at the bottom)

          v2.4: Rationalized Edition - 4/29/21

          • Completely reworked tooltips. Shift-click a node to force its tooltip to stay displayed. (And hopefully finally fixed flickering!)

          • Added text-input and slider components.

          • Added the ability to toggle respec confirmations.

          • Added custom respec confirmation messages.

          • The red layer highlight will not appear before a layer is unlocked.

          • Added unlocking hotkeys.

          • You no longer need to supply 'rows' and 'cols' for any Big Features.

          • Node symbols can use HTML.

          • Added documentation for the respec button.

          • Added prestigeNotify to subtabs, and prestigeNotify in subtabs also highlights the layer node.

          • The version number no longer contains special characters or irrational numbers.

          • Added ctrlDown and shiftDown variables.

          • Tooltips now use HTML (this means you need to replace any newlines with
            )

          v2.π.1 - 4/7/21

          • Fixed formatting for some larger numbers.
          • Upgrades will expand if there is too much text to display.
          • Fixed styling challenges.
          • No longer attempts to display a base currency when there is none.

          v2.π: Incrementally Updated - 2/5/21

          • Performance improvements.
          • Fixed tooltips overlapping with the top display.
          • Clicking a popup dismisses it immediately.
          • Added support for bulk challenge completions.
          • "Best" is updated automatically.
          • Fixed keeping Decimal values on reset.
          • Code reorganization and style improvements by fudo.

          v2.3.5 - 12/21/20

          • Added resetTime, which tracks the time since a layer prestiged or was reset.
          • A layer node will be highlighted red if one of its subtabs is highlighted red.
          • Fixed issues with keeping challenges, buyables, and clickables on reset.
          • Improved the unlocking of custom layers.
          • Other minor fixes.

          v2.3.4 - 12/16/20

          • Added a node image feature.
          • Resource display now always shows the amount of the currency the layer's gain is based on.
          • Added spacing between tree nodes.
          • Another attempt to fix tooltip flickering.

          v2.3.3 - 12/13/20

          • Fixed the first node in a row always taking up space.
          • layerShown is now optional.
          • All prestige types can now use features for custom prestige types.

          v2.3.2 - 12/13/20

          • Fixed achievement/milestone popups.

          v2.3.1 - 12/12/20

          • Another attempt to fix flickering tooltips.
          • The "this" keyword should work everywhere except tabFormat arrays (although I may have missed some things).
          • Fixed tree branches not updating when scrolling on the right-side tab.
          • Fixed a spacing issue when a node's symbol is ""
          • Removed some old, unneeded files.

          v2.3: Cooler and Newer Edition - 12/10/20

          • Added achievement/milestone popups (thank you to Jacorb for this contribution!)
          • The changelog tab is back, and can be set in mod.js.
          • Layer nodes and respec buttons will not be clicked by pressing "enter".
          • Possible fix for flickering tooltips and strange transitions.
          • The victory screen text is configurable.
          • Added image and textStyle features to achievements.
          • Added an argument to use specific rows in an "upgrades" component.
          • Fixed the comma appearing in the main display when there was no effectDescription
          • Added the ability to easily make a tab that is a collection of layers in subtabs.
          • Improved spacing for embedding layers with subtabs into subtabs.

          v2.2.8 - 12/03/20

          • Double-clicking a layer node brings you to the main subtab for that layer.
          • Attempted to fix challenges visually updating a different way.
          • Added a softcap function for use in formulas.
          • Added displayRow feature, which lets layers be shown somewhere separate from where they are in the reset order (e.g. side layers)
          • Fixed autoupgrade issue.

          v2.2.7 - 11/30/20

          • Added autoUpgrade feature.
          • resource-display now shows resource gain per second if passiveGain is active.
          • Fixed formatting issues on some large numbers.
          • Better support for using classed objects in player and in layers/tmp.
          • Made hard resetting more effective.
          • Removed Herobrine from getStartClickables.

          v2.2.6 - 11/30/20

          • Added goalDescription for challenges and made the new "canComplete" system the standard.
          • Another attempt to fix challenges not visually updating.
          • Fixed side layers not appearing.
          • Fixed getStartClickables again.

          v2.2.5 - 11/29/20

          • Added features for overriding the displays and costs/goals of upgrades and challenges to make them fully custom.
          • best, total, and unlocked are always automatically added to layerData (but best and total will only display if you add them yourself).
          • Fixed getStartClickables.

          v2.2.4 - 11/28/20

          • Added softcap and softcapPower features (for Normal layers)
          • Offline time limit and default max tick length were fixed (previously the limits were 1000x too large)
          • Added fixOldSaves.
          • You can use HTML in main-display.
          • Fixed a number of minor oddities.

          v2.2.3 - 11/28/20

          • Layers will be highlighted if you can finish a challenge.
          • The "can complete challenge" color now overrides the "already completed" color.
          • Button nodes now work as side "layers".
          • Setting a tooltip to "" hides it entirely.

          v2.2.2 - 11/22/20

          • Fixed right half of the screen being unclickable in some circumstances.
          • Fixed tree branches being offset.
          • Fix to lastSafeTab.

          v2.2.1 - 11/7/20

          • Added a small highlight to layers you can meaningfully prestige on.
          • Added passiveGeneration and autoPrestige features to standardize prestige automation. (The old ways still work, but the new ones work better with other things)
          • Improved milestones visually a bit.
          • "best" and "total" are now only displayed if present in startData.
          • Fixed issues with things not updating visually. (Thank you to to Jacorb!)
          • Side layers and button nodes can now be highlighted.
          • Updated docs on the new tree-related features.

          v2.2: Uprooted - 11/7/20

          • You can now embed a layer inside of a subtab or microtab!
          • Added support for hiding or reformatting the tree tab
          • Added non-layer button nodes
          • Added shouldNotify to subtab/microtab buttons. (You can make them highlighted)
          • Added commas to large exponents.
          • Upgrades now only show "currently" if they have an effectDisplay (so not for constant effects).
          • Achievements are part of the default tab format.
          • NaN is now handled more intelligently.
          • Renamed files, and moved less relevant ones to another folder.
          • The "hide completed challenges" setting now only hides challenges at max completions.
          • Thank you to thepaperpilot for fixing errors in docs and improving the infobox appearance!
          • Many other minor fixes.

          v2.1.4 - 10/25/20

          • Added an infobox component. Thank you to thepaperpilot for this contribution!
          • Layer type is now optional, and defaults to "none".
          • Improved the look of bars and tab buttons.
          • Improved spacing between layer nodes (also thanks to thepaperpilot!)
          • Fixed the "blank" component breaking if only specifying the height.
          • Fixed some numbers not displaying with enough digits.
          • Made a few more things able to be functions.
          • A few other minor fixes.

          v2.1.3.1 - 10/21/20

          • Fixed the update function.

          v2.1.3 - 10/21/20

          • gainMult and gainExp are now optional.
          • Layer unlocking is now kept on reset.
          • Game should start up faster.
          • Layer updates now have a determined order and starts with earlier-rowed layers.
          • Automation now has a determined order and starts with later-rowed layers.
          • Fixed issues with resetting clickables and challenges.
          • Commas should no longer appear in the decimal places of a number.
          • Fixed potential issue in displaying the tree.

          v2.1.2 - 10/19/20

          • Added buyUpgrade function (buyUpg still works though)
          • Added author name to modInfo.
          • Fix to crash caused when the name of a subtab or microtab is changed.
          • Fixes to outdated information in docs.
          • Improvements to Discord links.
          • Thank you to thepaperpilot for contributing to this update!

          v2.1.1 - 10/17/20

          • Added resource-display component, which displays the base currency for the prestige layer, as well as the best and/or total of this layer's prestige currency.
          • Fixed the value for the base currency not updating in resource-display.

          v2.1: We should have thought of this sooner! - 10/17/20

          • Moved most of the code users will want to edit to mod.js, added documentation for it.
            • Specifically, modInfo, VERSION, canGenPoints, getPointGen, and maxTickLength
          • Added getStartPoints()
          • Added the ability to store non-layer-related data
          • Added the ability to display more things at the top of the tree tab below points.
          • Made the endgame condition customizable
          • Added "sell one" and "sell all" buttons for buyables.
          • Moved the old "game" to demo.js, and replaced it with a minimal game that won't cause issues when edited.
          • Fixed issues with version number
          • Fixed number formatting issue making things like "10e9" appear.

          v2.0.5 - 10/16/20

          • Made more features (including prestige parameters) able to be dynamic.
          • Layer nodes can be hidden but still take up space with "ghost" visibility
          • Added clickableEffect for real.
          • Fixed some visual issues with bars.
          • A few other minor tweaks and improvements.

          v2.0.4 - 10/16/20

          • Fixed HTML on buttons interfering with clicking on them.

          v2.0.3 - 10/16/20

          • Fixed hotkeys not displaying in info.
          • Fixed the game supressing all external hotkeys.
          • You can use more things as currencies for upgrade costs and challenge goals using currencyLocation.
          • Added maxTickLength, which can be used to prevent offline time or tab-switching from breaking time-limit based mechanics.
          • Made buyable respec buttons and clickable "master" buttons their own components, and gave them a hide/show feature.
          • Added a general "tooltip" feature for achievements.

          v2.0.2 - 10/15/20

          • Branches are now dynamic (they can be functions).
          • Fixed a crash related to offline time.
          • Fixed links being too wide.

          v2.0.1 - 10/15/20

          • Fixed side layers appearing multiple times.

          v2.0: The Pinnacle of Achievement Mountain - 10/15/20

          • Added progress bars, which are highly customizable and can be horizontal or vertical!
          • Added "side layers", displayed smaller and off to the side, and don't get reset by default. They can be used for global achievements and statistics. Speaking of which...
          • Added achievements!
          • Added clickables, a more generalized variant of buyables.
          • Almost every value in layer data can be either a function or a constant value!
          • Added support for multiple completions of challenges.
          • Added "none" prestige type, which removes the need for any other prestige-related features.
          • The points display and other gui elements stay at the top of the screen when the tree scrolls.
          • Added getter/setter functions for the amounts and effects of most Big Features
          • Moved modInfo to game.js, added a spot in modInfo for a Discord link, changelog link. Also added a separate mod version from the TMT version in VERSION.
          • Tree structure is based on layer data, no index.html editing is needed.
          • Tmp does not need to be manually updated.
          • You don't have to have the same amount of upgrades in every row (and challs and buyables)
          • "unlocked" is optional for all Big Components (defaults to true).
          • All displays will update correctly.
          • Changelog is no longer in index.html at all.
          • Generation of Points now happens in the main game loop
          • Changed the reset functions to make keeping things easier
          • Renamed many things to increase readability (see the list in the link below)
          • Improved documentation based on feedback

          v1.3.5:

          • Completely automated convertToDecimal, now you never have to worry about it again.
          • Branches can be defined without a color id. But they can also use hex values for color ids!
          • Created a tutorial for getting started with TMT and Github.
          • Page title is now automatically taken from mod name.

          v1.3.4 - 10/8/20

          • Added "midsection" feature to add things to a tab's layout while still keeping the standard layout.
          • Fix for being able to buy more buyables than you should.

          v1.3.3 - 10/7/20

          • Fix for the "order of operations" issue in temp.

          v1.3.1 - 10/7/20

          • Added custom CSS and tooltips for Layer Nodes.
          • Added custom CSS for upgrades, buyables, milestones, and challenges, both individually and layer-wide.
          • You can now use HTML in most display text!
          • You can now make milestones unlockable and not display immediately.
          • Fixed importing saves, and issue with upgrades not appearing, and probably more.
          • Optional "name" layer feature, used in confirmation messages.

          v1.3: Tabception... ception! - 10/7/20

          • Added subtabs! And also a Micro-tab component to let you make smaller subtab-esque areas anywhere.
          • Added a "custom" prestige formula type, and a number of features to support it.
          • Added points/sec display (can be disabled).
          • Added h-line, v-line and image-display components, plus components for individual upgrades, challenges, and milestones.
          • Added upgEffect, buyableEffect, and challEffect functions.
          • Added "hide completed challenges" setting.
          • Moved old changelogs to a separate place.
          • Fixed hasMilestone and incr_order.
          • Static layers now show the currency amount needed for the next one if you can buy max.

          v1.2.4 - 10/4/20

          • Layers are now highlighted if you can buy an upgrade, and a new feature, shouldNotify, lets you make it highlight other ways.
          • Fixed bugs with hasUpg, hasChall, hasMilestone, and inChallenge.
          • Changed the sample code to use the above functions for convenience.

          v1.2.3 - 10/3/20

          • Added a row component, which displays a list of objects in a row.
          • Added a column component, which displays a list of objects in a column (useful within a row).
          • Changed blanks to have a customizable width and height.

          v1.2: This Changes Everything! - 10/3/20

          • Many layer features can now be static values or functions. (This made some formats change, which will break old things)
          • You can now use the "this" keyword, to make code easier to transfer when making new layers.
          • Also added "this.layer", which is the current layer's name, and works on existing subfeatures (e.g. individual upgrades) as well! Subfeatures also have "this.id".
          • Fixed a big save issue. If you use a unique mod id, your save will never conflict with other mods.
          • Added a configurable offline time limit in modinfo at the top of index.html. (default 1 hour)
          • Added a few minor features, and updated the docs with new information.

          v1.1.1 - 9/30/20

          • You can define hotkeys directly from layer config.

          v1.1: Enhanced Edition - 9/30/20

          • Added "Buyables", which can function like Space Buildings or Enhancers.
          • Custom CSS can now be used on any component! Make the third argument an object with CSS parameters.
          • Lots of minor good things.

          v1.0 - 9/27/20

          • First release.
          - +
          Skip to content

          The Modding Tree changelog:

          v2.5.9.2 - 5/19/21

          • Fixed many issues with things not updating.

          v2.5.9.1 - 5/18/21

          • Made text inputs never give NaNs.

          v2.5.9 - 5/18/21

          • Fixed issue when using text inputs for Numbers.
          • Added particle color feature.
          • Particle speed and dir are updated as it moves.
          • Added setSpeed and setDir for particles.
          • Added more trig functions.

          v2.5.8 - 5/17/21

          • Added makeShinies, which creates a stationary particle in a random spot.
          • Bars will visually update more quickly.
          • Fixed a major particle-related issue.
          • Fixed autoUpgrade.
          • Fixed a minor visual issue with tree nodes.

          v2.5.7 - 5/15/21

          • Added a particle system! Not only can it be used for visual effects, but particles can interact with the mouse. They could be used to create golden cookies or collectables, for example.
          • Added marked feature to buyables, clickables, and challenges. By default, stars multi-completion challenges when maxed.
          • Added 'deactivated' feature to layers, which disables many features.
          • Improved number formatting slightly.

          v2.5.6 - 5/14/21

          • You can now use non-numeric ids for upgrades, buyables, etc.
          • Fixed an exploit that let you buy an extra buyable.
          • Moved basic getter/setter functions to easyAccess.js.

          v2.5.5.2 - 5/12/21

          • Fixed a major issue with buyables.
          • Fixed a variety of tabFormat-related issues.
          • Fixed commas appearing in decimal places (thanks to pg132!)

          v2.5.5.1 - 5/12/21

          • Fixed clickables.

          v2.5.5 - 5/12/21

          • Added grids! They are a grid of buttons which behave the same, but have their own data. Good for inventory grids, map tiles, and more!
          • Added "marked" feature to add a mark to a node. Can be an image instead of a star. (Originally by Jacorb)
          • Added "layer-proxy" component that lets you use components from another layer.
          • Added the ability to display non-whole numbers in main-display.

          v2.5.4 - 5/10/21

          • Added a setting to always use single-tab mode.
          • Added directMult, which multiplies prestige gain after exponents and softcaps. It actually multiplies gain for static layers.
          • Added onEnter and onExit for challenges.
          • Improved displaying numbers between 0.0001 and 0.1.
          • Added documentation on how gainMult/Exp work for static layers.
          • Fixed a visual issue on mobile, thanks to thepaperpilot.
          • Improved documentation in general.

          v2.5.3 - 5/8/21

          • Improved performance of tab formats and bars.
          • Respec confirmation settings are now kept on resets.
          • Improved compatibility with older browsers.
          • Fixed missing pixel on vertical bars.

          v2.5.2.1 - 5/7/21

          • Fixed microtabs making layers highlight incorrectly.

          v2.5.2 - 5/7/21

          • Added glowColor for subtabs.
          • Improved the display for extremely small numbers.
          • Fixed issues in the buyable docs.

          v2.5.1 - 5/7/21

          • Fixed dynamic things in tabFormat not updating.

          v2.5: Dreams Really Do Come True - 5/7/21

          • Optimizations, hopefully a significant amount.
          • Added OOM/s point gen display at high values (thanks to Ducdat!)
          • Only one tab will display if the window is not wide enough (also thanks to Ducdat!)
          • Holding down a buyable's button now buys it continuously.
          • New milestone setting will also show the most recently unlocked milestone. (Also renamed all settings to be clearer)
          • Added an onHold feature for clickables.
          • Layer nodes will be highlighted even if the player is on the same tab.
          • Added customizable node glowColor.
          • Added buyable purchaseLimit.
          • Amount is automatically supplied to buyable cost and effect functions.
          • Locked (not yet visible) milestones no longer take up space. Also fixed hidden milestones taking a tiny bit of space.
          • Re-centered respec buttons.
          • Force-displayed tooltips are not hidden by resets.
          • Added formatting support for very small numbers. Disabled in most places by default because rounding errors might cause issues. Access it with formatSmall, or enable it globally by adding "allowSmall: true" to modInfo.

          v2.4.1 - 4/29/21

          • A number of minor fixes, many thanks to thepaperpilot.
          • The respec confirmation checkbox is now part of the respec-button component. (This also fixes the checkbox appearing when there is no respec button)
          • Added a few undocumented changes to the 2.4 changelog (the two at the bottom)

          v2.4: Rationalized Edition - 4/29/21

          • Completely reworked tooltips. Shift-click a node to force its tooltip to stay displayed. (And hopefully finally fixed flickering!)

          • Added text-input and slider components.

          • Added the ability to toggle respec confirmations.

          • Added custom respec confirmation messages.

          • The red layer highlight will not appear before a layer is unlocked.

          • Added unlocking hotkeys.

          • You no longer need to supply 'rows' and 'cols' for any Big Features.

          • Node symbols can use HTML.

          • Added documentation for the respec button.

          • Added prestigeNotify to subtabs, and prestigeNotify in subtabs also highlights the layer node.

          • The version number no longer contains special characters or irrational numbers.

          • Added ctrlDown and shiftDown variables.

          • Tooltips now use HTML (this means you need to replace any newlines with
            )

          v2.π.1 - 4/7/21

          • Fixed formatting for some larger numbers.
          • Upgrades will expand if there is too much text to display.
          • Fixed styling challenges.
          • No longer attempts to display a base currency when there is none.

          v2.π: Incrementally Updated - 2/5/21

          • Performance improvements.
          • Fixed tooltips overlapping with the top display.
          • Clicking a popup dismisses it immediately.
          • Added support for bulk challenge completions.
          • "Best" is updated automatically.
          • Fixed keeping Decimal values on reset.
          • Code reorganization and style improvements by fudo.

          v2.3.5 - 12/21/20

          • Added resetTime, which tracks the time since a layer prestiged or was reset.
          • A layer node will be highlighted red if one of its subtabs is highlighted red.
          • Fixed issues with keeping challenges, buyables, and clickables on reset.
          • Improved the unlocking of custom layers.
          • Other minor fixes.

          v2.3.4 - 12/16/20

          • Added a node image feature.
          • Resource display now always shows the amount of the currency the layer's gain is based on.
          • Added spacing between tree nodes.
          • Another attempt to fix tooltip flickering.

          v2.3.3 - 12/13/20

          • Fixed the first node in a row always taking up space.
          • layerShown is now optional.
          • All prestige types can now use features for custom prestige types.

          v2.3.2 - 12/13/20

          • Fixed achievement/milestone popups.

          v2.3.1 - 12/12/20

          • Another attempt to fix flickering tooltips.
          • The "this" keyword should work everywhere except tabFormat arrays (although I may have missed some things).
          • Fixed tree branches not updating when scrolling on the right-side tab.
          • Fixed a spacing issue when a node's symbol is ""
          • Removed some old, unneeded files.

          v2.3: Cooler and Newer Edition - 12/10/20

          • Added achievement/milestone popups (thank you to Jacorb for this contribution!)
          • The changelog tab is back, and can be set in mod.js.
          • Layer nodes and respec buttons will not be clicked by pressing "enter".
          • Possible fix for flickering tooltips and strange transitions.
          • The victory screen text is configurable.
          • Added image and textStyle features to achievements.
          • Added an argument to use specific rows in an "upgrades" component.
          • Fixed the comma appearing in the main display when there was no effectDescription
          • Added the ability to easily make a tab that is a collection of layers in subtabs.
          • Improved spacing for embedding layers with subtabs into subtabs.

          v2.2.8 - 12/03/20

          • Double-clicking a layer node brings you to the main subtab for that layer.
          • Attempted to fix challenges visually updating a different way.
          • Added a softcap function for use in formulas.
          • Added displayRow feature, which lets layers be shown somewhere separate from where they are in the reset order (e.g. side layers)
          • Fixed autoupgrade issue.

          v2.2.7 - 11/30/20

          • Added autoUpgrade feature.
          • resource-display now shows resource gain per second if passiveGain is active.
          • Fixed formatting issues on some large numbers.
          • Better support for using classed objects in player and in layers/tmp.
          • Made hard resetting more effective.
          • Removed Herobrine from getStartClickables.

          v2.2.6 - 11/30/20

          • Added goalDescription for challenges and made the new "canComplete" system the standard.
          • Another attempt to fix challenges not visually updating.
          • Fixed side layers not appearing.
          • Fixed getStartClickables again.

          v2.2.5 - 11/29/20

          • Added features for overriding the displays and costs/goals of upgrades and challenges to make them fully custom.
          • best, total, and unlocked are always automatically added to layerData (but best and total will only display if you add them yourself).
          • Fixed getStartClickables.

          v2.2.4 - 11/28/20

          • Added softcap and softcapPower features (for Normal layers)
          • Offline time limit and default max tick length were fixed (previously the limits were 1000x too large)
          • Added fixOldSaves.
          • You can use HTML in main-display.
          • Fixed a number of minor oddities.

          v2.2.3 - 11/28/20

          • Layers will be highlighted if you can finish a challenge.
          • The "can complete challenge" color now overrides the "already completed" color.
          • Button nodes now work as side "layers".
          • Setting a tooltip to "" hides it entirely.

          v2.2.2 - 11/22/20

          • Fixed right half of the screen being unclickable in some circumstances.
          • Fixed tree branches being offset.
          • Fix to lastSafeTab.

          v2.2.1 - 11/7/20

          • Added a small highlight to layers you can meaningfully prestige on.
          • Added passiveGeneration and autoPrestige features to standardize prestige automation. (The old ways still work, but the new ones work better with other things)
          • Improved milestones visually a bit.
          • "best" and "total" are now only displayed if present in startData.
          • Fixed issues with things not updating visually. (Thank you to to Jacorb!)
          • Side layers and button nodes can now be highlighted.
          • Updated docs on the new tree-related features.

          v2.2: Uprooted - 11/7/20

          • You can now embed a layer inside of a subtab or microtab!
          • Added support for hiding or reformatting the tree tab
          • Added non-layer button nodes
          • Added shouldNotify to subtab/microtab buttons. (You can make them highlighted)
          • Added commas to large exponents.
          • Upgrades now only show "currently" if they have an effectDisplay (so not for constant effects).
          • Achievements are part of the default tab format.
          • NaN is now handled more intelligently.
          • Renamed files, and moved less relevant ones to another folder.
          • The "hide completed challenges" setting now only hides challenges at max completions.
          • Thank you to thepaperpilot for fixing errors in docs and improving the infobox appearance!
          • Many other minor fixes.

          v2.1.4 - 10/25/20

          • Added an infobox component. Thank you to thepaperpilot for this contribution!
          • Layer type is now optional, and defaults to "none".
          • Improved the look of bars and tab buttons.
          • Improved spacing between layer nodes (also thanks to thepaperpilot!)
          • Fixed the "blank" component breaking if only specifying the height.
          • Fixed some numbers not displaying with enough digits.
          • Made a few more things able to be functions.
          • A few other minor fixes.

          v2.1.3.1 - 10/21/20

          • Fixed the update function.

          v2.1.3 - 10/21/20

          • gainMult and gainExp are now optional.
          • Layer unlocking is now kept on reset.
          • Game should start up faster.
          • Layer updates now have a determined order and starts with earlier-rowed layers.
          • Automation now has a determined order and starts with later-rowed layers.
          • Fixed issues with resetting clickables and challenges.
          • Commas should no longer appear in the decimal places of a number.
          • Fixed potential issue in displaying the tree.

          v2.1.2 - 10/19/20

          • Added buyUpgrade function (buyUpg still works though)
          • Added author name to modInfo.
          • Fix to crash caused when the name of a subtab or microtab is changed.
          • Fixes to outdated information in docs.
          • Improvements to Discord links.
          • Thank you to thepaperpilot for contributing to this update!

          v2.1.1 - 10/17/20

          • Added resource-display component, which displays the base currency for the prestige layer, as well as the best and/or total of this layer's prestige currency.
          • Fixed the value for the base currency not updating in resource-display.

          v2.1: We should have thought of this sooner! - 10/17/20

          • Moved most of the code users will want to edit to mod.js, added documentation for it.
            • Specifically, modInfo, VERSION, canGenPoints, getPointGen, and maxTickLength
          • Added getStartPoints()
          • Added the ability to store non-layer-related data
          • Added the ability to display more things at the top of the tree tab below points.
          • Made the endgame condition customizable
          • Added "sell one" and "sell all" buttons for buyables.
          • Moved the old "game" to demo.js, and replaced it with a minimal game that won't cause issues when edited.
          • Fixed issues with version number
          • Fixed number formatting issue making things like "10e9" appear.

          v2.0.5 - 10/16/20

          • Made more features (including prestige parameters) able to be dynamic.
          • Layer nodes can be hidden but still take up space with "ghost" visibility
          • Added clickableEffect for real.
          • Fixed some visual issues with bars.
          • A few other minor tweaks and improvements.

          v2.0.4 - 10/16/20

          • Fixed HTML on buttons interfering with clicking on them.

          v2.0.3 - 10/16/20

          • Fixed hotkeys not displaying in info.
          • Fixed the game supressing all external hotkeys.
          • You can use more things as currencies for upgrade costs and challenge goals using currencyLocation.
          • Added maxTickLength, which can be used to prevent offline time or tab-switching from breaking time-limit based mechanics.
          • Made buyable respec buttons and clickable "master" buttons their own components, and gave them a hide/show feature.
          • Added a general "tooltip" feature for achievements.

          v2.0.2 - 10/15/20

          • Branches are now dynamic (they can be functions).
          • Fixed a crash related to offline time.
          • Fixed links being too wide.

          v2.0.1 - 10/15/20

          • Fixed side layers appearing multiple times.

          v2.0: The Pinnacle of Achievement Mountain - 10/15/20

          • Added progress bars, which are highly customizable and can be horizontal or vertical!
          • Added "side layers", displayed smaller and off to the side, and don't get reset by default. They can be used for global achievements and statistics. Speaking of which...
          • Added achievements!
          • Added clickables, a more generalized variant of buyables.
          • Almost every value in layer data can be either a function or a constant value!
          • Added support for multiple completions of challenges.
          • Added "none" prestige type, which removes the need for any other prestige-related features.
          • The points display and other gui elements stay at the top of the screen when the tree scrolls.
          • Added getter/setter functions for the amounts and effects of most Big Features
          • Moved modInfo to game.js, added a spot in modInfo for a Discord link, changelog link. Also added a separate mod version from the TMT version in VERSION.
          • Tree structure is based on layer data, no index.html editing is needed.
          • Tmp does not need to be manually updated.
          • You don't have to have the same amount of upgrades in every row (and challs and buyables)
          • "unlocked" is optional for all Big Components (defaults to true).
          • All displays will update correctly.
          • Changelog is no longer in index.html at all.
          • Generation of Points now happens in the main game loop
          • Changed the reset functions to make keeping things easier
          • Renamed many things to increase readability (see the list in the link below)
          • Improved documentation based on feedback

          v1.3.5:

          • Completely automated convertToDecimal, now you never have to worry about it again.
          • Branches can be defined without a color id. But they can also use hex values for color ids!
          • Created a tutorial for getting started with TMT and Github.
          • Page title is now automatically taken from mod name.

          v1.3.4 - 10/8/20

          • Added "midsection" feature to add things to a tab's layout while still keeping the standard layout.
          • Fix for being able to buy more buyables than you should.

          v1.3.3 - 10/7/20

          • Fix for the "order of operations" issue in temp.

          v1.3.1 - 10/7/20

          • Added custom CSS and tooltips for Layer Nodes.
          • Added custom CSS for upgrades, buyables, milestones, and challenges, both individually and layer-wide.
          • You can now use HTML in most display text!
          • You can now make milestones unlockable and not display immediately.
          • Fixed importing saves, and issue with upgrades not appearing, and probably more.
          • Optional "name" layer feature, used in confirmation messages.

          v1.3: Tabception... ception! - 10/7/20

          • Added subtabs! And also a Micro-tab component to let you make smaller subtab-esque areas anywhere.
          • Added a "custom" prestige formula type, and a number of features to support it.
          • Added points/sec display (can be disabled).
          • Added h-line, v-line and image-display components, plus components for individual upgrades, challenges, and milestones.
          • Added upgEffect, buyableEffect, and challEffect functions.
          • Added "hide completed challenges" setting.
          • Moved old changelogs to a separate place.
          • Fixed hasMilestone and incr_order.
          • Static layers now show the currency amount needed for the next one if you can buy max.

          v1.2.4 - 10/4/20

          • Layers are now highlighted if you can buy an upgrade, and a new feature, shouldNotify, lets you make it highlight other ways.
          • Fixed bugs with hasUpg, hasChall, hasMilestone, and inChallenge.
          • Changed the sample code to use the above functions for convenience.

          v1.2.3 - 10/3/20

          • Added a row component, which displays a list of objects in a row.
          • Added a column component, which displays a list of objects in a column (useful within a row).
          • Changed blanks to have a customizable width and height.

          v1.2: This Changes Everything! - 10/3/20

          • Many layer features can now be static values or functions. (This made some formats change, which will break old things)
          • You can now use the "this" keyword, to make code easier to transfer when making new layers.
          • Also added "this.layer", which is the current layer's name, and works on existing subfeatures (e.g. individual upgrades) as well! Subfeatures also have "this.id".
          • Fixed a big save issue. If you use a unique mod id, your save will never conflict with other mods.
          • Added a configurable offline time limit in modinfo at the top of index.html. (default 1 hour)
          • Added a few minor features, and updated the docs with new information.

          v1.1.1 - 9/30/20

          • You can define hotkeys directly from layer config.

          v1.1: Enhanced Edition - 9/30/20

          • Added "Buyables", which can function like Space Buildings or Enhancers.
          • Custom CSS can now be used on any component! Make the third argument an object with CSS parameters.
          • Lots of minor good things.

          v1.0 - 9/27/20

          • First release.
          + \ No newline at end of file diff --git a/public/kronos/docs/!general-info.html b/public/kronos/docs/!general-info.html index 50734eea..3583f7f4 100644 --- a/public/kronos/docs/!general-info.html +++ b/public/kronos/docs/!general-info.html @@ -6,13 +6,13 @@ The-Modding-Tree | The Paper Pilot - + - + - - - + + + @@ -34,8 +34,8 @@ -
          Skip to content

          The-Modding-Tree

          Making a game in The Modding Tree mostly involves defining parameters or functions on objects. If you aren't following the getting started guide, you should start by setting up your basic mod info in mod.js. It's important to set a mod id to ensure saving works properly.

          Beyond that, the main way to add content is through creating layers, often in layers.js. You can add new layers by calling addLayer(layername, layerdata). There is an example of a basic layer in layers.js showing the recommended method. It is just an example and can be freely deleted. You can also use it as a reference or a base for your own layers.

          Most of the time, you won't need to dive deep into the code to create things, but you still can if you really want to, for example to add new Vue components in components.js.

          The Modding Tree uses break_eternity.js to store large values. This means that many numbers are Decimal objects, and must be treated differently. For example, you have to use new Decimal(x) to create a Decimal value instead of a plain number, and perform operations on them by calling functions. e.g, instead of x = x + y, use x = x.add(y). Keep in mind this also applies to comparison operators, which should be replaced with calling the .gt, .gte, .lt, .lte, .eq, and .neq functions. See the break_eternity.js docs for more details on working with Decimal values.

          Almost all values can be either a constant value, or a dynamic value. Dynamic values are defined by putting a function that returns what the value should be at any given time.

          All display text can use basic HTML elements (But you can't use most Vue features there).

          While reading this documentation, the following key will be used when describing features:

          • No label: This is required and the game may crash if it isn't included.
          • sometimes required: This is may be required, depending on other things in the layer.
          • optional: You can leave this out if you don't intend to use that feature for the layer.
          • assigned automagically: This value will be set automatically and override any value you set.
          • deprecated: This feature is not recommended to be used, because newer features are able to achieve the same thing in a better, easier way.

          Table of Contents

          General

          • Getting Started: Getting your own copy of the code set up with Github Desktop.
          • Main mod info: How to set up general things for your mod in mod.js.
          • Basic layer breakdown: Breaking down the components of a layer with minimal features.
          • Layer features: Explanations of all of the different properties that you can give a layer.
          • Custom Tab Layouts: An optional way to give your tabs a different layout. You can even create entirely new components to use.
          • Custom game layouts: You can get rid of the tree tab, add buttons and other things to the tree, or even customize the tab's layout like a layer tab.
          • Updating TMT: Using Github Desktop to update your mod's version of TMT.

          Common components

          • Upgrades: How to create upgrades for a layer.
          • Milestones: How to create milestones for a layer.
          • Buyables: Create rebuyable upgrades for your layer (with the option to make them respec-able). Can be used to make Enhancers or Space Buildings, for example.
          • Clickables: A more generalized variant of buyables, for any kind of thing that is sometimes clickable. Between these and Buyables, you can do just about anything.
          • Achievements: How to create achievements for a layer (or for the whole game).

          Other components and features

          • Challenges: How to create challenges for a layer.
          • Bars: Display some information as a progress bar, gauge, or similar. They are highly customizable, and can be horizontal and vertical as well.
          • Subtabs and Microtabs: Create subtabs for your tabs, as well as "microtab" components that you can put inside the tabs. You can even use them to embed a layer inside another layer!
          • [Grids][grids.md]: Create a group buttons that behave the same, but have their own data. Good for map tiles, an inventory grid, and more!
          • Infoboxes: Boxes containing text that can be shown or hidden.
          • Trees: Make your own trees. You can make non-layer button nodes too!
          • Particle system: Can be used to create particles for visual effects, but also interactable things like golden cookies or collectables.
          - +
          Skip to content

          The-Modding-Tree

          Making a game in The Modding Tree mostly involves defining parameters or functions on objects. If you aren't following the getting started guide, you should start by setting up your basic mod info in mod.js. It's important to set a mod id to ensure saving works properly.

          Beyond that, the main way to add content is through creating layers, often in layers.js. You can add new layers by calling addLayer(layername, layerdata). There is an example of a basic layer in layers.js showing the recommended method. It is just an example and can be freely deleted. You can also use it as a reference or a base for your own layers.

          Most of the time, you won't need to dive deep into the code to create things, but you still can if you really want to, for example to add new Vue components in components.js.

          The Modding Tree uses break_eternity.js to store large values. This means that many numbers are Decimal objects, and must be treated differently. For example, you have to use new Decimal(x) to create a Decimal value instead of a plain number, and perform operations on them by calling functions. e.g, instead of x = x + y, use x = x.add(y). Keep in mind this also applies to comparison operators, which should be replaced with calling the .gt, .gte, .lt, .lte, .eq, and .neq functions. See the break_eternity.js docs for more details on working with Decimal values.

          Almost all values can be either a constant value, or a dynamic value. Dynamic values are defined by putting a function that returns what the value should be at any given time.

          All display text can use basic HTML elements (But you can't use most Vue features there).

          While reading this documentation, the following key will be used when describing features:

          • No label: This is required and the game may crash if it isn't included.
          • sometimes required: This is may be required, depending on other things in the layer.
          • optional: You can leave this out if you don't intend to use that feature for the layer.
          • assigned automagically: This value will be set automatically and override any value you set.
          • deprecated: This feature is not recommended to be used, because newer features are able to achieve the same thing in a better, easier way.

          Table of Contents

          General

          • Getting Started: Getting your own copy of the code set up with Github Desktop.
          • Main mod info: How to set up general things for your mod in mod.js.
          • Basic layer breakdown: Breaking down the components of a layer with minimal features.
          • Layer features: Explanations of all of the different properties that you can give a layer.
          • Custom Tab Layouts: An optional way to give your tabs a different layout. You can even create entirely new components to use.
          • Custom game layouts: You can get rid of the tree tab, add buttons and other things to the tree, or even customize the tab's layout like a layer tab.
          • Updating TMT: Using Github Desktop to update your mod's version of TMT.

          Common components

          • Upgrades: How to create upgrades for a layer.
          • Milestones: How to create milestones for a layer.
          • Buyables: Create rebuyable upgrades for your layer (with the option to make them respec-able). Can be used to make Enhancers or Space Buildings, for example.
          • Clickables: A more generalized variant of buyables, for any kind of thing that is sometimes clickable. Between these and Buyables, you can do just about anything.
          • Achievements: How to create achievements for a layer (or for the whole game).

          Other components and features

          • Challenges: How to create challenges for a layer.
          • Bars: Display some information as a progress bar, gauge, or similar. They are highly customizable, and can be horizontal and vertical as well.
          • Subtabs and Microtabs: Create subtabs for your tabs, as well as "microtab" components that you can put inside the tabs. You can even use them to embed a layer inside another layer!
          • [Grids][grids.md]: Create a group buttons that behave the same, but have their own data. Good for map tiles, an inventory grid, and more!
          • Infoboxes: Boxes containing text that can be shown or hidden.
          • Trees: Make your own trees. You can make non-layer button nodes too!
          • Particle system: Can be used to create particles for visual effects, but also interactable things like golden cookies or collectables.
          + \ No newline at end of file diff --git a/public/kronos/docs/achievements.html b/public/kronos/docs/achievements.html index c3521cd5..426a20c3 100644 --- a/public/kronos/docs/achievements.html +++ b/public/kronos/docs/achievements.html @@ -6,13 +6,13 @@ Achievements | The Paper Pilot - + - + - - - + + + @@ -34,14 +34,14 @@ -
          Skip to content

          Achievements

          Achievements are awarded to the player when they meet a certain goal, and optionally give some benefit.

          You can make global achievements by putting them in a side layer by making its row equal to "side" instead of a number.

          Useful functions for dealing with achievements and implementing their effects:

          • hasAchievement(layer, id): determine if the player has the Achievement.
          • achievementEffect(layer, id): Returns the current effects of the achievement, if any.

          Achievements should be formatted like this:

          js
          achievements: {
          +    
          Skip to content

          Achievements

          Achievements are awarded to the player when they meet a certain goal, and optionally give some benefit.

          You can make global achievements by putting them in a side layer by making its row equal to "side" instead of a number.

          Useful functions for dealing with achievements and implementing their effects:

          • hasAchievement(layer, id): determine if the player has the Achievement.
          • achievementEffect(layer, id): Returns the current effects of the achievement, if any.

          Achievements should be formatted like this:

          js
          achievements: {
               11: {
                   name: "Blah",
                   more features
               },
               etc
          -}

          Usually, each achievement should have an id where the first digit is the row and the second digit is the column.

          Individual achievement can have these features:

          • name: optional. displayed at the top of the achievement. The only visible text. It can also be a function that returns updating text. Can use basic HTML.

          • done(): A function returning a boolean to determine if the achievement should be awarded.

          • tooltip: Default tooltip for the achievement, appears when it is hovered over. Should convey the goal and any reward for completing the achievement. It can also be a function that returns updating text. Can use basic HTML. Setting this to "" disables the tooltip.

          • effect(): optional. A function that calculates and returns the current values of any bonuses from the achievement. Can return a value or an object containing multiple values.

          • unlocked(): optional. A function returning a bool to determine if the achievement is visible or not. Default is unlocked.

          • onComplete() - optional. this function will be called when the achievement is completed.

          • image: optional, puts the image from the given URL (relative or absolute) in the achievement

          • style: optional. Applies CSS to this achievement, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • textStyle: optional. Applies CSS to the text, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the achievement was stored under, for convenient access. The achievement in the example's id is 11.

          • goalTooltip: optional, deprecated. Appears when the achievement is hovered over and locked, overrides the basic tooltip. This is to display the goal (or a hint). It can also be a function that returns updating text. Can use basic HTML.

          • doneTooltip: optional, deprecated. Appears when the achievement is hovered over and completed, overrides the basic tooltip. This can display what the player achieved (the goal), and the rewards, if any. It can also be a function that returns updating text. Can use basic HTML.

          Disable achievement popups by adding achievementsPopups: false to the layer.

          - +}

          Usually, each achievement should have an id where the first digit is the row and the second digit is the column.

          Individual achievement can have these features:

          • name: optional. displayed at the top of the achievement. The only visible text. It can also be a function that returns updating text. Can use basic HTML.

          • done(): A function returning a boolean to determine if the achievement should be awarded.

          • tooltip: Default tooltip for the achievement, appears when it is hovered over. Should convey the goal and any reward for completing the achievement. It can also be a function that returns updating text. Can use basic HTML. Setting this to "" disables the tooltip.

          • effect(): optional. A function that calculates and returns the current values of any bonuses from the achievement. Can return a value or an object containing multiple values.

          • unlocked(): optional. A function returning a bool to determine if the achievement is visible or not. Default is unlocked.

          • onComplete() - optional. this function will be called when the achievement is completed.

          • image: optional, puts the image from the given URL (relative or absolute) in the achievement

          • style: optional. Applies CSS to this achievement, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • textStyle: optional. Applies CSS to the text, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the achievement was stored under, for convenient access. The achievement in the example's id is 11.

          • goalTooltip: optional, deprecated. Appears when the achievement is hovered over and locked, overrides the basic tooltip. This is to display the goal (or a hint). It can also be a function that returns updating text. Can use basic HTML.

          • doneTooltip: optional, deprecated. Appears when the achievement is hovered over and completed, overrides the basic tooltip. This can display what the player achieved (the goal), and the rewards, if any. It can also be a function that returns updating text. Can use basic HTML.

          Disable achievement popups by adding achievementsPopups: false to the layer.

          + \ No newline at end of file diff --git a/public/kronos/docs/bars.html b/public/kronos/docs/bars.html index da56f220..814e5736 100644 --- a/public/kronos/docs/bars.html +++ b/public/kronos/docs/bars.html @@ -6,13 +6,13 @@ Bars | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
          Skip to content

          Bars

          Bars let you display information in a more direct way. It can be a progress bar, health bar, capacity gauge, or anything else.

          Bars are defined like other Big Features:

          js
          bars: {
          +    
          Skip to content

          Bars

          Bars let you display information in a more direct way. It can be a progress bar, health bar, capacity gauge, or anything else.

          Bars are defined like other Big Features:

          js
          bars: {
               bigBar: {
                   direction: RIGHT,
                   width: 200,
          @@ -43,8 +43,8 @@
                   etc
               },
               etc
          -}

          Features:

          • direction: UP, DOWN, LEFT, or RIGHT (not strings). Determines the direction that the bar is filled as it progresses. RIGHT means from left to right.

          • width, height: The size in pixels of the bar, but as numbers (no "px" at the end).

          • progress(): A function that returns the portion of the bar that is filled, from "empty" at 0 to "full" at 1, updating automatically. (Nothing bad happens if the value goes out of these bounds, and it can be a number or Decimal)

          • display(): optional. A function that returns text to be displayed on top of the bar, can use HTML.

          • unlocked(): optional. A function returning a bool to determine if the bar is visible or not. Default is unlocked.

          • baseStyle, fillStyle, borderStyle, textStyle: Optional, Apply CSS to the unfilled portion, filled portion, border, and display text on the bar, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the bar was stored under, for convenient access. The bar in the example's id is "bigBar".

          - +}

          Features:

          • direction: UP, DOWN, LEFT, or RIGHT (not strings). Determines the direction that the bar is filled as it progresses. RIGHT means from left to right.

          • width, height: The size in pixels of the bar, but as numbers (no "px" at the end).

          • progress(): A function that returns the portion of the bar that is filled, from "empty" at 0 to "full" at 1, updating automatically. (Nothing bad happens if the value goes out of these bounds, and it can be a number or Decimal)

          • display(): optional. A function that returns text to be displayed on top of the bar, can use HTML.

          • unlocked(): optional. A function returning a bool to determine if the bar is visible or not. Default is unlocked.

          • baseStyle, fillStyle, borderStyle, textStyle: Optional, Apply CSS to the unfilled portion, filled portion, border, and display text on the bar, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the bar was stored under, for convenient access. The bar in the example's id is "bigBar".

          + \ No newline at end of file diff --git a/public/kronos/docs/basic-layer-breakdown.html b/public/kronos/docs/basic-layer-breakdown.html index 902ad31e..2d53e865 100644 --- a/public/kronos/docs/basic-layer-breakdown.html +++ b/public/kronos/docs/basic-layer-breakdown.html @@ -6,13 +6,13 @@ Basic layer breakdown | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
          Skip to content

          Basic layer breakdown

          This is a very minimal layer with minimal features. Most things will require additional features.

          js
          addLayer("p", {
          +    
          Skip to content

          Basic layer breakdown

          This is a very minimal layer with minimal features. Most things will require additional features.

          js
          addLayer("p", {
               startData() { return {                  // startData is a function that returns default data for a layer. 
                   unlocked: true,                     // You can add more variables here to add them to your layer.
                   points: new Decimal(0),             // "points" is the internal name for the main resource of the layer.
          @@ -65,8 +65,8 @@
               upgrades: {
                   // Look in the upgrades docs to see what goes here!
               },
          -})
          - +})
          + \ No newline at end of file diff --git a/public/kronos/docs/buyables.html b/public/kronos/docs/buyables.html index 42245d7a..65b322b1 100644 --- a/public/kronos/docs/buyables.html +++ b/public/kronos/docs/buyables.html @@ -6,13 +6,13 @@ Buyables | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
          Skip to content

          Buyables

          Buyables are usually things that can be bought multiple times with scaling costs. They come with optional buttons that can be used for respeccing or selling buyables, among other things.

          The amount of a buyable owned is a Decimal.

          Useful functions for dealing with buyables and implementing their effects:

          • getBuyableAmount(layer, id): get the amount of the buyable the player has
          • setBuyableAmount(layer, id, amount): set the amount of the buyable the player has
          • buyableEffect(layer, id): Returns the current effects of the buyable, if any.

          Buyables should be formatted like this:

          js
          buyables: {
          +    
          Skip to content

          Buyables

          Buyables are usually things that can be bought multiple times with scaling costs. They come with optional buttons that can be used for respeccing or selling buyables, among other things.

          The amount of a buyable owned is a Decimal.

          Useful functions for dealing with buyables and implementing their effects:

          • getBuyableAmount(layer, id): get the amount of the buyable the player has
          • setBuyableAmount(layer, id, amount): set the amount of the buyable the player has
          • buyableEffect(layer, id): Returns the current effects of the buyable, if any.

          Buyables should be formatted like this:

          js
          buyables: {
               11: {
                   cost(x) { return new Decimal(1).mul(x) },
                   display() { return "Blah" },
          @@ -46,8 +46,8 @@
                   etc
               },
               etc
          -}

          Features:

          • title: optional. displayed at the top in a larger font. It can also be a function that returns updating text.

          • cost(): cost for buying the next buyable. Can have an optional argument "x" to calculate the cost of the x+1th purchase. (x is a Decimal). Can return an object if there are multiple currencies.

          • effect(): optional. A function that calculates and returns the current values of bonuses of this buyable. Can have an optional argument "x" to calculate the effect of having x of the buyable.. Can return a value or an object containing multiple values.

          • display(): A function returning everything that should be displayed on the buyable after the title, likely including the description, amount bought, cost, and current effect. Can use basic HTML.

          • unlocked(): optional. A function returning a bool to determine if the buyable is visible or not. Default is unlocked.

          • canAfford(): A function returning a bool to determine if you can buy one of the buyables.

          • buy(): A function that implements buying one of the buyable, including spending the currency.

          • buyMax(): optional. A function that implements buying as many of the buyable as possible.

          • style: optional. Applies CSS to this buyable, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • purchaseLimit: optional. The limit on how many of the buyable can be bought. The default is no limit.

          • marked: optional Adds a mark to the corner of the buyable. If it's "true" it will be a star, but it can also be an image URL.

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the buyable was stored under, for convenient access. The buyable in the example's id is 11.

          Sell One/Sell All:

          Including a sellOne or sellAll function will cause an additional button to appear beneath the buyable. They are functionally identical, but "sell one" appears above "sell all". You can also use them for other things.

          • sellOne/sellAll(): optional. Called when the button is pressed. The standard use would be to decrease/reset the amount of the buyable, and possibly return some currency to the player.

          • canSellOne/canSellAll(): optional. booleans determining whether or not to show the buttons. If "canSellOne/All" is absent but "sellOne/All" is present, the appropriate button will always show.

          To add a respec button, or something similar, add the respecBuyables function to the main buyables object (not individual buyables). You can use these features along with it:

          • respec(): optional. This is called when the button is pressed (after a toggleable confirmation message).

          • respecText: optional. Text to display on the respec Button.

          • showRespec(): optional. A function determining whether or not to show the button, if respecBuyables is defined. Defaults to true if absent.

          • respecMessage: optional. A custom confirmation message on respec, in place of the default one.

          - +}

          Features:

          • title: optional. displayed at the top in a larger font. It can also be a function that returns updating text.

          • cost(): cost for buying the next buyable. Can have an optional argument "x" to calculate the cost of the x+1th purchase. (x is a Decimal). Can return an object if there are multiple currencies.

          • effect(): optional. A function that calculates and returns the current values of bonuses of this buyable. Can have an optional argument "x" to calculate the effect of having x of the buyable.. Can return a value or an object containing multiple values.

          • display(): A function returning everything that should be displayed on the buyable after the title, likely including the description, amount bought, cost, and current effect. Can use basic HTML.

          • unlocked(): optional. A function returning a bool to determine if the buyable is visible or not. Default is unlocked.

          • canAfford(): A function returning a bool to determine if you can buy one of the buyables.

          • buy(): A function that implements buying one of the buyable, including spending the currency.

          • buyMax(): optional. A function that implements buying as many of the buyable as possible.

          • style: optional. Applies CSS to this buyable, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • purchaseLimit: optional. The limit on how many of the buyable can be bought. The default is no limit.

          • marked: optional Adds a mark to the corner of the buyable. If it's "true" it will be a star, but it can also be an image URL.

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the buyable was stored under, for convenient access. The buyable in the example's id is 11.

          Sell One/Sell All:

          Including a sellOne or sellAll function will cause an additional button to appear beneath the buyable. They are functionally identical, but "sell one" appears above "sell all". You can also use them for other things.

          • sellOne/sellAll(): optional. Called when the button is pressed. The standard use would be to decrease/reset the amount of the buyable, and possibly return some currency to the player.

          • canSellOne/canSellAll(): optional. booleans determining whether or not to show the buttons. If "canSellOne/All" is absent but "sellOne/All" is present, the appropriate button will always show.

          To add a respec button, or something similar, add the respecBuyables function to the main buyables object (not individual buyables). You can use these features along with it:

          • respec(): optional. This is called when the button is pressed (after a toggleable confirmation message).

          • respecText: optional. Text to display on the respec Button.

          • showRespec(): optional. A function determining whether or not to show the button, if respecBuyables is defined. Defaults to true if absent.

          • respecMessage: optional. A custom confirmation message on respec, in place of the default one.

          + \ No newline at end of file diff --git a/public/kronos/docs/challenges.html b/public/kronos/docs/challenges.html index 5bb0c5b5..0f7d31a1 100644 --- a/public/kronos/docs/challenges.html +++ b/public/kronos/docs/challenges.html @@ -6,13 +6,13 @@ Challenges | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
          Skip to content

          Challenges

          Challenges can have fully customizable win conditions. Useful functions for dealing with Challenges and implementing their effects:

          • inChallenge(layer, id): determine if the player is in a given challenge (or another challenge on the same layer that counts as this one).
          • hasChallenge(layer, id): determine if the player has completed the challenge.
          • challengeCompletions(layer, id): determine how many times the player completed the challenge.
          • maxedChallenge(layer, id): determines if the player has reached the maximum completions.
          • challengeEffect(layer, id): Returns the current effects of the challenge, if any.

          Challenges are stored in the following format:

          js
          challenges: {
          +    
          Skip to content

          Challenges

          Challenges can have fully customizable win conditions. Useful functions for dealing with Challenges and implementing their effects:

          • inChallenge(layer, id): determine if the player is in a given challenge (or another challenge on the same layer that counts as this one).
          • hasChallenge(layer, id): determine if the player has completed the challenge.
          • challengeCompletions(layer, id): determine how many times the player completed the challenge.
          • maxedChallenge(layer, id): determines if the player has reached the maximum completions.
          • challengeEffect(layer, id): Returns the current effects of the challenge, if any.

          Challenges are stored in the following format:

          js
          challenges: {
               11: {
                   name: "Ouch",
                   challengeDescription: "description of ouchie",
          @@ -42,8 +42,8 @@
                   etc
               },
               etc
          -}

          Usually, each challenge should have an id where the first digit is the row and the second digit is the column.

          Individual Challenges can have these features:

          • name: Name of the challenge, can be a string or a function. Can use basic HTML.

          • challengeDescription: A description of what makes the challenge a challenge. You will need to implement these elsewhere. It can also be a function that returns updating text. Can use basic HTML.

          • goalDescription: A description of the win condition for the challenge. It can also be a function that returns updating text. Can use basic HTML. (Optional if using the old goal system)

          • canComplete(): A function that returns true if you meet the win condition for the challenge. Returning a number will allow bulk completing the challenge. (Optional if using the old goal system)

          • rewardDescription: A description of the reward's effect. You will also have to implement the effect where it is applied. It can also be a function that returns updating text. Can use basic HTML.

          • rewardEffect(): optional. A function that calculates and returns the current values of any bonuses from the reward. Can return a value or an object containing multiple values. Can use basic HTML.

          • rewardDisplay(): optional. A function that returns a display of the current effects of the reward with formatting. Default behavior is to just display the a number appropriately formatted.

          • fullDisplay(): OVERRIDE. Overrides the other displays and descriptions, and lets you set the full text for the challenge. Can use basic HTML.

          • unlocked(): optional. A function returning a bool to determine if the challenge is visible or not. Default is unlocked.

          • onComplete() - optional. this function will be called when the challenge is completed when previously incomplete.

          • onEnter() - optional. this function will be called when entering the challenge

          • onExit() - optional. this function will be called when exiting the challenge in any way

          • countsAs: optional. If a challenge combines the effects of other challenges in this layer, you can use this. An array of challenge ids. The player is effectively in all of those challenges when in the current one.

          • completionLimit: optional. the amount of times you can complete this challenge. Default is 1 completion.

          • style: optional. Applies CSS to this challenge, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • marked: optional Adds a mark to the corner of the challenge. If it's "true" it will be a star, but it can also be an image URL. By default, if the challenge has multiple completions, it will be starred at max completions.

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar

          • id: assigned automagically. It's the "key" which the challenge was stored under, for convenient access. The challenge in the example's id is 11.

          The old goal system uses these features:

          • goal: deprecated, A Decimal for the amount of currency required to beat the challenge. By default, the goal is in basic Points. The goal can also be a function if its value changes.

          • currencyDisplayName: deprecated. the name to display for the currency for the goal

          • currencyInternalName: deprecated. the internal name for that currency

          • currencyLayer: deprecated. the internal name of the layer that currency is stored in. If it's not in a layer, omit. If it's not stored directly in a layer, instead use the next feature.

          • currencyLocation(): deprecated. if your currency is stored in something inside a layer (e.g. a buyable's amount), you can access it this way. This is a function returning the object in "player" that contains the value (like player[this.layer].buyables)

          - +}

          Usually, each challenge should have an id where the first digit is the row and the second digit is the column.

          Individual Challenges can have these features:

          • name: Name of the challenge, can be a string or a function. Can use basic HTML.

          • challengeDescription: A description of what makes the challenge a challenge. You will need to implement these elsewhere. It can also be a function that returns updating text. Can use basic HTML.

          • goalDescription: A description of the win condition for the challenge. It can also be a function that returns updating text. Can use basic HTML. (Optional if using the old goal system)

          • canComplete(): A function that returns true if you meet the win condition for the challenge. Returning a number will allow bulk completing the challenge. (Optional if using the old goal system)

          • rewardDescription: A description of the reward's effect. You will also have to implement the effect where it is applied. It can also be a function that returns updating text. Can use basic HTML.

          • rewardEffect(): optional. A function that calculates and returns the current values of any bonuses from the reward. Can return a value or an object containing multiple values. Can use basic HTML.

          • rewardDisplay(): optional. A function that returns a display of the current effects of the reward with formatting. Default behavior is to just display the a number appropriately formatted.

          • fullDisplay(): OVERRIDE. Overrides the other displays and descriptions, and lets you set the full text for the challenge. Can use basic HTML.

          • unlocked(): optional. A function returning a bool to determine if the challenge is visible or not. Default is unlocked.

          • onComplete() - optional. this function will be called when the challenge is completed when previously incomplete.

          • onEnter() - optional. this function will be called when entering the challenge

          • onExit() - optional. this function will be called when exiting the challenge in any way

          • countsAs: optional. If a challenge combines the effects of other challenges in this layer, you can use this. An array of challenge ids. The player is effectively in all of those challenges when in the current one.

          • completionLimit: optional. the amount of times you can complete this challenge. Default is 1 completion.

          • style: optional. Applies CSS to this challenge, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • marked: optional Adds a mark to the corner of the challenge. If it's "true" it will be a star, but it can also be an image URL. By default, if the challenge has multiple completions, it will be starred at max completions.

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar

          • id: assigned automagically. It's the "key" which the challenge was stored under, for convenient access. The challenge in the example's id is 11.

          The old goal system uses these features:

          • goal: deprecated, A Decimal for the amount of currency required to beat the challenge. By default, the goal is in basic Points. The goal can also be a function if its value changes.

          • currencyDisplayName: deprecated. the name to display for the currency for the goal

          • currencyInternalName: deprecated. the internal name for that currency

          • currencyLayer: deprecated. the internal name of the layer that currency is stored in. If it's not in a layer, omit. If it's not stored directly in a layer, instead use the next feature.

          • currencyLocation(): deprecated. if your currency is stored in something inside a layer (e.g. a buyable's amount), you can access it this way. This is a function returning the object in "player" that contains the value (like player[this.layer].buyables)

          + \ No newline at end of file diff --git a/public/kronos/docs/clickables.html b/public/kronos/docs/clickables.html index 237a8897..c84bcb55 100644 --- a/public/kronos/docs/clickables.html +++ b/public/kronos/docs/clickables.html @@ -6,13 +6,13 @@ Clickables | The Paper Pilot - + - + - - - + + + @@ -34,14 +34,14 @@ -
          Skip to content

          Clickables

          Clickables are any kind of thing that you can click for an effect. They're a more generalized version of Buyables.

          DO NOT USE THESE TO MAKE THINGS THAT YOU CLICK REPEATEDLY FOR A BONUS BECAUSE THOSE ARE AWFUL.

          There are several differences between the two. One is that a buyable's saved data is its amount as a Decimal, while Clickables store a "state" which can be a number or string, but not Decimal, array, or object). Buyables have a number of extra features which you can see on their page. Clickables also have a smaller default size.

          Useful functions for dealing with clickables and implementing their effects:

          • getClickableState(layer, id): get the state of the clickable the player has
          • setClickableState(layer, id, state): set the state of the clickable the player has
          • clickableEffect(layer, id): Returns the current effects of the clickable, if any.

          Clickables should be formatted like this:

          js
          clickables: {
          +    
          Skip to content

          Clickables

          Clickables are any kind of thing that you can click for an effect. They're a more generalized version of Buyables.

          DO NOT USE THESE TO MAKE THINGS THAT YOU CLICK REPEATEDLY FOR A BONUS BECAUSE THOSE ARE AWFUL.

          There are several differences between the two. One is that a buyable's saved data is its amount as a Decimal, while Clickables store a "state" which can be a number or string, but not Decimal, array, or object). Buyables have a number of extra features which you can see on their page. Clickables also have a smaller default size.

          Useful functions for dealing with clickables and implementing their effects:

          • getClickableState(layer, id): get the state of the clickable the player has
          • setClickableState(layer, id, state): set the state of the clickable the player has
          • clickableEffect(layer, id): Returns the current effects of the clickable, if any.

          Clickables should be formatted like this:

          js
          clickables: {
               11: {
                   display() {return "Blah"},
                   etc
               }
               etc
          -}

          Features:

          • title: optional. displayed at the top in a larger font. It can also be a function that returns updating text.

          • effect(): optional. A function that calculates and returns the current values of bonuses of this clickable. Can return a value or an object containing multiple values.

          • display(): A function returning everything that should be displayed on the clickable after the title, likely changing based on its state. Can use basic HTML.

          • unlocked(): optional. A function returning a bool to determine if the clickable is visible or not. Default is unlocked.

          • canClick(): A function returning a bool to determine if you can click the clickable.

          • onClick(): A function that implements clicking the clickable.

          • onHold(): optional A function that is called 20x/sec when the button is held for at least 0.25 seconds.

          • style: optional. Applies CSS to this clickable, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • marked: optional Adds a mark to the corner of the clickable. If it's "true" it will be a star, but it can also be an image URL.

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the clickable was stored under, for convenient access. The clickable in the example's id is 11.

          You can also use these features on the clickables object to add a button above all the clickables, for implementing a respec button or similar.

          • masterButtonPress(): optional. If present, an additional button will appear above the clickables. Pressing it will call this function.

          • masterButtonText: optional. Text to display on the Master Button.

          • showMasterButton(): optional. A function determining whether or not to show the button, if masterButtonPress is defined. Defaults to true if absent.

          - +}

          Features:

          • title: optional. displayed at the top in a larger font. It can also be a function that returns updating text.

          • effect(): optional. A function that calculates and returns the current values of bonuses of this clickable. Can return a value or an object containing multiple values.

          • display(): A function returning everything that should be displayed on the clickable after the title, likely changing based on its state. Can use basic HTML.

          • unlocked(): optional. A function returning a bool to determine if the clickable is visible or not. Default is unlocked.

          • canClick(): A function returning a bool to determine if you can click the clickable.

          • onClick(): A function that implements clicking the clickable.

          • onHold(): optional A function that is called 20x/sec when the button is held for at least 0.25 seconds.

          • style: optional. Applies CSS to this clickable, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • marked: optional Adds a mark to the corner of the clickable. If it's "true" it will be a star, but it can also be an image URL.

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the clickable was stored under, for convenient access. The clickable in the example's id is 11.

          You can also use these features on the clickables object to add a button above all the clickables, for implementing a respec button or similar.

          • masterButtonPress(): optional. If present, an additional button will appear above the clickables. Pressing it will call this function.

          • masterButtonText: optional. Text to display on the Master Button.

          • showMasterButton(): optional. A function determining whether or not to show the button, if masterButtonPress is defined. Defaults to true if absent.

          + \ No newline at end of file diff --git a/public/kronos/docs/custom-tab-layouts.html b/public/kronos/docs/custom-tab-layouts.html index bd44013d..71b6f03d 100644 --- a/public/kronos/docs/custom-tab-layouts.html +++ b/public/kronos/docs/custom-tab-layouts.html @@ -6,13 +6,13 @@ Custom tab layouts | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
          Skip to content

          Custom tab layouts

          Note: If you are using subtabs, tabFormat is used differently, but the same format is used for defining their layouts. See here for more on subtabs.

          Custom tab layouts can be used to do basically anything in a tab window, especially combined with the "style" layer feature. The tabFormat feature is an array of things, like this:

          js
          tabFormat: [
          +    
          Skip to content

          Custom tab layouts

          Note: If you are using subtabs, tabFormat is used differently, but the same format is used for defining their layouts. See here for more on subtabs.

          Custom tab layouts can be used to do basically anything in a tab window, especially combined with the "style" layer feature. The tabFormat feature is an array of things, like this:

          js
          tabFormat: [
               "main-display",
               ["prestige-button", function() { return "Melt your points into " }],
               "blank",
          @@ -47,8 +47,8 @@
               "blank",
               "blank",
               "upgrades"
          -]

          It is a list of components, which can be either just a name, or an array with arguments. If it's an array, the first item is the name of the component, the second is the data passed into it, and the third (optional) applies a CSS style to it with a "CSS object", where the keys are CSS attributes.

          These are the existing components, but you can create more in components.js:

          • display-text: Displays some text (can use basic HTML). The argument is the text to display. It can also be a function that returns updating text.

          • raw-html: Displays some basic HTML, can also be a function.

          • blank: Adds empty space. The default dimensions are 8px x 17px. The argument changes the dimensions. If it's a single value (e.g. "20px"), that determines the height. If you have a pair of arguments, the first is width and the second is height.

          • row: Display a list of components horizontally. The argument is an array of components in the tab layout format.

          • column: Display a list of components vertically. The argument is an array of components in the tab layout format. This is useful to display columns within a row.

          • main-display: The text that displays the main currency for the layer and its effects. The argument is the amount of precision to use, allowing it to display non-whole numbers.

          • resource-display: The text that displays the currency that this layer is based on, as well as the best and/or total values for this layer's prestige currency (if they are put in startData for this layer).

          • prestige-button: The argument is a string that the prestige button should say before the amount of currency you will gain. It can also be a function that returns updating text.

          • text-input: A text input box. The argument is the name of the variable in player[layer] that the input is for, player[layer][argument] (Works with strings, numbers, and Decimals!)

          • slider: Lets the user input a value with a slider. The argument a 3-element array: [name, min, max]. The name is the name of the variable in player[layer] that the input that the input is for, and min and max are the limits of the slider. (Does not work for Decimal values)

          • upgrades: The layer's upgrades. The argument is optional, and is a the list of rows this component should include, if it doesn't have all of them.

          • milestones, challenges, achievements: Display the upgrades, milestones, and challenges for a layer, as appropriate.

          • buyables, clickables: Display all of the buyables/clickables for this layer, as appropriate. The argument is optional and is the size of the boxes in pixels.

          • microtabs: Display a set of subtabs for an area. The argument is the name of the set of microtabs in the "microtabs" feature.

          • bar: Display a bar. The argument is the id of the bar to display.

          • infobox: Display an infobox. The argument is the id of the infobox to display.

          • tree: Displays a tree. The argument is an array of arrays containing the names of the nodes in the tree (first by row, then by column) See here for more information on tree layouts and nodes!

          • toggle: A toggle button that toggles a bool value. The argument is a pair that identifies the location in player of the bool to toggle, e.g. [layer, id]. 'layer' also affects the color of the toggle.

          • grid: Displays the gridable grid for the layer. If you need more than one grid, use a layer proxy.

          • layer-proxy: Lets you use components from another layer. The argument is a pair, [layer, data], consisting of the id of the layer to proxy from, and the tabFormat for the components to show. (Note: you cannot use a microtab within a layer proxy)

          The rest of the components are sub-components. They can be used just like other components, but are typically part of another component.

          • upgrade, milestone, challenge, buyable, clickable, achievement, gridable: An individual upgrade, challenge, etc. The argument is the id. This can be used if you want to have upgrades split up across multiple subtabs, for example.

          • respec-button, master-button: The respec and master buttons for buyables and clickables, respectively.

          • sell-one, sell-all: The "sell one" and "sell all" for buyables, respectively. The argument is the id of the buyable.

          - +]

          It is a list of components, which can be either just a name, or an array with arguments. If it's an array, the first item is the name of the component, the second is the data passed into it, and the third (optional) applies a CSS style to it with a "CSS object", where the keys are CSS attributes.

          These are the existing components, but you can create more in components.js:

          • display-text: Displays some text (can use basic HTML). The argument is the text to display. It can also be a function that returns updating text.

          • raw-html: Displays some basic HTML, can also be a function.

          • blank: Adds empty space. The default dimensions are 8px x 17px. The argument changes the dimensions. If it's a single value (e.g. "20px"), that determines the height. If you have a pair of arguments, the first is width and the second is height.

          • row: Display a list of components horizontally. The argument is an array of components in the tab layout format.

          • column: Display a list of components vertically. The argument is an array of components in the tab layout format. This is useful to display columns within a row.

          • main-display: The text that displays the main currency for the layer and its effects. The argument is the amount of precision to use, allowing it to display non-whole numbers.

          • resource-display: The text that displays the currency that this layer is based on, as well as the best and/or total values for this layer's prestige currency (if they are put in startData for this layer).

          • prestige-button: The argument is a string that the prestige button should say before the amount of currency you will gain. It can also be a function that returns updating text.

          • text-input: A text input box. The argument is the name of the variable in player[layer] that the input is for, player[layer][argument] (Works with strings, numbers, and Decimals!)

          • slider: Lets the user input a value with a slider. The argument a 3-element array: [name, min, max]. The name is the name of the variable in player[layer] that the input that the input is for, and min and max are the limits of the slider. (Does not work for Decimal values)

          • upgrades: The layer's upgrades. The argument is optional, and is a the list of rows this component should include, if it doesn't have all of them.

          • milestones, challenges, achievements: Display the upgrades, milestones, and challenges for a layer, as appropriate.

          • buyables, clickables: Display all of the buyables/clickables for this layer, as appropriate. The argument is optional and is the size of the boxes in pixels.

          • microtabs: Display a set of subtabs for an area. The argument is the name of the set of microtabs in the "microtabs" feature.

          • bar: Display a bar. The argument is the id of the bar to display.

          • infobox: Display an infobox. The argument is the id of the infobox to display.

          • tree: Displays a tree. The argument is an array of arrays containing the names of the nodes in the tree (first by row, then by column) See here for more information on tree layouts and nodes!

          • toggle: A toggle button that toggles a bool value. The argument is a pair that identifies the location in player of the bool to toggle, e.g. [layer, id]. 'layer' also affects the color of the toggle.

          • grid: Displays the gridable grid for the layer. If you need more than one grid, use a layer proxy.

          • layer-proxy: Lets you use components from another layer. The argument is a pair, [layer, data], consisting of the id of the layer to proxy from, and the tabFormat for the components to show. (Note: you cannot use a microtab within a layer proxy)

          The rest of the components are sub-components. They can be used just like other components, but are typically part of another component.

          • upgrade, milestone, challenge, buyable, clickable, achievement, gridable: An individual upgrade, challenge, etc. The argument is the id. This can be used if you want to have upgrades split up across multiple subtabs, for example.

          • respec-button, master-button: The respec and master buttons for buyables and clickables, respectively.

          • sell-one, sell-all: The "sell one" and "sell all" for buyables, respectively. The argument is the id of the buyable.

          + \ No newline at end of file diff --git a/public/kronos/docs/getting-started.html b/public/kronos/docs/getting-started.html index 034c647d..c797503f 100644 --- a/public/kronos/docs/getting-started.html +++ b/public/kronos/docs/getting-started.html @@ -6,13 +6,13 @@ Getting started | The Paper Pilot - + - + - - - + + + @@ -34,8 +34,8 @@ -
          Skip to content

          Getting started

          Welcome to The Modding Tree!

          Using the Modding Tree, at its simplest level, just requires getting a copy of it onto your computer. However, if you do it the right way, it will help in many ways.

          Don't let the word "Github" scare you away. It's actually much easier to use than most people think, especially because most people use it the hard way. The key is Github Desktop, which lets you do everything you need to, without even touching the command line.

          The benefits of using Github:

          • It makes it much, much easier to update The Modding Tree.
          • You can share your work without any extra effort using githack, or with a bit more effort, set up a github.io site.
          • It lets you undo changes to your code, and to have multiple versions of it.
          • It lets you collaborate with other people, if you want to.

          Getting set up with Github Desktop, Visual Studio Code, and The Modding Tree:

          1. Install Github Desktop and Visual Studio Code.

          2. Make a Github account. You can handle this on your own.

          3. Log in on your browser, and go back to The Modding Tree page. At the top right, there should be a button that says "fork". Click on it, and then on your username. You now have your own fork, or copy, of The Modding Tree.

          4. Open Github Desktop and log in. Ignore everything else and choose "clone a repository". A "repository" is basically a "Github project", like The Modding Tree. "Cloning" is downloading a copy of the repository to your computer.

          5. Look for The Modding Tree in the list of repositiories (it should be the only one) and click "clone".

          6. Select that you're using it for your own purposes, and click continue. It will download the files and handle everything.

          Using your repository

          1. Click on "show in explorer/finder" to the right, and then open the index.html file in the folder. The page should open up on your browser. This will let you view and test your project locally!

          2. To edit your project, click "open in VSCode" in Github Desktop.

          3. Open mod.js in VSCode, and look at the top part where it has a "modInfo" object. Fill in your mod's name to whatever you want, and change the id as well. (It can be any string value, and it's used to determine where the savefile is. Make it something that's probably unique, and don't change it again later or else it'll effectively wipe existing saves)

          4. Save mod.js, and then reload index.html in your browser. The title on the tab, as well as on the info page, will now be updated! You can reload the page every time you change the code to test it quickly and easily.

          5. Go back to Github Desktop. It's time to save your changes into the git system by making a "commit". This basically saves your work and creates a snapshot of what your code looks like at this moment, allowing you to look back at it later.

          6. At the bottom right corner, add a summary of your changes, and then click "commit to master".

          7. Finally, at the top middle, click "push origin" to push your changes out onto the online repository.

          8. You can view your project on line, or share it with others, by going to https://raw.githack.com/[YOUR-GITHUB-USERNAME]/The-Modding-Tree/master/index.html

          And now, you have successfully used Github! You can look at the documentation to see how The Modding Tree's system works and to make your mod a reality.

          - +
          Skip to content

          Getting started

          Welcome to The Modding Tree!

          Using the Modding Tree, at its simplest level, just requires getting a copy of it onto your computer. However, if you do it the right way, it will help in many ways.

          Don't let the word "Github" scare you away. It's actually much easier to use than most people think, especially because most people use it the hard way. The key is Github Desktop, which lets you do everything you need to, without even touching the command line.

          The benefits of using Github:

          • It makes it much, much easier to update The Modding Tree.
          • You can share your work without any extra effort using githack, or with a bit more effort, set up a github.io site.
          • It lets you undo changes to your code, and to have multiple versions of it.
          • It lets you collaborate with other people, if you want to.

          Getting set up with Github Desktop, Visual Studio Code, and The Modding Tree:

          1. Install Github Desktop and Visual Studio Code.

          2. Make a Github account. You can handle this on your own.

          3. Log in on your browser, and go back to The Modding Tree page. At the top right, there should be a button that says "fork". Click on it, and then on your username. You now have your own fork, or copy, of The Modding Tree.

          4. Open Github Desktop and log in. Ignore everything else and choose "clone a repository". A "repository" is basically a "Github project", like The Modding Tree. "Cloning" is downloading a copy of the repository to your computer.

          5. Look for The Modding Tree in the list of repositiories (it should be the only one) and click "clone".

          6. Select that you're using it for your own purposes, and click continue. It will download the files and handle everything.

          Using your repository

          1. Click on "show in explorer/finder" to the right, and then open the index.html file in the folder. The page should open up on your browser. This will let you view and test your project locally!

          2. To edit your project, click "open in VSCode" in Github Desktop.

          3. Open mod.js in VSCode, and look at the top part where it has a "modInfo" object. Fill in your mod's name to whatever you want, and change the id as well. (It can be any string value, and it's used to determine where the savefile is. Make it something that's probably unique, and don't change it again later or else it'll effectively wipe existing saves)

          4. Save mod.js, and then reload index.html in your browser. The title on the tab, as well as on the info page, will now be updated! You can reload the page every time you change the code to test it quickly and easily.

          5. Go back to Github Desktop. It's time to save your changes into the git system by making a "commit". This basically saves your work and creates a snapshot of what your code looks like at this moment, allowing you to look back at it later.

          6. At the bottom right corner, add a summary of your changes, and then click "commit to master".

          7. Finally, at the top middle, click "push origin" to push your changes out onto the online repository.

          8. You can view your project on line, or share it with others, by going to https://raw.githack.com/[YOUR-GITHUB-USERNAME]/The-Modding-Tree/master/index.html

          And now, you have successfully used Github! You can look at the documentation to see how The Modding Tree's system works and to make your mod a reality.

          + \ No newline at end of file diff --git a/public/kronos/docs/grids.html b/public/kronos/docs/grids.html index 6dbacb94..62f502ab 100644 --- a/public/kronos/docs/grids.html +++ b/public/kronos/docs/grids.html @@ -6,13 +6,13 @@ Grids | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
          Skip to content

          Grids

          Grids are an easier way of making a group of similar clickables. They all have the same behavior, but are different based on their data.

          NOTE: Gridables are similar to clickables in some respects, but are fundamentally different from normal TMT components in quite a few ways. Be sure to keep these in mind:

          • Gridable ids use base 100 instead of base 10, so you can have more than 10 tiles in a row. This means that a grid might look like this: 101 102 201 202
          • Individual gridables are not defined individually. All properties go directly into the "grid" object. Functions are called with arguments for the id of the gridables and its associated data, so you can give them the appropriate appearance and properties based on that.
          • If you need two unrelated grids in a layer, you'll need to use a layer proxy component.

          Useful functions for dealing with grids:

          • getGridData(layer, id): get the data for the chosen gridable
          • setGridData(layer, id, state): set the data for the chosen gridable
          • gridEffect(layer, id): get the effect for the chosen gridable

          The grid should be formatted like this:

          js
          grid: {
          +    
          Skip to content

          Grids

          Grids are an easier way of making a group of similar clickables. They all have the same behavior, but are different based on their data.

          NOTE: Gridables are similar to clickables in some respects, but are fundamentally different from normal TMT components in quite a few ways. Be sure to keep these in mind:

          • Gridable ids use base 100 instead of base 10, so you can have more than 10 tiles in a row. This means that a grid might look like this: 101 102 201 202
          • Individual gridables are not defined individually. All properties go directly into the "grid" object. Functions are called with arguments for the id of the gridables and its associated data, so you can give them the appropriate appearance and properties based on that.
          • If you need two unrelated grids in a layer, you'll need to use a layer proxy component.

          Useful functions for dealing with grids:

          • getGridData(layer, id): get the data for the chosen gridable
          • setGridData(layer, id, state): set the data for the chosen gridable
          • gridEffect(layer, id): get the effect for the chosen gridable

          The grid should be formatted like this:

          js
          grid: {
               rows: 4, // If these are dynamic make sure to have a max value as well!
               cols: 5,
               getStartData(id) {
          @@ -54,8 +54,8 @@
               },
           
               etc
          -}

          Features:

          • rows, cols: The amount of rows and columns of gridable to display.

          • maxRows, maxCols: sometimes needed. If rows or cols are dynamic, you need to define the maximum amount that there can be (you can increase it when you update the game though). These CANNOT be dynamic.

          • getStartData(id): Creates the default data for the gridable at this position. This can be an object, or a regular value.

          • getUnlocked(id): optional. Returns true if the gridable at this position should be visible.

          • getTitle(data, id): optional. Returns text that should displayed at the top in a larger font, based on the position and data of the gridable.

          • getDisplay(data, id): optional. Returns everything that should be displayed on the gridable after the title, based on the position and data of the gridable.

          • getStyle(data, id): optional. Returns CSS to apply to this gridable, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • getCanClick(data, id): optional. A function returning a bool to determine if you can click a gridable, based on its data and position. If absent, you can always click it.

          • onClick(data, id): A function that implements clicking on the gridable, based on its position and data.

          • onHold(data, id): optional A function that is called 20x/sec when the button is held for at least 0.25 seconds.

          • getEffect(data, id): optional. A function that calculates and returns a gridable's effect, based on its position and data. (Whatever that means for a gridable)

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          - +}

          Features:

          • rows, cols: The amount of rows and columns of gridable to display.

          • maxRows, maxCols: sometimes needed. If rows or cols are dynamic, you need to define the maximum amount that there can be (you can increase it when you update the game though). These CANNOT be dynamic.

          • getStartData(id): Creates the default data for the gridable at this position. This can be an object, or a regular value.

          • getUnlocked(id): optional. Returns true if the gridable at this position should be visible.

          • getTitle(data, id): optional. Returns text that should displayed at the top in a larger font, based on the position and data of the gridable.

          • getDisplay(data, id): optional. Returns everything that should be displayed on the gridable after the title, based on the position and data of the gridable.

          • getStyle(data, id): optional. Returns CSS to apply to this gridable, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • getCanClick(data, id): optional. A function returning a bool to determine if you can click a gridable, based on its data and position. If absent, you can always click it.

          • onClick(data, id): A function that implements clicking on the gridable, based on its position and data.

          • onHold(data, id): optional A function that is called 20x/sec when the button is held for at least 0.25 seconds.

          • getEffect(data, id): optional. A function that calculates and returns a gridable's effect, based on its position and data. (Whatever that means for a gridable)

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          + \ No newline at end of file diff --git a/public/kronos/docs/infoboxes.html b/public/kronos/docs/infoboxes.html index 668155a2..92edfb63 100644 --- a/public/kronos/docs/infoboxes.html +++ b/public/kronos/docs/infoboxes.html @@ -6,13 +6,13 @@ Infoboxes | The Paper Pilot - + - + - - - + + + @@ -34,15 +34,15 @@ -
          Skip to content

          Infoboxes

          Infoboxes are good for displaying "lore", or story elements, as well as for explaining complicated things.

          In the default tab layout, the first infobox will be displayed at the very top of the tab.

          Infoboxes are defined like other Big Features:

          js
          infoboxes: {
          +    
          Skip to content

          Infoboxes

          Infoboxes are good for displaying "lore", or story elements, as well as for explaining complicated things.

          In the default tab layout, the first infobox will be displayed at the very top of the tab.

          Infoboxes are defined like other Big Features:

          js
          infoboxes: {
               lore: {
                   title: "foo",
                   body() { return "bar" },
                   etc
               },
               etc
          -}

          Features:

          • title: The text displayed above the main box. Can be a function to be dynamic, and can use basic HTML.

          • body: The text displayed inside the box. Can be a function to be dynamic, and can use basic HTML.

          • style, titleStyle, bodyStyle: optional. Apply CSS to the infobox, or to the title button or body of the infobox, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • unlocked(): optional. A function returning a bool to determine if the infobox is visible or not. Default is unlocked.

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar

          • id: assigned automagically. It's the "key" which the bar was stored under, for convenient access. The infobox in the example's id is "lore".

          - +}

          Features:

          • title: The text displayed above the main box. Can be a function to be dynamic, and can use basic HTML.

          • body: The text displayed inside the box. Can be a function to be dynamic, and can use basic HTML.

          • style, titleStyle, bodyStyle: optional. Apply CSS to the infobox, or to the title button or body of the infobox, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • unlocked(): optional. A function returning a bool to determine if the infobox is visible or not. Default is unlocked.

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar

          • id: assigned automagically. It's the "key" which the bar was stored under, for convenient access. The infobox in the example's id is "lore".

          + \ No newline at end of file diff --git a/public/kronos/docs/layer-features.html b/public/kronos/docs/layer-features.html index 972ce6d3..9065796e 100644 --- a/public/kronos/docs/layer-features.html +++ b/public/kronos/docs/layer-features.html @@ -6,13 +6,13 @@ Layer Features | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
          Skip to content

          Layer Features

          This is a more comprehensive list of established features to add to layers. You can add more freely, if you want to have other functions or values associated with your layer. These have special functionality, though.

          You can make almost any value dynamic by using a function in its place, including all display strings and styling/color features.

          Layer Definition features

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar to access the saved value. It makes copying code to new layers easier. It is also assigned to all upgrades and buyables and such.

          • name: optional. used in reset confirmations (and the default infobox title). If absent, it just uses the layer's id.

          • startData(): A function to return the default save data for this layer. Add any variables you have to it. Make sure to use Decimal values rather than normal numbers.

            Standard values: - Required: - unlocked: a bool determining if this layer is unlocked or not - points: a Decimal, the main currency for the layer - Optional: - total: A Decimal, tracks total amount of main prestige currency. Always tracked, but only shown if you add it here. - best: A Decimal, tracks highest amount of main prestige currency. Always tracked, but only shown if you add it here. - unlockOrder: used to keep track of relevant layers unlocked before this one. - resetTime: A number, time since this layer was last prestiged (or reset by another layer)

          • color: A color associated with this layer, used in many places. (A string in hex format with a #)

          • row: The row of the layer, starting at 0. This affects where the node appears on the standard tree, and which resets affect the layer.

            Using "side" instead of a number will cause the layer to appear off to the side as a smaller node (useful for achievements and statistics). Side layers are not affected by resets unless you add a doReset to them.

          • displayRow: OVERRIDE Changes where the layer node appears without changing where it is in the reset order.

          • resource: Name of the main currency you gain by resetting on this layer.

          • effect(): optional. A function that calculates and returns the current values of any bonuses inherent to the main currency. Can return a value or an object containing multiple values. You will also have to implement the effect where it is applied.

          • effectDescription: optional. A function that returns a description of this effect. If the text stays constant, it can just be a string.

          • layerShown(): optional, A function returning a bool which determines if this layer's node should be visible on the tree. It can also return "ghost", which will hide the layer, but its node will still take up space in the tree. Defaults to true.

          • hotkeys: optional. An array containing information on any hotkeys associated with this layer:

            js
            hotkeys: [
            +    
            Skip to content

            Layer Features

            This is a more comprehensive list of established features to add to layers. You can add more freely, if you want to have other functions or values associated with your layer. These have special functionality, though.

            You can make almost any value dynamic by using a function in its place, including all display strings and styling/color features.

            Layer Definition features

            • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar to access the saved value. It makes copying code to new layers easier. It is also assigned to all upgrades and buyables and such.

            • name: optional. used in reset confirmations (and the default infobox title). If absent, it just uses the layer's id.

            • startData(): A function to return the default save data for this layer. Add any variables you have to it. Make sure to use Decimal values rather than normal numbers.

              Standard values: - Required: - unlocked: a bool determining if this layer is unlocked or not - points: a Decimal, the main currency for the layer - Optional: - total: A Decimal, tracks total amount of main prestige currency. Always tracked, but only shown if you add it here. - best: A Decimal, tracks highest amount of main prestige currency. Always tracked, but only shown if you add it here. - unlockOrder: used to keep track of relevant layers unlocked before this one. - resetTime: A number, time since this layer was last prestiged (or reset by another layer)

            • color: A color associated with this layer, used in many places. (A string in hex format with a #)

            • row: The row of the layer, starting at 0. This affects where the node appears on the standard tree, and which resets affect the layer.

              Using "side" instead of a number will cause the layer to appear off to the side as a smaller node (useful for achievements and statistics). Side layers are not affected by resets unless you add a doReset to them.

            • displayRow: OVERRIDE Changes where the layer node appears without changing where it is in the reset order.

            • resource: Name of the main currency you gain by resetting on this layer.

            • effect(): optional. A function that calculates and returns the current values of any bonuses inherent to the main currency. Can return a value or an object containing multiple values. You will also have to implement the effect where it is applied.

            • effectDescription: optional. A function that returns a description of this effect. If the text stays constant, it can just be a string.

            • layerShown(): optional, A function returning a bool which determines if this layer's node should be visible on the tree. It can also return "ghost", which will hide the layer, but its node will still take up space in the tree. Defaults to true.

            • hotkeys: optional. An array containing information on any hotkeys associated with this layer:

              js
              hotkeys: [
                   {
                       key: "p", // What the hotkey button is. Use uppercase if it's combined with shift, or "ctrl+x" for holding down ctrl.
                       description: "p: reset your points for prestige points", // The description of the hotkey that is displayed in the game's How To Play tab
              @@ -44,8 +44,8 @@
               ]
            • style: optional. a "CSS object" where the keys are CSS attributes, containing any CSS that should affect this layer's entire tab.

            • tabFormat: optional. use this if you want to add extra things to your tab or change the layout. See here for more info.

            • midsection: optional, an alternative to tabFormat, which is inserted in between Milestones and Buyables in the standard tab layout. (cannot do subtabs)

            Big features (all optional)

            • upgrades: A set of one-time purchases which can have unique upgrade conditions, currency costs, and bonuses. See here for more info.

            • milestones: A list of bonuses gained upon reaching certain thresholds of a resource. Often used for automation/QOL. See here for more info.

            • challenges: The player can enter challenges, which make the game harder. If they reach a goal and beat the challenge, they recieve a bonus. See here for more info.

            • buyables: Effectively upgrades that can be bought multiple times, and are optionally respeccable. Many uses. See here for more info.

            • clickables: Extremely versatile and generalized buttons which can only be clicked sometimes. See here for more info.

            • microtabs: An area that functions like a set of subtabs, with buttons at the top changing the content within. (Advanced) See here for more info.

            • bars: Display some information as a progress bar, gague, or similar. They are highly customizable, and can be vertical as well. See here for more info.

            • achievements: Kind of like milestones, but with a different display style and some other differences. Extra features are on the way at a later date! See here for more info.

            • achievementPopups, milestonePopups: optional, If false, disables popup message when you get the achievement/milestone. True by default.

            • infoboxes: Displays some text in a box that can be shown or hidden. See here for more info.

            • grid: A grid of buttons that behave the same, but have their own data.See here for more info.

            Prestige formula features

            • type: optional. Determines which prestige formula you use. Defaults to "none".

              • "normal": The amount of currency you gain is independent of its current amount (like Prestige). The formula before bonuses is based on baseResource^exponent
              • "static": The cost is dependent on your total after reset. The formula before bonuses is based on base^(x^exponent)
              • "custom": You can define everything, from the calculations to the text on the button, yourself. (See more at the bottom)
              • "none": This layer does not prestige, and therefore does not need any of the other features in this section.
            • baseResource: The name of the resource that determines how much of the main currency you gain on reset.

            • baseAmount(): A function that gets the current value of the base resource.

            • requires: A Decimal, the amount of the base needed to gain 1 of the prestige currency. Also the amount required to unlock the layer. You can instead make this a function, to make it harder if another layer was unlocked first (based on unlockOrder).

            • exponent: Used as described above.

            • base: sometimes required. required for "static" layers, used as described above. If absent, defaults to 2. Must be greater than 1.

            • roundUpCost: optional. a bool, which is true if the resource cost needs to be rounded up. (use if the base resource is a "static" currency.)

            • gainMult(), gainExp(): optional. For normal layers, these functions calculate the multiplier and exponent on resource gain from upgrades and boosts and such. Plug in most bonuses here. For static layers, they instead divide and root the cost of the resource.

            • directMult(): optional. Directly multiplies the resource gain, after exponents and softcaps. For static layers, actually multiplies resource gain instead of reducing the cost.

            • softcap, softcapPower: optional. For normal layers, gain beyond [softcap] points is put to the [softcapPower]th power Default for softcap is e1e7, and for power is 0.5.

            • canBuyMax(): sometimes required. required for static layers, function used to determine if buying max is permitted.

            • onPrestige(gain): optional. A function that triggers when this layer prestiges, just before you gain the currency. Can be used to have secondary resource gain on prestige, or to recalculate things or whatnot.

            • resetDescription: optional. Use this to replace "Reset for " on the Prestige button with something else.

            • prestigeButtonText(): sometimes required. Use this to make the entirety of the text a Prestige button contains. Only required for custom layers, but usable by all types.

            • passiveGeneration(): optional, returns a regular number. You automatically generate your gain times this number every second (does nothing if absent) This is good for automating Normal layers.

            • autoPrestige(): optional, returns a boolean, if true, the layer will always automatically do a prestige if it can. This is good for automating Static layers.

            Tree/node features

            • symbol: optional. The text that appears on this layer's node. Default is the layer id with the first letter capitalized.

            • image: override. The url (local or global) of an image that goes on the node. (Overrides symbol)

            • position: optional. Determines the horizontal position of the layer in its row in a standard tree. By default, it uses the layer id, and layers are sorted in alphabetical order.

            • branches: optional. An array of layer/node ids. On a tree, a line will appear from this layer to all of the layers in the list. Alternatively, an entry in the array can be a 2-element array consisting of the layer id and a color value. The color value can either be a string with a hex color code, or a number from 1-3 (theme-affected colors).

            • nodeStyle: optional. A CSS object, where the keys are CSS attributes, which styles this layer's node on the tree.

            • tooltip() / tooltipLocked(): optional. Functions that return text, which is the tooltip for the node when the layer is unlocked or locked, respectively. By default the tooltips behave the same as in the original Prestige Tree. If the value is "", the tooltip will be disabled.

            • marked: optional Adds a mark to the corner of the node. If it's "true" it will be a star, but it can also be an image URL.

            Other features

            • doReset(resettingLayer): optional. Is triggered when a layer on a row greater than or equal to this one does a reset. The default behavior is to reset everything on the row, but only if it was triggered by a layer in a higher row. doReset is always called for side layers, but for these the default behavior is to reset nothing.

              If you want to keep things, determine what to keep based on resettingLayer, milestones, and such, then call layerDataReset(layer, keep), where layer is this layer, and keep is an array of the names of things to keep. It can include things like "points", "best", "total" (for this layer's prestige currency), "upgrades", any unique variables like "generatorPower", etc. If you want to only keep specific upgrades or something like that, save them in a separate variable, then call layerDataReset, and then set player[this.layer].upgrades to the saved upgrades.

            • update(diff): optional. This function is called every game tick. Use it for any passive resource production or time-based things. diff is the time since the last tick.

            • autoUpgrade: optional, a boolean value, if true, the game will attempt to buy this layer's upgrades every tick. Defaults to false.

            • automate(): optional. This function is called every game tick, after production. Use it to activate automation things that aren't otherwise supported.

            • resetsNothing: optional. Returns true if this layer shouldn't trigger any resets when you prestige.

            • increaseUnlockOrder: optional. An array of layer ids. When this layer is unlocked for the first time, the unlockOrder value for any not-yet-unlocked layers in this list increases. This can be used to make them harder to unlock.

            • shouldNotify: optional. A function to return true if this layer should be highlighted in the tree. The layer will automatically be highlighted if you can buy an upgrade whether you have this or not.

            • glowColor: optional. The color that this layer will be highlighted if it should notify. The default is red. You can use this if you want several different notification types!

            • componentStyles: optional. An object that contains a set of functions returning CSS objects. Each of these will be applied to any components on the layer with the type of its id. Example:

            js
            componentStyles: {
                 "challenge"() { return {'height': '200px'} },
                 "prestige-button"() { return {'color': '#AA66AA'} }
            -}
            • deactivated: optional, if this is true, hasUpgrade, hasChallenge, hasAchievement, and hasMilestone will return false for things in the layer, and you will be unable to buy or click things on the layer. You will have to disable effects of buyables, the innate layer effect, and possibly other things yourself.

            Custom Prestige type

            (All of these can also be used by other prestige types)

            • getResetGain(): mostly for custom prestige type. Returns how many points you should get if you reset now. You can call getResetGain(this.layer, useType = "static") or similar to calculate what your gain would be under another prestige type (provided you have all of the required features in the layer).

            • getNextAt(canMax=false): mostly for custom prestige type. Returns how many of the base currency you need to get to the next point. canMax is an optional variable used with Static-ish layers to differentiate between if it's looking for the first point you can reset at, or the requirement for any gain at all (Supporting both is good). You can also call getNextAt(this.layer, canMax=false, useType = "static") or similar to calculate what your next at would be under another prestige type (provided you have all of the required features in the layer).

            • canReset(): mostly for custom prestige type. Return true only if you have the resources required to do a prestige here.

            • prestigeNotify(): mostly for custom prestige types, returns true if this layer should be subtly highlighted to indicate you can prestige for a meaningful gain.

            - +}
            • deactivated: optional, if this is true, hasUpgrade, hasChallenge, hasAchievement, and hasMilestone will return false for things in the layer, and you will be unable to buy or click things on the layer. You will have to disable effects of buyables, the innate layer effect, and possibly other things yourself.

            Custom Prestige type

            (All of these can also be used by other prestige types)

            • getResetGain(): mostly for custom prestige type. Returns how many points you should get if you reset now. You can call getResetGain(this.layer, useType = "static") or similar to calculate what your gain would be under another prestige type (provided you have all of the required features in the layer).

            • getNextAt(canMax=false): mostly for custom prestige type. Returns how many of the base currency you need to get to the next point. canMax is an optional variable used with Static-ish layers to differentiate between if it's looking for the first point you can reset at, or the requirement for any gain at all (Supporting both is good). You can also call getNextAt(this.layer, canMax=false, useType = "static") or similar to calculate what your next at would be under another prestige type (provided you have all of the required features in the layer).

            • canReset(): mostly for custom prestige type. Return true only if you have the resources required to do a prestige here.

            • prestigeNotify(): mostly for custom prestige types, returns true if this layer should be subtly highlighted to indicate you can prestige for a meaningful gain.

          + \ No newline at end of file diff --git a/public/kronos/docs/main-mod-info.html b/public/kronos/docs/main-mod-info.html index aaae3cc9..316e034a 100644 --- a/public/kronos/docs/main-mod-info.html +++ b/public/kronos/docs/main-mod-info.html @@ -6,13 +6,13 @@ mod.js | The Paper Pilot - + - + - - - + + + @@ -34,12 +34,12 @@ -
          Skip to content

          mod.js

          Most of the non-layer code and data that you're likely to edit is here in mod.js. Everything in mod.js will not be altered by updates, besides the addition of new things.

          Here's a breakdown of what's in it:

          • modInfo is where most of the basic configuration for the mod is. It contains:

            • name: The name of your mod. (a string)

            • id: The id for your mod, a unique string that is used to determine savefile location. Be sure to set it when you start making a mod, and don't change it later because it will erase all saves.

            • author: The name of the author, displayed in the info tab.

            • pointsName: This changes what is displayed instead of "points" for the main currency. (It does not affect it in the code.)

            • discordName, discordLink: If you have a Discord server or other discussion place, you can add a link to it.

              "discordName" is the text on the link, and "discordLink" is the url of an invite. If you're using a Discord invite, please make sure it's set to never expire.

            • offlineLimit: The maximum amount of offline time that the player can accumulate, in hours. Any extra time is lost. (a number)

              This is useful because most of these mods are fast-paced enough that too much offline time ruins the balance, such as the time in between updates. That is why I suggest developers disable offline time on their own savefile.

            • initialStartPoints: A Decimal for the amount of points a new player should start with.

          • VERSION is used to describe the current version of your mod. It contains:

            • num: The mod's version number, displayed at the top right of the tree tab.
            • name: The version's name, displayed alongside the number in the info tab.
          • changelog is the HTML displayed in the changelog tab. If this gets particularly long, it might be good to put in a separate file (be sure to add the file to index.html)

          • doNotCallTheseFunctionsEveryTick is very important, if you are adding non-standard functions. TMT calls every function anywhere in "layers" every tick to store the result, unless specifically told not to. Functions that have are used to do an action need to be identified. "Official" functions (those in the documentation) are all fine, but if you make any new ones, add their names to this array.

          js
          // (The ones here are examples, all official functions are already taken care of)
          +    
          Skip to content

          mod.js

          Most of the non-layer code and data that you're likely to edit is here in mod.js. Everything in mod.js will not be altered by updates, besides the addition of new things.

          Here's a breakdown of what's in it:

          • modInfo is where most of the basic configuration for the mod is. It contains:

            • name: The name of your mod. (a string)

            • id: The id for your mod, a unique string that is used to determine savefile location. Be sure to set it when you start making a mod, and don't change it later because it will erase all saves.

            • author: The name of the author, displayed in the info tab.

            • pointsName: This changes what is displayed instead of "points" for the main currency. (It does not affect it in the code.)

            • discordName, discordLink: If you have a Discord server or other discussion place, you can add a link to it.

              "discordName" is the text on the link, and "discordLink" is the url of an invite. If you're using a Discord invite, please make sure it's set to never expire.

            • offlineLimit: The maximum amount of offline time that the player can accumulate, in hours. Any extra time is lost. (a number)

              This is useful because most of these mods are fast-paced enough that too much offline time ruins the balance, such as the time in between updates. That is why I suggest developers disable offline time on their own savefile.

            • initialStartPoints: A Decimal for the amount of points a new player should start with.

          • VERSION is used to describe the current version of your mod. It contains:

            • num: The mod's version number, displayed at the top right of the tree tab.
            • name: The version's name, displayed alongside the number in the info tab.
          • changelog is the HTML displayed in the changelog tab. If this gets particularly long, it might be good to put in a separate file (be sure to add the file to index.html)

          • doNotCallTheseFunctionsEveryTick is very important, if you are adding non-standard functions. TMT calls every function anywhere in "layers" every tick to store the result, unless specifically told not to. Functions that have are used to do an action need to be identified. "Official" functions (those in the documentation) are all fine, but if you make any new ones, add their names to this array.

          js
          // (The ones here are examples, all official functions are already taken care of)
           var doNotCallTheseFunctionsEveryTick = ["doReset", "buy", "onPurchase", "blowUpEverything"]
          • getStartPoints(): A function to determine the amount of points the player starts with after a reset. (returns a Decimal value)

          • canGenPoints(): A function returning a boolean for if points should be generated. Use this if you want an upgrade to unlock generating points.

          • getPointGen(): A function that calculates your points per second. Anything that affects your point gain should go into the calculation here.

          • addedPlayerData(): A function that returns any non-layer-related data that you want to be added to the save data and "player" object.

          js
          function addedPlayerData() { return {
           	weather: "Yes",
           	happiness: new Decimal(72),
          -}}
          • displayThings: An array of functions used to display extra things at the top of the tree tab. Each function returns a string, which is a line to display (with basic HTML support). If a function returns nothing, nothing is displayed (and it doesn't take up a line).

          • isEndgame(): A function to determine if the player has reached the end of the game, at which point the "you win!" screen appears.

          Less important things beyond this point!

          • maxTickLength(): Returns the maximum tick length, in milliseconds. Only really useful if you have something that reduces over time, which long ticks mess up (usually a challenge).

          • fixOldSave(): Can be used to modify a save file when loading into a new version of the game. Use this to undo inflation, never forcibly hard reset your players.

          - +}}
          • displayThings: An array of functions used to display extra things at the top of the tree tab. Each function returns a string, which is a line to display (with basic HTML support). If a function returns nothing, nothing is displayed (and it doesn't take up a line).

          • isEndgame(): A function to determine if the player has reached the end of the game, at which point the "you win!" screen appears.

          Less important things beyond this point!

          • maxTickLength(): Returns the maximum tick length, in milliseconds. Only really useful if you have something that reduces over time, which long ticks mess up (usually a challenge).

          • fixOldSave(): Can be used to modify a save file when loading into a new version of the game. Use this to undo inflation, never forcibly hard reset your players.

          + \ No newline at end of file diff --git a/public/kronos/docs/milestones.html b/public/kronos/docs/milestones.html index b052b839..da6ea4f8 100644 --- a/public/kronos/docs/milestones.html +++ b/public/kronos/docs/milestones.html @@ -6,13 +6,13 @@ Milestones | The Paper Pilot - + - + - - - + + + @@ -34,15 +34,15 @@ -
          Skip to content

          Milestones

          Milestones are awarded to the player when they meet a certain goal, and give some benefit. Milestones should be formatted like this:

          js
          milestones: {
          +    
          Skip to content

          Milestones

          Milestones are awarded to the player when they meet a certain goal, and give some benefit. Milestones should be formatted like this:

          js
          milestones: {
               0: {
                   requirementDescription: "123 waffles",
                   effectDescription: "blah",
                   done() { return player.w.points.gte(123) }
               }
               etc
          -}

          You can use hasMilestone(layer, id) to determine if the player has a given milestone

          Milestone features:

          • requirementDescription: A string describing the requirement for unlocking this milestone. Suggestion: Use a "total". It can also be a function that returns updating text. Can use basic HTML.

          • effectDescription: A string describing the reward for having the milestone. You will have to implement the reward elsewhere. It can also be a function that returns updating text. Can use basic HTML.

          • done(): A function returning a boolean to determine if the milestone should be awarded.

          • toggles: optional. Creates toggle buttons that appear on the milestone when it is unlocked. The toggles can toggle a given boolean value in a layer. It is defined as an array of paired items, one pair per toggle. The first is the internal name of the layer the value being toggled is stored in, and the second is the internal name of the variable to toggle. (e.g. [["b", "auto"], ["g", "auto"])

            Tip: Toggles are not de-set if the milestone becomes locked! In this case, you should also check if the player has the milestone.

          • style: optional. Applies CSS to this milestone, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • unlocked(): optional. A function returning a boolean to determine if the milestone should be shown. If absent, it is always shown.

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the milestone was stored under, for convenient access. The milestone in the example's id is 0.

          Disaable milestone popups by adding milestonePopups: false to the layer.

          - +}

          You can use hasMilestone(layer, id) to determine if the player has a given milestone

          Milestone features:

          • requirementDescription: A string describing the requirement for unlocking this milestone. Suggestion: Use a "total". It can also be a function that returns updating text. Can use basic HTML.

          • effectDescription: A string describing the reward for having the milestone. You will have to implement the reward elsewhere. It can also be a function that returns updating text. Can use basic HTML.

          • done(): A function returning a boolean to determine if the milestone should be awarded.

          • toggles: optional. Creates toggle buttons that appear on the milestone when it is unlocked. The toggles can toggle a given boolean value in a layer. It is defined as an array of paired items, one pair per toggle. The first is the internal name of the layer the value being toggled is stored in, and the second is the internal name of the variable to toggle. (e.g. [["b", "auto"], ["g", "auto"])

            Tip: Toggles are not de-set if the milestone becomes locked! In this case, you should also check if the player has the milestone.

          • style: optional. Applies CSS to this milestone, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • unlocked(): optional. A function returning a boolean to determine if the milestone should be shown. If absent, it is always shown.

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the milestone was stored under, for convenient access. The milestone in the example's id is 0.

          Disaable milestone popups by adding milestonePopups: false to the layer.

          + \ No newline at end of file diff --git a/public/kronos/docs/particles.html b/public/kronos/docs/particles.html index 63a8f22f..aa13fc8d 100644 --- a/public/kronos/docs/particles.html +++ b/public/kronos/docs/particles.html @@ -6,13 +6,13 @@ Particles | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
          Skip to content

          Particles

          Particles are free-floating elements that can move and have many different behaviors. They can also interact with the mouse.

          To make particles, use makeParticles(particle, amount). particle is a particle-defining object, with features as explained below. There is also makeShinies, which uses different defaults and creates stationary particles at a random location. There are also a few other useful things listed at the end.

          js
          
          +    
          Skip to content

          Particles

          Particles are free-floating elements that can move and have many different behaviors. They can also interact with the mouse.

          To make particles, use makeParticles(particle, amount). particle is a particle-defining object, with features as explained below. There is also makeShinies, which uses different defaults and creates stationary particles at a random location. There are also a few other useful things listed at the end.

          js
          
           const myParticle {
               image:"options_wheel.png",
               spread: 20,
          @@ -44,8 +44,8 @@
                   return (Math.random() + 1.2) * 8 
               },
               etc...
          -}

          Features can be functions or constant. These features will be called when each particle is made, with an id argument, which is assigned based on which of the amount particles being spawned this is. All of these are optional, with a default value.

          All distances are in pixels and angles are in degrees, with 0 being up and going clockwise.

          • time: The amount of time, in seconds, that the particle will last. Default is 3.

          • fadeOutTime: The amount of seconds that fading out at the end should take (part of the total lifetime). Default is 1.

          • fadeInTime: The amount of seconds that fading in should take (part of the total lifetime). Default is 0.

          • image: The image the particle should display. "" will display no image. Default is a generic particle.

          • text: Displays text on the particle. Can use basic HTML.

          • style: Lets you apply other CSS styling to the particle.

          • width, height: The dimensions of the particle. Default is 35 and 35.

          • color: Sets the color of the image to this color.

          • angle: The angle that the particle should face. Default is 0.

          • dir: The initial angle that the particles should move in, before spread is factored in. Default is whatever angle is.

          • spread: If there are several particles, they will be spread out by this many degrees, centered on dir. Default is 30.

          • rotation: The amount that the (visual) angle of the particle should change by. Default is 0.

          • speed: The starting speed of the particle. Default is 15.

          • gravity: The amount the particle should accelerate downwards. Default is 0.

          • x, y: The starting coordinates of the particle. Default is at the mouse position.

          • offset: How far from the start each particle should appear. Default is 10.

          • xVel, yVel: Set initially based on other properties, then used to update movement.

          • layer: When changing tabs, if leaving the layer tab, this particle will be erased.

          • You can add other features to particles, but you must impliment their effects yourself.

          Function features: These stay as functions and are for more advanced things. They are optional.

          • update(): Called each tick. Lets you do more advanced visual and movement behaviors by changing other properties.
          • onClick(), onMouseOver(), onMouseLeave(): Called when the particle is interacted with.

          Other useful things that are not features of the particle object:

          • setDir(particle, dir), setSpeed(particle, speed): Set the speed/direction on a particle.
          • clearParticles(check): Function to delete particles. With no check, it deletes all particles. Check is a function that takes a particle, and returns true if that particle should be deleted.
          • You can use Vue.delete(particles, this.id) to make a particle delete itself.
          • mouseX and mouseY are variables that track the mouse position.
          • sin(x), cos(x), tan(x): functions that do these operations, with x in degrees. (Instead of radians).
          • asin(x), acos(x), atan(x): functions that do these operations, with the returned value in degrees. (instead of radians).
          - +}

          Features can be functions or constant. These features will be called when each particle is made, with an id argument, which is assigned based on which of the amount particles being spawned this is. All of these are optional, with a default value.

          All distances are in pixels and angles are in degrees, with 0 being up and going clockwise.

          • time: The amount of time, in seconds, that the particle will last. Default is 3.

          • fadeOutTime: The amount of seconds that fading out at the end should take (part of the total lifetime). Default is 1.

          • fadeInTime: The amount of seconds that fading in should take (part of the total lifetime). Default is 0.

          • image: The image the particle should display. "" will display no image. Default is a generic particle.

          • text: Displays text on the particle. Can use basic HTML.

          • style: Lets you apply other CSS styling to the particle.

          • width, height: The dimensions of the particle. Default is 35 and 35.

          • color: Sets the color of the image to this color.

          • angle: The angle that the particle should face. Default is 0.

          • dir: The initial angle that the particles should move in, before spread is factored in. Default is whatever angle is.

          • spread: If there are several particles, they will be spread out by this many degrees, centered on dir. Default is 30.

          • rotation: The amount that the (visual) angle of the particle should change by. Default is 0.

          • speed: The starting speed of the particle. Default is 15.

          • gravity: The amount the particle should accelerate downwards. Default is 0.

          • x, y: The starting coordinates of the particle. Default is at the mouse position.

          • offset: How far from the start each particle should appear. Default is 10.

          • xVel, yVel: Set initially based on other properties, then used to update movement.

          • layer: When changing tabs, if leaving the layer tab, this particle will be erased.

          • You can add other features to particles, but you must impliment their effects yourself.

          Function features: These stay as functions and are for more advanced things. They are optional.

          • update(): Called each tick. Lets you do more advanced visual and movement behaviors by changing other properties.
          • onClick(), onMouseOver(), onMouseLeave(): Called when the particle is interacted with.

          Other useful things that are not features of the particle object:

          • setDir(particle, dir), setSpeed(particle, speed): Set the speed/direction on a particle.
          • clearParticles(check): Function to delete particles. With no check, it deletes all particles. Check is a function that takes a particle, and returns true if that particle should be deleted.
          • You can use Vue.delete(particles, this.id) to make a particle delete itself.
          • mouseX and mouseY are variables that track the mouse position.
          • sin(x), cos(x), tan(x): functions that do these operations, with x in degrees. (Instead of radians).
          • asin(x), acos(x), atan(x): functions that do these operations, with the returned value in degrees. (instead of radians).
          + \ No newline at end of file diff --git a/public/kronos/docs/subtabs-and-microtabs.html b/public/kronos/docs/subtabs-and-microtabs.html index 2baf50ec..04225cce 100644 --- a/public/kronos/docs/subtabs-and-microtabs.html +++ b/public/kronos/docs/subtabs-and-microtabs.html @@ -6,13 +6,13 @@ Subtabs and Microtabs | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
          Skip to content

          Subtabs and Microtabs

          Subtabs are separate sections of a tab that you can view by selecting one at the top of the tab. Microtabs are smaller areas that function in much the same way. You can also embed layers inside of subtabs/microtabs.

          Subtabs are defined by using the tab format like this, where each element of tabFormat is given the name of that subtab:

          js
          tabFormat: {
          +    
          Skip to content

          Subtabs and Microtabs

          Subtabs are separate sections of a tab that you can view by selecting one at the top of the tab. Microtabs are smaller areas that function in much the same way. You can also embed layers inside of subtabs/microtabs.

          Subtabs are defined by using the tab format like this, where each element of tabFormat is given the name of that subtab:

          js
          tabFormat: {
               "Main tab": {
                   content: [tab format things],
                   *subtab features*
          @@ -58,8 +58,8 @@
               otherStuff: {
                   // There could be another set of microtabs here
               }
          -}

          Normal subtabs and microtab subtabs both use the same features:

          Features:

          • content: The tab layout code for the subtab, in the tab layout format.

          • style: optional. Applies CSS to the whole subtab when switched to, in the form of an "CSS Object", where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • buttonStyle: optional. A CSS object, which affects the appearance of the button for that subtab.

          • unlocked(): optional. a function to determine if the button for this subtab should be visible. By default, a subtab is always unlocked. You can't use the "this" keyword in this function.

          • shouldNotify()/prestigeNotify(): optional, if true, the tab button will be highlighted to notify the player that there is something there.

          • glowColor: optional, specifies the color that the subtab glows. If this subtab is causing the main layer to node glow (and it would't otherwise) the node also glows this color. Is NOT overridden by embedding a layer.

          • embedLayer: SIGNIFICANT, the id of another layer. If you have this, it will override "content", "style" and "shouldNotify", instead displaying the entire layer in the subtab.

          - +}

          Normal subtabs and microtab subtabs both use the same features:

          Features:

          • content: The tab layout code for the subtab, in the tab layout format.

          • style: optional. Applies CSS to the whole subtab when switched to, in the form of an "CSS Object", where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • buttonStyle: optional. A CSS object, which affects the appearance of the button for that subtab.

          • unlocked(): optional. a function to determine if the button for this subtab should be visible. By default, a subtab is always unlocked. You can't use the "this" keyword in this function.

          • shouldNotify()/prestigeNotify(): optional, if true, the tab button will be highlighted to notify the player that there is something there.

          • glowColor: optional, specifies the color that the subtab glows. If this subtab is causing the main layer to node glow (and it would't otherwise) the node also glows this color. Is NOT overridden by embedding a layer.

          • embedLayer: SIGNIFICANT, the id of another layer. If you have this, it will override "content", "style" and "shouldNotify", instead displaying the entire layer in the subtab.

          + \ No newline at end of file diff --git a/public/kronos/docs/trees-and-tree-customization.html b/public/kronos/docs/trees-and-tree-customization.html index 139406f7..d63a8044 100644 --- a/public/kronos/docs/trees-and-tree-customization.html +++ b/public/kronos/docs/trees-and-tree-customization.html @@ -6,13 +6,13 @@ Trees and tree customization | The Paper Pilot - + - + - - - + + + @@ -34,10 +34,10 @@ -
          Skip to content

          Trees and tree customization

          If you want to have something beyond the standard tree on the left tab, you can do that in tree.js. You can change the layout of the tree, including making non-layer nodes, change it into something other than a tree, or hide the left tab altogether. This also introduces the "tree" component, which can be used in your layers as well.

          layoutInfo

          The most important part is layoutInfo, containing:

          • startTab: The id of the default tab to show on the left at the start.
          • showTree: True if the tree tab should be shown at the start of the game. (The other tab will fill the whole page)
          • treeLayout: If present, overrides the tree layout and places nodes as you describe instead (explained in the next section).

          Additionally, if you want the main layout to not be a tree, you can edit the "tree-tab" layer at the bottom of tree.js to modify it just like a normal layer's tab. You can even switch between left tabs, using showNavTab(layer) to make that layer appear on the left.

          Trees

          The tree component is defined as an array of arrays of names of layers or nodes to show in the tree. They work just like layers/ nodes in the main tree (but branches between nodes will only work on the first node if you have duplicates.)

          Here is an example tree:

          js
          [["p"],
          +    
          Skip to content

          Trees and tree customization

          If you want to have something beyond the standard tree on the left tab, you can do that in tree.js. You can change the layout of the tree, including making non-layer nodes, change it into something other than a tree, or hide the left tab altogether. This also introduces the "tree" component, which can be used in your layers as well.

          layoutInfo

          The most important part is layoutInfo, containing:

          • startTab: The id of the default tab to show on the left at the start.
          • showTree: True if the tree tab should be shown at the start of the game. (The other tab will fill the whole page)
          • treeLayout: If present, overrides the tree layout and places nodes as you describe instead (explained in the next section).

          Additionally, if you want the main layout to not be a tree, you can edit the "tree-tab" layer at the bottom of tree.js to modify it just like a normal layer's tab. You can even switch between left tabs, using showNavTab(layer) to make that layer appear on the left.

          Trees

          The tree component is defined as an array of arrays of names of layers or nodes to show in the tree. They work just like layers/ nodes in the main tree (but branches between nodes will only work on the first node if you have duplicates.)

          Here is an example tree:

          js
          [["p"],
            ["left", "blank", "right", "blank"]
          - ["a", "b", "blank", "c", "weirdButton"]]

          Nodes

          Nodes are non-layer buttons that can go in trees. They are defined similarly to layers, but with addNode instead of addLayer.

          Features:

          • color: optional, The node's color. (A string in hex format with a #)

          • symbol: optional The text on the button (The id capitalized by default)

          • canClick(): Returns true if the player can click the node. ()

          • onClick(): The function called when the node is clicked.

          • layerShown(): optional, A function returning a bool which determines if this node should be visible. It can also return "ghost", which will hide the layer, but its node will still take up space in its tree.

          • branches: optional. An array of layer/node ids. On a tree, a line will appear from this node to all of the nodes in the list. Alternatively, an entry in the array can be a 2-element array consisting of the id and a color value. The color value can either be a string with a hex color code, or a number from 1-3 (theme-affected colors).

          • nodeStyle: optional. A CSS object, where the keys are CSS attributes, which styles this node on the tree.

          • tooltip() / tooltipLocked(): optional. Functions that return text, which is the tooltip for the node when the layer is unlocked or locked, respectively. By default the tooltips behave the same as in the original Prestige Tree.

          • row: optional, the row that this node appears in (for the default tree).

          • position: optional, Determines the horizontal position of the layer in its row in a default tree. By default, it uses the id, and layers/nodes are sorted in alphabetical order.

          - + ["a", "b", "blank", "c", "weirdButton"]]

          Nodes

          Nodes are non-layer buttons that can go in trees. They are defined similarly to layers, but with addNode instead of addLayer.

          Features:

          • color: optional, The node's color. (A string in hex format with a #)

          • symbol: optional The text on the button (The id capitalized by default)

          • canClick(): Returns true if the player can click the node. ()

          • onClick(): The function called when the node is clicked.

          • layerShown(): optional, A function returning a bool which determines if this node should be visible. It can also return "ghost", which will hide the layer, but its node will still take up space in its tree.

          • branches: optional. An array of layer/node ids. On a tree, a line will appear from this node to all of the nodes in the list. Alternatively, an entry in the array can be a 2-element array consisting of the id and a color value. The color value can either be a string with a hex color code, or a number from 1-3 (theme-affected colors).

          • nodeStyle: optional. A CSS object, where the keys are CSS attributes, which styles this node on the tree.

          • tooltip() / tooltipLocked(): optional. Functions that return text, which is the tooltip for the node when the layer is unlocked or locked, respectively. By default the tooltips behave the same as in the original Prestige Tree.

          • row: optional, the row that this node appears in (for the default tree).

          • position: optional, Determines the horizontal position of the layer in its row in a default tree. By default, it uses the id, and layers/nodes are sorted in alphabetical order.

          + \ No newline at end of file diff --git a/public/kronos/docs/updating-tmt.html b/public/kronos/docs/updating-tmt.html index 46401488..8178167e 100644 --- a/public/kronos/docs/updating-tmt.html +++ b/public/kronos/docs/updating-tmt.html @@ -6,13 +6,13 @@ Updating The Modding Tree | The Paper Pilot - + - + - - - + + + @@ -34,8 +34,8 @@ -
          Skip to content

          Updating The Modding Tree

          This tutorial assumes that you have used the Getting Started Tutorial, and are using Github Desktop and VSCode for your mod.

          Here's what you have to do when there's a TMT update:

          1. Look at the changelog. It will warn you if the update will break anything or require any changes. Decide if you want to try to update.

          2. Open Github Desktop, and at the top middle, click "fetch origin". This will make Github Desktop get information about the update.

          3. Click where it says "current branch: master" at the top middle, and at the bottom of the thing that appears, click "choose a branch to merge into master".

          4. Select upstream/master. It will likely say there are conflicts, but you have tools to resolve them. Click "Merge upstream/master into master".

          5. A conflict happens when the things you're trying to merge have both made changes in the same place. Click "open in Visual Studio Code" next to the first file.

          6. Scroll down through the file, and look for the parts highlighted in red and green. One of these is your code, and the other is some code that will be modified by the update. Do your best to try to edit things to keep the updated changes, but keep your content.

          7. Continue to do this for all remaining changes.

          8. Do any other changes required by the update, run the game, fix issues, etc.

          - +
          Skip to content

          Updating The Modding Tree

          This tutorial assumes that you have used the Getting Started Tutorial, and are using Github Desktop and VSCode for your mod.

          Here's what you have to do when there's a TMT update:

          1. Look at the changelog. It will warn you if the update will break anything or require any changes. Decide if you want to try to update.

          2. Open Github Desktop, and at the top middle, click "fetch origin". This will make Github Desktop get information about the update.

          3. Click where it says "current branch: master" at the top middle, and at the bottom of the thing that appears, click "choose a branch to merge into master".

          4. Select upstream/master. It will likely say there are conflicts, but you have tools to resolve them. Click "Merge upstream/master into master".

          5. A conflict happens when the things you're trying to merge have both made changes in the same place. Click "open in Visual Studio Code" next to the first file.

          6. Scroll down through the file, and look for the parts highlighted in red and green. One of these is your code, and the other is some code that will be modified by the update. Do your best to try to edit things to keep the updated changes, but keep your content.

          7. Continue to do this for all remaining changes.

          8. Do any other changes required by the update, run the game, fix issues, etc.

          + \ No newline at end of file diff --git a/public/kronos/docs/upgrades.html b/public/kronos/docs/upgrades.html index a0e8e715..92a4c34c 100644 --- a/public/kronos/docs/upgrades.html +++ b/public/kronos/docs/upgrades.html @@ -6,13 +6,13 @@ Upgrades | The Paper Pilot - + - + - - - + + + @@ -34,15 +34,15 @@ -
          Skip to content

          Upgrades

          Useful functions for dealing with Upgrades and implementing their effects:

          • hasUpgrade(layer, id): determine if the player has the upgrade
          • upgradeEffect(layer, id): Returns the current effects of the upgrade, if any
          • buyUpgrade(layer, id): Buys an upgrade directly (if affordable)

          Hint: Basic point gain is calculated in mod.js's "getPointGen" function.

          Upgrades are stored in the following format:

          js
          upgrades: {
          +    
          Skip to content

          Upgrades

          Useful functions for dealing with Upgrades and implementing their effects:

          • hasUpgrade(layer, id): determine if the player has the upgrade
          • upgradeEffect(layer, id): Returns the current effects of the upgrade, if any
          • buyUpgrade(layer, id): Buys an upgrade directly (if affordable)

          Hint: Basic point gain is calculated in mod.js's "getPointGen" function.

          Upgrades are stored in the following format:

          js
          upgrades: {
               11: {
                   description: "Blah",
                   cost: new Decimal(100),
                   etc
               },
               etc
          -}

          Usually, upgrades should have an id where the first digit is the row and the second digit is the column.

          Individual upgrades can have these features:

          • title: optional. Displayed at the top in a larger font. It can also be a function that returns updating text. Can use basic HTML.

          • description: A description of the upgrade's effect. You will also have to implement the effect where it is applied. It can also be a function that returns updating text. Can use basic HTML.

          • effect(): optional. A function that calculates and returns the current values of any bonuses from the upgrade. Can return a value or an object containing multiple values.

          • effectDisplay(): optional. A function that returns a display of the current effects of the upgrade with formatting. Default displays nothing. Can use basic HTML.

          • fullDisplay(): OVERRIDE. Overrides the other displays and descriptions, and lets you set the full text for the upgrade. Can use basic HTML.

          • cost: A Decimal for the cost of the upgrade. By default, upgrades cost the main prestige currency for the layer.

          • unlocked(): optional. A function returning a bool to determine if the upgrade is visible or not. Default is unlocked.

          • onPurchase(): optional. This function will be called when the upgrade is purchased. Good for upgrades like "makes this layer act like it was unlocked first".

          • style: optional. Applies CSS to this upgrade, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the upgrade was stored under, for convenient access. The upgrade in the example's id is 11.

          By default, upgrades use the main prestige currency for the layer. You can include these to change them (but it needs to be a Decimal):

          • currencyDisplayName: optional. The name to display for the currency for the upgrade.

          • currencyInternalName: optional. The internal name for that currency.

          • currencyLayer: optional. The internal name of the layer that currency is stored in. If it's not in a layer (like Points), omit. If it's not stored directly in a layer, instead use the next feature.

          • currencyLocation: optional. If your currency is stored in something inside a layer (e.g. a buyable's amount), you can access it this way. This is a function returning the object in "player" that contains the value (like player[this.layer].buyables)

          If you want to do something more complicated like upgrades that cost two currencies, you can override the purchase system with these (and you need to use fullDisplay as well)

          • canAfford(): OVERRIDE, a function determining if you are able to buy the upgrade

          • pay(): OVERRIDE, a function that reduces your currencies when you buy the upgrade

          - +}

          Usually, upgrades should have an id where the first digit is the row and the second digit is the column.

          Individual upgrades can have these features:

          • title: optional. Displayed at the top in a larger font. It can also be a function that returns updating text. Can use basic HTML.

          • description: A description of the upgrade's effect. You will also have to implement the effect where it is applied. It can also be a function that returns updating text. Can use basic HTML.

          • effect(): optional. A function that calculates and returns the current values of any bonuses from the upgrade. Can return a value or an object containing multiple values.

          • effectDisplay(): optional. A function that returns a display of the current effects of the upgrade with formatting. Default displays nothing. Can use basic HTML.

          • fullDisplay(): OVERRIDE. Overrides the other displays and descriptions, and lets you set the full text for the upgrade. Can use basic HTML.

          • cost: A Decimal for the cost of the upgrade. By default, upgrades cost the main prestige currency for the layer.

          • unlocked(): optional. A function returning a bool to determine if the upgrade is visible or not. Default is unlocked.

          • onPurchase(): optional. This function will be called when the upgrade is purchased. Good for upgrades like "makes this layer act like it was unlocked first".

          • style: optional. Applies CSS to this upgrade, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the upgrade was stored under, for convenient access. The upgrade in the example's id is 11.

          By default, upgrades use the main prestige currency for the layer. You can include these to change them (but it needs to be a Decimal):

          • currencyDisplayName: optional. The name to display for the currency for the upgrade.

          • currencyInternalName: optional. The internal name for that currency.

          • currencyLayer: optional. The internal name of the layer that currency is stored in. If it's not in a layer (like Points), omit. If it's not stored directly in a layer, instead use the next feature.

          • currencyLocation: optional. If your currency is stored in something inside a layer (e.g. a buyable's amount), you can access it this way. This is a function returning the object in "player" that contains the value (like player[this.layer].buyables)

          If you want to do something more complicated like upgrades that cost two currencies, you can override the purchase system with these (and you need to use fullDisplay as well)

          • canAfford(): OVERRIDE, a function determining if you are able to buy the upgrade

          • pay(): OVERRIDE, a function that reduces your currencies when you buy the upgrade

          + \ No newline at end of file diff --git a/public/lit/Old Things/2.0-format-changes.html b/public/lit/Old Things/2.0-format-changes.html index 42cb0f5a..ca726470 100644 --- a/public/lit/Old Things/2.0-format-changes.html +++ b/public/lit/Old Things/2.0-format-changes.html @@ -6,13 +6,13 @@ 2.0 format changes | The Paper Pilot - + - + - - - + + + @@ -34,8 +34,8 @@ -
          Skip to content

          2.0 format changes

          • Temp format is changed from temp.something[layer] to temp[layer].something, for consistency
          • Challenges are now saved as an object with the amount of completions in each spot. (This will break saves.)
          • effectDisplay in Challenges and Upgrades no longer takes an argument, and neither does effect for Buyables
          • Buyable cost can take an argument for amount of buyables, but it needs to function if no argument is supplied (it should do the cost for the next purchase).
          • Generation of Points now happens in the main game loop (not in a layer update function), enabled by canGenPoints in game.js.
          • Changed fullLayerReset to layerDataReset, which takes an array of names of values to keep

          In addition, many names were changed, mostly expanding abbreviations:

          All instances of:

          • chall -> challenge
          • unl -> unlocked
          • upg -> upgrade (besides CSS)
          • amt -> amount
          • desc -> description
          • resCeil -> roundUpCost
          • order -> unlockOrder
          • incr_order -> increaseUnlockOrder

          Challenges:

          • desc -> challengeDescription
          • reward -> rewardDescription
          • effect -> rewardEffect
          • effectDisplay -> rewardDisplay
          • active -> challengeActive
          - +
          Skip to content

          2.0 format changes

          • Temp format is changed from temp.something[layer] to temp[layer].something, for consistency
          • Challenges are now saved as an object with the amount of completions in each spot. (This will break saves.)
          • effectDisplay in Challenges and Upgrades no longer takes an argument, and neither does effect for Buyables
          • Buyable cost can take an argument for amount of buyables, but it needs to function if no argument is supplied (it should do the cost for the next purchase).
          • Generation of Points now happens in the main game loop (not in a layer update function), enabled by canGenPoints in game.js.
          • Changed fullLayerReset to layerDataReset, which takes an array of names of values to keep

          In addition, many names were changed, mostly expanding abbreviations:

          All instances of:

          • chall -> challenge
          • unl -> unlocked
          • upg -> upgrade (besides CSS)
          • amt -> amount
          • desc -> description
          • resCeil -> roundUpCost
          • order -> unlockOrder
          • incr_order -> increaseUnlockOrder

          Challenges:

          • desc -> challengeDescription
          • reward -> rewardDescription
          • effect -> rewardEffect
          • effectDisplay -> rewardDisplay
          • active -> challengeActive
          + \ No newline at end of file diff --git a/public/lit/README.html b/public/lit/README.html index 3d636cd3..cd3bb09f 100644 --- a/public/lit/README.html +++ b/public/lit/README.html @@ -6,13 +6,13 @@ Kronos | The Paper Pilot - + - + - - - + + + @@ -34,8 +34,8 @@ -
          Skip to content

          Kronos

          Play here.

          Updating the website:

          • git submodule update --remote
          • git add -A
          • git commit -m "Updated kronos"
          • git push
          - +
          Skip to content

          Kronos

          Play here.

          Updating the website:

          • git submodule update --remote
          • git add -A
          • git commit -m "Updated kronos"
          • git push
          + \ No newline at end of file diff --git a/public/lit/changelog.html b/public/lit/changelog.html index dde96d26..c5f5cfc6 100644 --- a/public/lit/changelog.html +++ b/public/lit/changelog.html @@ -6,13 +6,13 @@ The Modding Tree changelog: | The Paper Pilot - + - + - - - + + + @@ -34,8 +34,8 @@ -
          Skip to content

          The Modding Tree changelog:

          v2.π: Incrementally Updated - 2/5/21

          • Performance improvements.
          • Fixed tooltips overlapping with the top display.
          • Clicking a popup dismisses it immediately.
          • Added support for bulk challenge completions.
          • "Best" is updated automatically.
          • Fixed keeping Decimal values on reset.
          • Code reorganization and style improvements by fudo.

          v2.3.5 - 12/21/20

          • Added resetTime, which tracks the time since a layer prestiged or was reset.
          • A layer node will be highlighted red if one of its subtabs is highlighted red.
          • Fixed issues with keeping challenges, buyables, and clickables on reset.
          • Improved the unlocking of custom layers.
          • Other minor fixes.

          v2.3.4 - 12/16/20

          • Added a node image feature.
          • Resource display now always shows the amount of the currency the layer's gain is based on.
          • Added spacing between tree nodes.
          • Another attempt to fix tooltip flickering.

          v2.3.3 - 12/13/20

          • Fixed the first node in a row always taking up space.
          • layerShown is now optional.
          • All prestige types can now use features for custom prestige types.

          v2.3.2 - 12/13/20

          • Fixed achievement/milestone popups.

          v2.3.1 - 12/12/20

          • Another attempt to fix flickering tooltips.
          • The "this" keyword should work everywhere except tabFormat arrays (although I may have missed some things).
          • Fixed tree branches not updating when scrolling on the right-side tab.
          • Fixed a spacing issue when a node's symbol is ""
          • Removed some old, unneeded files.

          v2.3: Cooler and Newer Edition - 12/10/20

          • Added achievement/milestone popups (thank you to Jacorb for this contribution!)
          • The changelog tab is back, and can be set in mod.js.
          • Layer nodes and respec buttons will not be clicked by pressing "enter".
          • Possible fix for flickering tooltips and strange transitions.
          • The victory screen text is configurable.
          • Added image and textStyle features to achievements.
          • Added an argument to use specific rows in an "upgrades" component.
          • Fixed the comma appearing in the main display when there was no effectDescription
          • Added the ability to easily make a tab that is a collection of layers in subtabs.
          • Improved spacing for embedding layers with subtabs into subtabs.

          v2.2.8 - 12/03/20

          • Double-clicking a layer node brings you to the main subtab for that layer.
          • Attempted to fix challenges visually updating a different way.
          • Added a softcap function for use in formulas.
          • Added displayRow feature, which lets layers be shown somewhere separate from where they are in the reset order (e.g. side layers)
          • Fixed autoupgrade issue.

          v2.2.7 - 11/30/20

          • Added autoUpgrade feature.
          • resource-display now shows resource gain per second if passiveGain is active.
          • Fixed formatting issues on some large numbers.
          • Better support for using classed objects in player and in layers/tmp.
          • Made hard resetting more effective.
          • Removed Herobrine from getStartClickables.

          v2.2.6 - 11/30/20

          • Added goalDescription for challenges and made the new "canComplete" system the standard.
          • Another attempt to fix challenges not visually updating.
          • Fixed side layers not appearing.
          • Fixed getStartClickables again.

          v2.2.5 - 11/29/20

          • Added features for overriding the displays and costs/goals of upgrades and challenges to make them fully custom.
          • best, total, and unlocked are always automatically added to layerData (but best and total will only display if you add them yourself).
          • Fixed getStartClickables.

          v2.2.4 - 11/28/20

          • Added softcap and softcapPower features (for Normal layers)
          • Offline time limit and default max tick length were fixed (previously the limits were 1000x too large)
          • Added fixOldSaves.
          • You can use HTML in main-display.
          • Fixed a number of minor oddities.

          v2.2.3 - 11/28/20

          • Layers will be highlighted if you can finish a challenge.
          • The "can complete challenge" color now overrides the "already completed" color.
          • Button nodes now work as side "layers".
          • Setting a tooltip to "" hides it entirely.

          v2.2.2 - 11/22/20

          • Fixed right half of the screen being unclickable in some circumstances.
          • Fixed tree branches being offset.
          • Fix to lastSafeTab.

          v2.2.1 - 11/7/20

          • Added a small highlight to layers you can meaningfully prestige on.
          • Added passiveGeneration and autoPrestige features to standardize prestige automation. (The old ways still work, but the new ones work better with other things)
          • Improved milestones visually a bit.
          • "best" and "total" are now only displayed if present in startData.
          • Fixed issues with things not updating visually. (Thank you to to Jacorb!)
          • Side layers and button nodes can now be highlighted.
          • Updated docs on the new tree-related features.

          v2.2: Uprooted - 11/7/20

          • You can now embed a layer inside of a subtab or microtab!
          • Added support for hiding or reformatting the tree tab
          • Added non-layer button nodes
          • Added shouldNotify to subtab/microtab buttons. (You can make them highlighted)
          • Added commas to large exponents.
          • Upgrades now only show "currently" if they have an effectDisplay (so not for constant effects).
          • Achievements are part of the default tab format.
          • NaN is now handled more intelligently.
          • Renamed files, and moved less relevant ones to another folder.
          • The "hide completed challenges" setting now only hides challenges at max completions.
          • Thank you to thepaperpilot for fixing errors in docs and improving the infobox appearance!
          • Many other minor fixes.

          v2.1.4 - 10/25/20

          • Added an infobox component. Thank you to thepaperpilot for this contribution!
          • Layer type is now optional, and defaults to "none".
          • Improved the look of bars and tab buttons.
          • Improved spacing between layer nodes (also thanks to thepaperpilot!)
          • Fixed the "blank" component breaking if only specifying the height.
          • Fixed some numbers not displaying with enough digits.
          • Made a few more things able to be functions.
          • A few other minor fixes.

          v2.1.3.1 - 10/21/20

          • Fixed the update function.

          v2.1.3 - 10/21/20

          • gainMult and gainExp are now optional.
          • Layer unlocking is now kept on reset.
          • Game should start up faster.
          • Layer updates now have a determined order and starts with earlier-rowed layers.
          • Automation now has a determined order and starts with later-rowed layers.
          • Fixed issues with resetting clickables and challenges.
          • Commas should no longer appear in the decimal places of a number.
          • Fixed potential issue in displaying the tree.

          v2.1.2 - 10/19/20

          • Added buyUpgrade function (buyUpg still works though)
          • Added author name to modInfo.
          • Fix to crash caused when the name of a subtab or microtab is changed.
          • Fixes to outdated information in docs.
          • Improvements to Discord links.
          • Thank you to thepaperpilot for contributing to this update!

          v2.1.1 - 10/17/20

          • Added resource-display component, which displays the base currency for the prestige layer, as well as the best and/or total of this layer's prestige currency.
          • Fixed the value for the base currency not updating in resource-display.

          v2.1: We should have thought of this sooner! - 10/17/20

          • Moved most of the code users will want to edit to mod.js, added documentation for it.
            • Specifically, modInfo, VERSION, canGenPoints, getPointGen, and maxTickLength
          • Added getStartPoints()
          • Added the ability to store non-layer-related data
          • Added the ability to display more things at the top of the tree tab below points.
          • Made the endgame condition customizable
          • Added "sell one" and "sell all" buttons for buyables.
          • Moved the old "game" to demo.js, and replaced it with a minimal game that won't cause issues when edited.
          • Fixed issues with version number
          • Fixed number formatting issue making things like "10e9" appear.

          v2.0.5 - 10/16/20

          • Made more features (including prestige parameters) able to be dynamic.
          • Layer nodes can be hidden but still take up space with "ghost" visibility
          • Added clickableEffect for real.
          • Fixed some visual issues with bars.
          • A few other minor tweaks and improvements.

          v2.0.4 - 10/16/20

          • Fixed HTML on buttons interfering with clicking on them.

          v2.0.3 - 10/16/20

          • Fixed hotkeys not displaying in info.
          • Fixed the game supressing all external hotkeys.
          • You can use more things as currencies for upgrade costs and challenge goals using currencyLocation.
          • Added maxTickLength, which can be used to prevent offline time or tab-switching from breaking time-limit based mechanics.
          • Made buyable respec buttons and clickable "master" buttons their own components, and gave them a hide/show feature.
          • Added a general "tooltip" feature for achievements.

          v2.0.2 - 10/15/20

          • Branches are now dynamic (they can be functions).
          • Fixed a crash related to offline time.
          • Fixed links being too wide.

          v2.0.1 - 10/15/20

          • Fixed side layers appearing multiple times.

          v2.0: The Pinnacle of Achievement Mountain - 10/15/20

          • Added progress bars, which are highly customizable and can be horizontal or vertical!
          • Added "side layers", displayed smaller and off to the side, and don't get reset by default. They can be used for global achievements and statistics. Speaking of which...
          • Added achievements!
          • Added clickables, a more generalized variant of buyables.
          • Almost every value in layer data can be either a function or a constant value!
          • Added support for multiple completions of challenges.
          • Added "none" prestige type, which removes the need for any other prestige-related features.
          • The points display and other gui elements stay at the top of the screen when the tree scrolls.
          • Added getter/setter functions for the amounts and effects of most Big Features
          • Moved modInfo to game.js, added a spot in modInfo for a Discord link, changelog link. Also added a separate mod version from the TMT version in VERSION.
          • Tree structure is based on layer data, no index.html editing is needed.
          • Tmp does not need to be manually updated.
          • You don't have to have the same amount of upgrades in every row (and challs and buyables)
          • "unlocked" is optional for all Big Components (defaults to true).
          • All displays will update correctly.
          • Changelog is no longer in index.html at all.
          • Generation of Points now happens in the main game loop
          • Changed the reset functions to make keeping things easier
          • Renamed many things to increase readability (see the list in the link below)
          • Improved documentation based on feedback

          v1.3.5:

          • Completely automated convertToDecimal, now you never have to worry about it again.
          • Branches can be defined without a color id. But they can also use hex values for color ids!
          • Created a tutorial for getting started with TMT and Github.
          • Page title is now automatically taken from mod name.

          v1.3.4 - 10/8/20

          • Added "midsection" feature to add things to a tab's layout while still keeping the standard layout.
          • Fix for being able to buy more buyables than you should.

          v1.3.3 - 10/7/20

          • Fix for the "order of operations" issue in temp.

          v1.3.1 - 10/7/20

          • Added custom CSS and tooltips for Layer Nodes.
          • Added custom CSS for upgrades, buyables, milestones, and challenges, both individually and layer-wide.
          • You can now use HTML in most display text!
          • You can now make milestones unlockable and not display immediately.
          • Fixed importing saves, and issue with upgrades not appearing, and probably more.
          • Optional "name" layer feature, used in confirmation messages.

          v1.3: Tabception... ception! - 10/7/20

          • Added subtabs! And also a Micro-tab component to let you make smaller subtab-esque areas anywhere.
          • Added a "custom" prestige formula type, and a number of features to support it.
          • Added points/sec display (can be disabled).
          • Added h-line, v-line and image-display components, plus components for individual upgrades, challenges, and milestones.
          • Added upgEffect, buyableEffect, and challEffect functions.
          • Added "hide completed challenges" setting.
          • Moved old changelogs to a separate place.
          • Fixed hasMilestone and incr_order.
          • Static layers now show the currency amount needed for the next one if you can buy max.

          v1.2.4 - 10/4/20

          • Layers are now highlighted if you can buy an upgrade, and a new feature, shouldNotify, lets you make it highlight other ways.
          • Fixed bugs with hasUpg, hasChall, hasMilestone, and inChallenge.
          • Changed the sample code to use the above functions for convenience.

          v1.2.3 - 10/3/20

          • Added a row component, which displays a list of objects in a row.
          • Added a column component, which displays a list of objects in a column (useful within a row).
          • Changed blanks to have a customizable width and height.

          v1.2: This Changes Everything! - 10/3/20

          • Many layer features can now be static values or functions. (This made some formats change, which will break old things)
          • You can now use the "this" keyword, to make code easier to transfer when making new layers.
          • Also added "this.layer", which is the current layer's name, and works on existing subfeatures (e.g. individual upgrades) as well! Subfeatures also have "this.id".
          • Fixed a big save issue. If you use a unique mod id, your save will never conflict with other mods.
          • Added a configurable offline time limit in modinfo at the top of index.html. (default 1 hour)
          • Added a few minor features, and updated the docs with new information.

          v1.1.1:

          • You can define hotkeys directly from layer config.

          v1.1: Enhanced Edition

          • Added "Buyables", which can function like Space Buildings or Enhancers.
          • Custom CSS can now be used on any component! Make the third argument an object with CSS parameters.
          • Lots of minor good things.

          v1.0:

          • First release.
          - +
          Skip to content

          The Modding Tree changelog:

          v2.π: Incrementally Updated - 2/5/21

          • Performance improvements.
          • Fixed tooltips overlapping with the top display.
          • Clicking a popup dismisses it immediately.
          • Added support for bulk challenge completions.
          • "Best" is updated automatically.
          • Fixed keeping Decimal values on reset.
          • Code reorganization and style improvements by fudo.

          v2.3.5 - 12/21/20

          • Added resetTime, which tracks the time since a layer prestiged or was reset.
          • A layer node will be highlighted red if one of its subtabs is highlighted red.
          • Fixed issues with keeping challenges, buyables, and clickables on reset.
          • Improved the unlocking of custom layers.
          • Other minor fixes.

          v2.3.4 - 12/16/20

          • Added a node image feature.
          • Resource display now always shows the amount of the currency the layer's gain is based on.
          • Added spacing between tree nodes.
          • Another attempt to fix tooltip flickering.

          v2.3.3 - 12/13/20

          • Fixed the first node in a row always taking up space.
          • layerShown is now optional.
          • All prestige types can now use features for custom prestige types.

          v2.3.2 - 12/13/20

          • Fixed achievement/milestone popups.

          v2.3.1 - 12/12/20

          • Another attempt to fix flickering tooltips.
          • The "this" keyword should work everywhere except tabFormat arrays (although I may have missed some things).
          • Fixed tree branches not updating when scrolling on the right-side tab.
          • Fixed a spacing issue when a node's symbol is ""
          • Removed some old, unneeded files.

          v2.3: Cooler and Newer Edition - 12/10/20

          • Added achievement/milestone popups (thank you to Jacorb for this contribution!)
          • The changelog tab is back, and can be set in mod.js.
          • Layer nodes and respec buttons will not be clicked by pressing "enter".
          • Possible fix for flickering tooltips and strange transitions.
          • The victory screen text is configurable.
          • Added image and textStyle features to achievements.
          • Added an argument to use specific rows in an "upgrades" component.
          • Fixed the comma appearing in the main display when there was no effectDescription
          • Added the ability to easily make a tab that is a collection of layers in subtabs.
          • Improved spacing for embedding layers with subtabs into subtabs.

          v2.2.8 - 12/03/20

          • Double-clicking a layer node brings you to the main subtab for that layer.
          • Attempted to fix challenges visually updating a different way.
          • Added a softcap function for use in formulas.
          • Added displayRow feature, which lets layers be shown somewhere separate from where they are in the reset order (e.g. side layers)
          • Fixed autoupgrade issue.

          v2.2.7 - 11/30/20

          • Added autoUpgrade feature.
          • resource-display now shows resource gain per second if passiveGain is active.
          • Fixed formatting issues on some large numbers.
          • Better support for using classed objects in player and in layers/tmp.
          • Made hard resetting more effective.
          • Removed Herobrine from getStartClickables.

          v2.2.6 - 11/30/20

          • Added goalDescription for challenges and made the new "canComplete" system the standard.
          • Another attempt to fix challenges not visually updating.
          • Fixed side layers not appearing.
          • Fixed getStartClickables again.

          v2.2.5 - 11/29/20

          • Added features for overriding the displays and costs/goals of upgrades and challenges to make them fully custom.
          • best, total, and unlocked are always automatically added to layerData (but best and total will only display if you add them yourself).
          • Fixed getStartClickables.

          v2.2.4 - 11/28/20

          • Added softcap and softcapPower features (for Normal layers)
          • Offline time limit and default max tick length were fixed (previously the limits were 1000x too large)
          • Added fixOldSaves.
          • You can use HTML in main-display.
          • Fixed a number of minor oddities.

          v2.2.3 - 11/28/20

          • Layers will be highlighted if you can finish a challenge.
          • The "can complete challenge" color now overrides the "already completed" color.
          • Button nodes now work as side "layers".
          • Setting a tooltip to "" hides it entirely.

          v2.2.2 - 11/22/20

          • Fixed right half of the screen being unclickable in some circumstances.
          • Fixed tree branches being offset.
          • Fix to lastSafeTab.

          v2.2.1 - 11/7/20

          • Added a small highlight to layers you can meaningfully prestige on.
          • Added passiveGeneration and autoPrestige features to standardize prestige automation. (The old ways still work, but the new ones work better with other things)
          • Improved milestones visually a bit.
          • "best" and "total" are now only displayed if present in startData.
          • Fixed issues with things not updating visually. (Thank you to to Jacorb!)
          • Side layers and button nodes can now be highlighted.
          • Updated docs on the new tree-related features.

          v2.2: Uprooted - 11/7/20

          • You can now embed a layer inside of a subtab or microtab!
          • Added support for hiding or reformatting the tree tab
          • Added non-layer button nodes
          • Added shouldNotify to subtab/microtab buttons. (You can make them highlighted)
          • Added commas to large exponents.
          • Upgrades now only show "currently" if they have an effectDisplay (so not for constant effects).
          • Achievements are part of the default tab format.
          • NaN is now handled more intelligently.
          • Renamed files, and moved less relevant ones to another folder.
          • The "hide completed challenges" setting now only hides challenges at max completions.
          • Thank you to thepaperpilot for fixing errors in docs and improving the infobox appearance!
          • Many other minor fixes.

          v2.1.4 - 10/25/20

          • Added an infobox component. Thank you to thepaperpilot for this contribution!
          • Layer type is now optional, and defaults to "none".
          • Improved the look of bars and tab buttons.
          • Improved spacing between layer nodes (also thanks to thepaperpilot!)
          • Fixed the "blank" component breaking if only specifying the height.
          • Fixed some numbers not displaying with enough digits.
          • Made a few more things able to be functions.
          • A few other minor fixes.

          v2.1.3.1 - 10/21/20

          • Fixed the update function.

          v2.1.3 - 10/21/20

          • gainMult and gainExp are now optional.
          • Layer unlocking is now kept on reset.
          • Game should start up faster.
          • Layer updates now have a determined order and starts with earlier-rowed layers.
          • Automation now has a determined order and starts with later-rowed layers.
          • Fixed issues with resetting clickables and challenges.
          • Commas should no longer appear in the decimal places of a number.
          • Fixed potential issue in displaying the tree.

          v2.1.2 - 10/19/20

          • Added buyUpgrade function (buyUpg still works though)
          • Added author name to modInfo.
          • Fix to crash caused when the name of a subtab or microtab is changed.
          • Fixes to outdated information in docs.
          • Improvements to Discord links.
          • Thank you to thepaperpilot for contributing to this update!

          v2.1.1 - 10/17/20

          • Added resource-display component, which displays the base currency for the prestige layer, as well as the best and/or total of this layer's prestige currency.
          • Fixed the value for the base currency not updating in resource-display.

          v2.1: We should have thought of this sooner! - 10/17/20

          • Moved most of the code users will want to edit to mod.js, added documentation for it.
            • Specifically, modInfo, VERSION, canGenPoints, getPointGen, and maxTickLength
          • Added getStartPoints()
          • Added the ability to store non-layer-related data
          • Added the ability to display more things at the top of the tree tab below points.
          • Made the endgame condition customizable
          • Added "sell one" and "sell all" buttons for buyables.
          • Moved the old "game" to demo.js, and replaced it with a minimal game that won't cause issues when edited.
          • Fixed issues with version number
          • Fixed number formatting issue making things like "10e9" appear.

          v2.0.5 - 10/16/20

          • Made more features (including prestige parameters) able to be dynamic.
          • Layer nodes can be hidden but still take up space with "ghost" visibility
          • Added clickableEffect for real.
          • Fixed some visual issues with bars.
          • A few other minor tweaks and improvements.

          v2.0.4 - 10/16/20

          • Fixed HTML on buttons interfering with clicking on them.

          v2.0.3 - 10/16/20

          • Fixed hotkeys not displaying in info.
          • Fixed the game supressing all external hotkeys.
          • You can use more things as currencies for upgrade costs and challenge goals using currencyLocation.
          • Added maxTickLength, which can be used to prevent offline time or tab-switching from breaking time-limit based mechanics.
          • Made buyable respec buttons and clickable "master" buttons their own components, and gave them a hide/show feature.
          • Added a general "tooltip" feature for achievements.

          v2.0.2 - 10/15/20

          • Branches are now dynamic (they can be functions).
          • Fixed a crash related to offline time.
          • Fixed links being too wide.

          v2.0.1 - 10/15/20

          • Fixed side layers appearing multiple times.

          v2.0: The Pinnacle of Achievement Mountain - 10/15/20

          • Added progress bars, which are highly customizable and can be horizontal or vertical!
          • Added "side layers", displayed smaller and off to the side, and don't get reset by default. They can be used for global achievements and statistics. Speaking of which...
          • Added achievements!
          • Added clickables, a more generalized variant of buyables.
          • Almost every value in layer data can be either a function or a constant value!
          • Added support for multiple completions of challenges.
          • Added "none" prestige type, which removes the need for any other prestige-related features.
          • The points display and other gui elements stay at the top of the screen when the tree scrolls.
          • Added getter/setter functions for the amounts and effects of most Big Features
          • Moved modInfo to game.js, added a spot in modInfo for a Discord link, changelog link. Also added a separate mod version from the TMT version in VERSION.
          • Tree structure is based on layer data, no index.html editing is needed.
          • Tmp does not need to be manually updated.
          • You don't have to have the same amount of upgrades in every row (and challs and buyables)
          • "unlocked" is optional for all Big Components (defaults to true).
          • All displays will update correctly.
          • Changelog is no longer in index.html at all.
          • Generation of Points now happens in the main game loop
          • Changed the reset functions to make keeping things easier
          • Renamed many things to increase readability (see the list in the link below)
          • Improved documentation based on feedback

          v1.3.5:

          • Completely automated convertToDecimal, now you never have to worry about it again.
          • Branches can be defined without a color id. But they can also use hex values for color ids!
          • Created a tutorial for getting started with TMT and Github.
          • Page title is now automatically taken from mod name.

          v1.3.4 - 10/8/20

          • Added "midsection" feature to add things to a tab's layout while still keeping the standard layout.
          • Fix for being able to buy more buyables than you should.

          v1.3.3 - 10/7/20

          • Fix for the "order of operations" issue in temp.

          v1.3.1 - 10/7/20

          • Added custom CSS and tooltips for Layer Nodes.
          • Added custom CSS for upgrades, buyables, milestones, and challenges, both individually and layer-wide.
          • You can now use HTML in most display text!
          • You can now make milestones unlockable and not display immediately.
          • Fixed importing saves, and issue with upgrades not appearing, and probably more.
          • Optional "name" layer feature, used in confirmation messages.

          v1.3: Tabception... ception! - 10/7/20

          • Added subtabs! And also a Micro-tab component to let you make smaller subtab-esque areas anywhere.
          • Added a "custom" prestige formula type, and a number of features to support it.
          • Added points/sec display (can be disabled).
          • Added h-line, v-line and image-display components, plus components for individual upgrades, challenges, and milestones.
          • Added upgEffect, buyableEffect, and challEffect functions.
          • Added "hide completed challenges" setting.
          • Moved old changelogs to a separate place.
          • Fixed hasMilestone and incr_order.
          • Static layers now show the currency amount needed for the next one if you can buy max.

          v1.2.4 - 10/4/20

          • Layers are now highlighted if you can buy an upgrade, and a new feature, shouldNotify, lets you make it highlight other ways.
          • Fixed bugs with hasUpg, hasChall, hasMilestone, and inChallenge.
          • Changed the sample code to use the above functions for convenience.

          v1.2.3 - 10/3/20

          • Added a row component, which displays a list of objects in a row.
          • Added a column component, which displays a list of objects in a column (useful within a row).
          • Changed blanks to have a customizable width and height.

          v1.2: This Changes Everything! - 10/3/20

          • Many layer features can now be static values or functions. (This made some formats change, which will break old things)
          • You can now use the "this" keyword, to make code easier to transfer when making new layers.
          • Also added "this.layer", which is the current layer's name, and works on existing subfeatures (e.g. individual upgrades) as well! Subfeatures also have "this.id".
          • Fixed a big save issue. If you use a unique mod id, your save will never conflict with other mods.
          • Added a configurable offline time limit in modinfo at the top of index.html. (default 1 hour)
          • Added a few minor features, and updated the docs with new information.

          v1.1.1:

          • You can define hotkeys directly from layer config.

          v1.1: Enhanced Edition

          • Added "Buyables", which can function like Space Buildings or Enhancers.
          • Custom CSS can now be used on any component! Make the third argument an object with CSS parameters.
          • Lots of minor good things.

          v1.0:

          • First release.
          + \ No newline at end of file diff --git a/public/lit/docs/!general-info.html b/public/lit/docs/!general-info.html index b89d8d75..4a7c9739 100644 --- a/public/lit/docs/!general-info.html +++ b/public/lit/docs/!general-info.html @@ -6,13 +6,13 @@ The-Modding-Tree | The Paper Pilot - + - + - - - + + + @@ -34,8 +34,8 @@ -
          Skip to content

          The-Modding-Tree

          The main way to add content is through creating layers. You can either add a layer directly in the layers object in layerSupport.js, or declare it in another file and register it by calling addLayer(layername, layerdata). There is an example layer registration in layers.js showing the recommended method. It is just an example and can be freely deleted. You can also use it as a reference or a base for your own layers.

          The first thing you need to do is fill out the modInfo object at the top of mod.js to set your mod's name, ID (a string), and other information. A unique modId will prevent your mod's saves from conflicting with other mods. Note that changing this after people have started playing will reset their saves.

          Most of the time, you won't need to dive deep into the code to create things, but you still can if you really want to, for example to add new Vue components in v.js.

          The Modding Tree uses break_eternity.js to store large values. This means that many numbers are Decimal objects, and must be treated differently. For example, you have to use new Decimal(x) to create a Decimal value instead of a plain number, and perform operations on them by calling functions. e.g, instead of x = x + y, use x = x.add(y). Keep in mind this also applies to comparison operators, which should be replaced with calling the .gt, .gte, .lt, .lte, .eq, and .neq functions. See the break_eternity.js docs for more details on working with Decimal values.

          Almost all values can be either a constant value, or a dynamic value. Dynamic values are defined by putting a function that returns what the value should be at any given time.

          All display text can use basic HTML elements (But you can't use most Vue features there).

          While reading this documentation, the following key will be used when describing features:

          • No label: This is required and the game may crash if it isn't included.
          • sometimes required: This is may be required, depending on other things in the layer.
          • optional: You can leave this out if you don't intend to use that feature for the layer.
          • assigned automagically: This value will be set automatically and override any value you set.
          • deprecated: This feature is not recommended to be used anymore, and may be removed in future versions of TMT.

          Table of Contents

          General

          • Getting Started: Getting your own copy of the code set up with Github Desktop.
          • Main mod info: How to set up general things for your mod in mod.js.
          • Basic layer breakdown: Breaking down the components of a layer with minimal features.
          • Layer features: Explanations of all of the different properties that you can give a layer.
          • Custom Tab Layouts: An optional way to give your tabs a different layout. You can even create entirely new components to use.
          • Custom game layouts: You can get rid of the tree tab, add buttons and other things to the tree, or even customize the tab's layout like a layer tab.
          • Updating TMT: Using Github Desktop to update your mod's version of TMT.

          Common components

          • Upgrades: How to create upgrades for a layer.
          • Milestones: How to create milestones for a layer.
          • Buyables: Create rebuyable upgrades for your layer (with the option to make them respec-able). Can be used to make Enhancers or Space Buildings.
          • Clickables: A more generalized variant of buyables, for any kind of thing that is sometimes clickable. Between these and Buyables, you can do just about anything.

          Other components and features

          • Challenges: How to create challenges for a layer.
          • Bars: Display some information as a progress bar, gauge, or similar. They are highly customizable, and can be horizontal and vertical as well.
          • Subtabs and Microtabs: Create subtabs for your tabs, as well as "microtab" components that you can put inside the tabs. You can even use them to embed a layer inside another layer!
          • Achievements: How to create achievements for a layer (or for the whole game).
          • Infoboxes: Boxes containing text that can be shown or hidden.
          • Trees: Make your own trees. You can make non-layer button nodes too!
          - +
          Skip to content

          The-Modding-Tree

          The main way to add content is through creating layers. You can either add a layer directly in the layers object in layerSupport.js, or declare it in another file and register it by calling addLayer(layername, layerdata). There is an example layer registration in layers.js showing the recommended method. It is just an example and can be freely deleted. You can also use it as a reference or a base for your own layers.

          The first thing you need to do is fill out the modInfo object at the top of mod.js to set your mod's name, ID (a string), and other information. A unique modId will prevent your mod's saves from conflicting with other mods. Note that changing this after people have started playing will reset their saves.

          Most of the time, you won't need to dive deep into the code to create things, but you still can if you really want to, for example to add new Vue components in v.js.

          The Modding Tree uses break_eternity.js to store large values. This means that many numbers are Decimal objects, and must be treated differently. For example, you have to use new Decimal(x) to create a Decimal value instead of a plain number, and perform operations on them by calling functions. e.g, instead of x = x + y, use x = x.add(y). Keep in mind this also applies to comparison operators, which should be replaced with calling the .gt, .gte, .lt, .lte, .eq, and .neq functions. See the break_eternity.js docs for more details on working with Decimal values.

          Almost all values can be either a constant value, or a dynamic value. Dynamic values are defined by putting a function that returns what the value should be at any given time.

          All display text can use basic HTML elements (But you can't use most Vue features there).

          While reading this documentation, the following key will be used when describing features:

          • No label: This is required and the game may crash if it isn't included.
          • sometimes required: This is may be required, depending on other things in the layer.
          • optional: You can leave this out if you don't intend to use that feature for the layer.
          • assigned automagically: This value will be set automatically and override any value you set.
          • deprecated: This feature is not recommended to be used anymore, and may be removed in future versions of TMT.

          Table of Contents

          General

          • Getting Started: Getting your own copy of the code set up with Github Desktop.
          • Main mod info: How to set up general things for your mod in mod.js.
          • Basic layer breakdown: Breaking down the components of a layer with minimal features.
          • Layer features: Explanations of all of the different properties that you can give a layer.
          • Custom Tab Layouts: An optional way to give your tabs a different layout. You can even create entirely new components to use.
          • Custom game layouts: You can get rid of the tree tab, add buttons and other things to the tree, or even customize the tab's layout like a layer tab.
          • Updating TMT: Using Github Desktop to update your mod's version of TMT.

          Common components

          • Upgrades: How to create upgrades for a layer.
          • Milestones: How to create milestones for a layer.
          • Buyables: Create rebuyable upgrades for your layer (with the option to make them respec-able). Can be used to make Enhancers or Space Buildings.
          • Clickables: A more generalized variant of buyables, for any kind of thing that is sometimes clickable. Between these and Buyables, you can do just about anything.

          Other components and features

          • Challenges: How to create challenges for a layer.
          • Bars: Display some information as a progress bar, gauge, or similar. They are highly customizable, and can be horizontal and vertical as well.
          • Subtabs and Microtabs: Create subtabs for your tabs, as well as "microtab" components that you can put inside the tabs. You can even use them to embed a layer inside another layer!
          • Achievements: How to create achievements for a layer (or for the whole game).
          • Infoboxes: Boxes containing text that can be shown or hidden.
          • Trees: Make your own trees. You can make non-layer button nodes too!
          + \ No newline at end of file diff --git a/public/lit/docs/achievements.html b/public/lit/docs/achievements.html index 5bd95379..0f1a8df7 100644 --- a/public/lit/docs/achievements.html +++ b/public/lit/docs/achievements.html @@ -6,13 +6,13 @@ Achievements | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
          Skip to content

          Achievements

          Achievements are awarded to the player when they meet a certain goal, and optionally give some benefit. Currently they are pretty basic, but additional features will be added later to help.

          You can make global achievements by putting them in a side layer by making its row equal to "side" instead of a number.

          Useful functions for dealing with achievements and implementing their effects:

          • hasAchievement(layer, id): determine if the player has the Achievement.
          • achievementEffect(layer, id): Returns the current effects of the achievement, if any.

          Achievements should be formatted like this:

          js
          achievements: {
          +    
          Skip to content

          Achievements

          Achievements are awarded to the player when they meet a certain goal, and optionally give some benefit. Currently they are pretty basic, but additional features will be added later to help.

          You can make global achievements by putting them in a side layer by making its row equal to "side" instead of a number.

          Useful functions for dealing with achievements and implementing their effects:

          • hasAchievement(layer, id): determine if the player has the Achievement.
          • achievementEffect(layer, id): Returns the current effects of the achievement, if any.

          Achievements should be formatted like this:

          js
          achievements: {
               rows: # of rows,
               cols: # of columns,
               11: {
          @@ -42,8 +42,8 @@
                   more features
               },
               etc
          -}

          Each achievement should have an id where the first digit is the row and the second digit is the column.

          Individual achievement can have these features:

          • name: optional. displayed at the top of the achievement. The only visible text. It can also be a function that returns updating text. Can use basic HTML.

          • done(): A function returning a boolean to determine if the achievement should be awarded.

          • tooltip: Default tooltip for the achievement, appears when it is hovered over. Should convey the goal and any reward for completing the achievement. It can also be a function that returns updating text. Can use basic HTML. Setting this to "" disables the tooltip.

          • effect(): optional. A function that calculates and returns the current values of any bonuses from the achievement. Can return a value or an object containing multiple values.

          • unlocked(): optional. A function returning a bool to determine if the achievement is visible or not. Default is unlocked.

          • onComplete() - optional. this function will be called when the achievement is completed.

          • image: optional, puts the image from the given URL (relative or absolute) in the achievement

          • style: optional. Applies CSS to this achievement, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • textStyle: optional. Applies CSS to the text, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the achievement was stored under, for convenient access. The achievement in the example's id is 11.

          • goalTooltip: optional, deprecated. Appears when the achievement is hovered over and locked, overrides the basic tooltip. This is to display the goal (or a hint). It can also be a function that returns updating text. Can use basic HTML.

          • doneTooltip: optional, deprecated. Appears when the achievement is hovered over and completed, overrides the basic tooltip. This can display what the player achieved (the goal), and the rewards, if any. It can also be a function that returns updating text. Can use basic HTML.

          Disable achievement popups by adding achievementsPopups: false to the layer.

          - +}

          Each achievement should have an id where the first digit is the row and the second digit is the column.

          Individual achievement can have these features:

          • name: optional. displayed at the top of the achievement. The only visible text. It can also be a function that returns updating text. Can use basic HTML.

          • done(): A function returning a boolean to determine if the achievement should be awarded.

          • tooltip: Default tooltip for the achievement, appears when it is hovered over. Should convey the goal and any reward for completing the achievement. It can also be a function that returns updating text. Can use basic HTML. Setting this to "" disables the tooltip.

          • effect(): optional. A function that calculates and returns the current values of any bonuses from the achievement. Can return a value or an object containing multiple values.

          • unlocked(): optional. A function returning a bool to determine if the achievement is visible or not. Default is unlocked.

          • onComplete() - optional. this function will be called when the achievement is completed.

          • image: optional, puts the image from the given URL (relative or absolute) in the achievement

          • style: optional. Applies CSS to this achievement, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • textStyle: optional. Applies CSS to the text, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the achievement was stored under, for convenient access. The achievement in the example's id is 11.

          • goalTooltip: optional, deprecated. Appears when the achievement is hovered over and locked, overrides the basic tooltip. This is to display the goal (or a hint). It can also be a function that returns updating text. Can use basic HTML.

          • doneTooltip: optional, deprecated. Appears when the achievement is hovered over and completed, overrides the basic tooltip. This can display what the player achieved (the goal), and the rewards, if any. It can also be a function that returns updating text. Can use basic HTML.

          Disable achievement popups by adding achievementsPopups: false to the layer.

          + \ No newline at end of file diff --git a/public/lit/docs/bars.html b/public/lit/docs/bars.html index cd07a6cc..9014f3c1 100644 --- a/public/lit/docs/bars.html +++ b/public/lit/docs/bars.html @@ -6,13 +6,13 @@ Bars | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
          Skip to content

          Bars

          Bars let you display information in a more direct way. It can be a progress bar, health bar, capacity gauge, or anything else.

          Bars are defined like other Big Features:

          js
          bars: {
          +    
          Skip to content

          Bars

          Bars let you display information in a more direct way. It can be a progress bar, health bar, capacity gauge, or anything else.

          Bars are defined like other Big Features:

          js
          bars: {
               bigBar: {
                   direction: RIGHT,
                   width: 200,
          @@ -43,8 +43,8 @@
                   etc
               },
               etc
          -}

          Features:

          • direction: UP, DOWN, LEFT, or RIGHT (not strings). Determines the direction that the bar is filled as it progresses. RIGHT means from left to right.

          • width, height: The size in pixels of the bar, but as numbers (no "px" at the end).

          • progress(): A function that returns the portion of the bar that is filled, from "empty" at 0 to "full" at 1, updating automatically. (Nothing bad happens if the value goes out of these bounds, and it can be a number or Decimal)

          • display(): optional. A function that returns text to be displayed on top of the bar, can use HTML.

          • unlocked(): optional. A function returning a bool to determine if the bar is visible or not. Default is unlocked.

          • baseStyle, fillStyle, borderStyle, textStyle: Optional, Apply CSS to the unfilled portion, filled portion, border, and display text on the bar, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the bar was stored under, for convenient access. The bar in the example's id is "bigBar".

          - +}

          Features:

          • direction: UP, DOWN, LEFT, or RIGHT (not strings). Determines the direction that the bar is filled as it progresses. RIGHT means from left to right.

          • width, height: The size in pixels of the bar, but as numbers (no "px" at the end).

          • progress(): A function that returns the portion of the bar that is filled, from "empty" at 0 to "full" at 1, updating automatically. (Nothing bad happens if the value goes out of these bounds, and it can be a number or Decimal)

          • display(): optional. A function that returns text to be displayed on top of the bar, can use HTML.

          • unlocked(): optional. A function returning a bool to determine if the bar is visible or not. Default is unlocked.

          • baseStyle, fillStyle, borderStyle, textStyle: Optional, Apply CSS to the unfilled portion, filled portion, border, and display text on the bar, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the bar was stored under, for convenient access. The bar in the example's id is "bigBar".

          + \ No newline at end of file diff --git a/public/lit/docs/basic-layer-breakdown.html b/public/lit/docs/basic-layer-breakdown.html index ead4ea53..2d136ce0 100644 --- a/public/lit/docs/basic-layer-breakdown.html +++ b/public/lit/docs/basic-layer-breakdown.html @@ -6,13 +6,13 @@ Basic layer breakdown | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
          Skip to content

          Basic layer breakdown

          This is a very minimal layer with minimal features. Most things will require additional features.

          js
          addLayer("p", {
          +    
          Skip to content

          Basic layer breakdown

          This is a very minimal layer with minimal features. Most things will require additional features.

          js
          addLayer("p", {
               startData() { return {                  // startData is a function that returns default data for a layer. 
                   unlocked: true,                     // You can add more variables here to add them to your layer.
                   points: new Decimal(0),             // "points" is the internal name for the main resource of the layer.
          @@ -61,8 +61,8 @@
               },
           
               layerShown() { return true }            // Returns a bool for if this layer's node should be visible in the tree.
          -})
          - +})
          + \ No newline at end of file diff --git a/public/lit/docs/buyables.html b/public/lit/docs/buyables.html index fdb7feea..9c4136ef 100644 --- a/public/lit/docs/buyables.html +++ b/public/lit/docs/buyables.html @@ -6,13 +6,13 @@ Buyables | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
          Skip to content

          Buyables

          Buyables are usually things that can be bought multiple times with scaling costs. If you set a respec function, the player can reset the purchases to get their currency back.

          The amount of a buyable owned is a Decimal.

          Useful functions for dealing with buyables and implementing their effects:

          • getBuyableAmount(layer, id): get the amount of the buyable the player has
          • setBuyableAmount(layer, id, amount): set the amount of the buyable the player has
          • buyableEffect(layer, id): Returns the current effects of the buyable, if any.

          Buyables should be formatted like this:

          js
          buyables: {
          +    
          Skip to content

          Buyables

          Buyables are usually things that can be bought multiple times with scaling costs. If you set a respec function, the player can reset the purchases to get their currency back.

          The amount of a buyable owned is a Decimal.

          Useful functions for dealing with buyables and implementing their effects:

          • getBuyableAmount(layer, id): get the amount of the buyable the player has
          • setBuyableAmount(layer, id, amount): set the amount of the buyable the player has
          • buyableEffect(layer, id): Returns the current effects of the buyable, if any.

          Buyables should be formatted like this:

          js
          buyables: {
               rows: # of rows,
               cols: # of columns,
               11: {
          @@ -48,8 +48,8 @@
                   etc
               },
               etc
          -}

          Features:

          • title: optional. displayed at the top in a larger font. It can also be a function that returns updating text.

          • cost(): cost for buying the next buyable. Can have an optional argument "x" to calculate the cost of the x+1th object, but needs to use "current amount" as a default value for x. (x is a Decimal). Can return an object if there are multiple currencies.

          • effect(): optional. A function that calculates and returns the current values of bonuses of this buyable. Can return a value or an object containing multiple values.

          • display(): A function returning everything that should be displayed on the buyable after the title, likely including the description, amount bought, cost, and current effect. Can use basic HTML.

          • unlocked(): optional. A function returning a bool to determine if the buyable is visible or not. Default is unlocked.

          • canAfford(): A function returning a bool to determine if you can buy one of the buyables.

          • buy(): A function that implements buying one of the buyable, including spending the currency.

          • buyMax(): optional. A function that implements buying as many of the buyable as possible.

          • style: optional. Applies CSS to this buyable, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the buyable was stored under, for convenient access. The buyable in the example's id is 11.

          Sell One/Sell All:

          Including a sellOne or sellAll function will cause an additional button to appear beneath the buyable. They are functionally identical, but "sell one" appears above "sell all". You can also use them for other things.

          • sellOne/sellAll(): optional. Called when the button is pressed. The standard use would be to decrease/reset the amount of the buyable, and possibly return some currency to the player.

          • canSellOne/canSellAll(): optional. booleans determining whether or not to show the buttons. If "canSellOne/All" is absent but "sellOne/All" is present, the appropriate button will always show.

          - +}

          Features:

          • title: optional. displayed at the top in a larger font. It can also be a function that returns updating text.

          • cost(): cost for buying the next buyable. Can have an optional argument "x" to calculate the cost of the x+1th object, but needs to use "current amount" as a default value for x. (x is a Decimal). Can return an object if there are multiple currencies.

          • effect(): optional. A function that calculates and returns the current values of bonuses of this buyable. Can return a value or an object containing multiple values.

          • display(): A function returning everything that should be displayed on the buyable after the title, likely including the description, amount bought, cost, and current effect. Can use basic HTML.

          • unlocked(): optional. A function returning a bool to determine if the buyable is visible or not. Default is unlocked.

          • canAfford(): A function returning a bool to determine if you can buy one of the buyables.

          • buy(): A function that implements buying one of the buyable, including spending the currency.

          • buyMax(): optional. A function that implements buying as many of the buyable as possible.

          • style: optional. Applies CSS to this buyable, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the buyable was stored under, for convenient access. The buyable in the example's id is 11.

          Sell One/Sell All:

          Including a sellOne or sellAll function will cause an additional button to appear beneath the buyable. They are functionally identical, but "sell one" appears above "sell all". You can also use them for other things.

          • sellOne/sellAll(): optional. Called when the button is pressed. The standard use would be to decrease/reset the amount of the buyable, and possibly return some currency to the player.

          • canSellOne/canSellAll(): optional. booleans determining whether or not to show the buttons. If "canSellOne/All" is absent but "sellOne/All" is present, the appropriate button will always show.

          + \ No newline at end of file diff --git a/public/lit/docs/challenges.html b/public/lit/docs/challenges.html index d2aa7d6b..dda437a2 100644 --- a/public/lit/docs/challenges.html +++ b/public/lit/docs/challenges.html @@ -6,13 +6,13 @@ Challenges | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
          Skip to content

          Challenges

          Challenges can have fully customizable win conditions. Useful functions for dealing with Challenges and implementing their effects:

          • inChallenge(layer, id): determine if the player is in a given challenge (or another challenge on the same layer that counts as this one).
          • hasChallenge(layer, id): determine if the player has completed the challenge.
          • challengeCompletions(layer, id): determine how many times the player completed the challenge.
          • challengeEffect(layer, id): Returns the current effects of the challenge, if any.

          Challenges are stored in the following format:

          js
          challenges: {
          +    
          Skip to content

          Challenges

          Challenges can have fully customizable win conditions. Useful functions for dealing with Challenges and implementing their effects:

          • inChallenge(layer, id): determine if the player is in a given challenge (or another challenge on the same layer that counts as this one).
          • hasChallenge(layer, id): determine if the player has completed the challenge.
          • challengeCompletions(layer, id): determine how many times the player completed the challenge.
          • challengeEffect(layer, id): Returns the current effects of the challenge, if any.

          Challenges are stored in the following format:

          js
          challenges: {
               rows: # of rows,
               cols: # of columns,
               11: {
          @@ -44,8 +44,8 @@
                   etc
               },
               etc
          -}

          Each challenge should have an id where the first digit is the row and the second digit is the column.

          Individual Challenges can have these features:

          • name: Name of the challenge, can be a string or a function. Can use basic HTML.

          • challengeDescription: A description of what makes the challenge a challenge. You will need to implement these elsewhere. It can also be a function that returns updating text. Can use basic HTML.

          • goalDescription: A description of the win condition for the challenge. It can also be a function that returns updating text. Can use basic HTML. (Optional if using the old goal system)

          • canComplete(): A function that returns true if you meet the win condition for the challenge. Returning a number will allow bulk completing the challenge. (Optional if using the old goal system)

          • rewardDescription: A description of the reward's effect. You will also have to implement the effect where it is applied. It can also be a function that returns updating text. Can use basic HTML.

          • rewardEffect(): optional. A function that calculates and returns the current values of any bonuses from the reward. Can return a value or an object containing multiple values. Can use basic HTML.

          • rewardDisplay(): optional. A function that returns a display of the current effects of the reward with formatting. Default behavior is to just display the a number appropriately formatted.

          • fullDisplay(): OVERRIDE. Overrides the other displays and descriptions, and lets you set the full text for the challenge. Can use basic HTML.

          • unlocked(): optional. A function returning a bool to determine if the challenge is visible or not. Default is unlocked.

          • onComplete() - optional. this function will be called when the challenge is completed when previously incomplete.

          • countsAs: optional. If a challenge combines the effects of other challenges in this layer, you can use this. An array of challenge ids. The player is effectively in all of those challenges when in the current one.

          • completionLimit: optional. the amount of times you can complete this challenge. Default is 1 completion.

          • style: optional. Applies CSS to this challenge, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar

          • id: assigned automagically. It's the "key" which the challenge was stored under, for convenient access. The challenge in the example's id is 11.

          The old goal system uses these features:

          • goal: deprecated, A Decimal for the amount of currency required to beat the challenge. By default, the goal is in basic Points. The goal can also be a function if its value changes.

          • currencyDisplayName: deprecated. the name to display for the currency for the goal

          • currencyInternalName: deprecated. the internal name for that currency

          • currencyLayer: deprecated. the internal name of the layer that currency is stored in. If it's not in a layer, omit. If it's not stored directly in a layer, instead use the next feature.

          • currencyLocation(): deprecated. if your currency is stored in something inside a layer (e.g. a buyable's amount), you can access it this way. This is a function returning the object in "player" that contains the value (like player[this.layer].buyables)

          - +}

          Each challenge should have an id where the first digit is the row and the second digit is the column.

          Individual Challenges can have these features:

          • name: Name of the challenge, can be a string or a function. Can use basic HTML.

          • challengeDescription: A description of what makes the challenge a challenge. You will need to implement these elsewhere. It can also be a function that returns updating text. Can use basic HTML.

          • goalDescription: A description of the win condition for the challenge. It can also be a function that returns updating text. Can use basic HTML. (Optional if using the old goal system)

          • canComplete(): A function that returns true if you meet the win condition for the challenge. Returning a number will allow bulk completing the challenge. (Optional if using the old goal system)

          • rewardDescription: A description of the reward's effect. You will also have to implement the effect where it is applied. It can also be a function that returns updating text. Can use basic HTML.

          • rewardEffect(): optional. A function that calculates and returns the current values of any bonuses from the reward. Can return a value or an object containing multiple values. Can use basic HTML.

          • rewardDisplay(): optional. A function that returns a display of the current effects of the reward with formatting. Default behavior is to just display the a number appropriately formatted.

          • fullDisplay(): OVERRIDE. Overrides the other displays and descriptions, and lets you set the full text for the challenge. Can use basic HTML.

          • unlocked(): optional. A function returning a bool to determine if the challenge is visible or not. Default is unlocked.

          • onComplete() - optional. this function will be called when the challenge is completed when previously incomplete.

          • countsAs: optional. If a challenge combines the effects of other challenges in this layer, you can use this. An array of challenge ids. The player is effectively in all of those challenges when in the current one.

          • completionLimit: optional. the amount of times you can complete this challenge. Default is 1 completion.

          • style: optional. Applies CSS to this challenge, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar

          • id: assigned automagically. It's the "key" which the challenge was stored under, for convenient access. The challenge in the example's id is 11.

          The old goal system uses these features:

          • goal: deprecated, A Decimal for the amount of currency required to beat the challenge. By default, the goal is in basic Points. The goal can also be a function if its value changes.

          • currencyDisplayName: deprecated. the name to display for the currency for the goal

          • currencyInternalName: deprecated. the internal name for that currency

          • currencyLayer: deprecated. the internal name of the layer that currency is stored in. If it's not in a layer, omit. If it's not stored directly in a layer, instead use the next feature.

          • currencyLocation(): deprecated. if your currency is stored in something inside a layer (e.g. a buyable's amount), you can access it this way. This is a function returning the object in "player" that contains the value (like player[this.layer].buyables)

          + \ No newline at end of file diff --git a/public/lit/docs/clickables.html b/public/lit/docs/clickables.html index 9e007f54..fe34f3dd 100644 --- a/public/lit/docs/clickables.html +++ b/public/lit/docs/clickables.html @@ -6,13 +6,13 @@ Clickables | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
          Skip to content

          Clickables

          Clickables are any kind of thing that you can click for an effect. They're a more generalized version of Buyables.

          DO NOT USE THESE TO MAKE THINGS THAT YOU CLICK REPEATEDLY FOR A BONUS BECAUSE THOSE ARE AWFUL.

          There are several differences between the two. One is that a buyable's saved data is its amount as a Decimal, while Clickables store a "state" which can be a number or string, but not Decimal, array, or object). Buyables have a number of extra features which you can see on their page. Clickables also have a smaller default size.

          Useful functions for dealing with achievements and implementing their effects:

          • getClickableState(layer, id): get the state of the clickable the player has
          • setClickableState(layer, id, state): set the state of the buyable the player has
          • clickableEffect(layer, id): Returns the current effects of the clickable, if any.

          Clickables should be formatted like this:

          js
          clickables: {
          +    
          Skip to content

          Clickables

          Clickables are any kind of thing that you can click for an effect. They're a more generalized version of Buyables.

          DO NOT USE THESE TO MAKE THINGS THAT YOU CLICK REPEATEDLY FOR A BONUS BECAUSE THOSE ARE AWFUL.

          There are several differences between the two. One is that a buyable's saved data is its amount as a Decimal, while Clickables store a "state" which can be a number or string, but not Decimal, array, or object). Buyables have a number of extra features which you can see on their page. Clickables also have a smaller default size.

          Useful functions for dealing with achievements and implementing their effects:

          • getClickableState(layer, id): get the state of the clickable the player has
          • setClickableState(layer, id, state): set the state of the buyable the player has
          • clickableEffect(layer, id): Returns the current effects of the clickable, if any.

          Clickables should be formatted like this:

          js
          clickables: {
               rows: # of rows,
               cols: # of columns,
               11: {
          @@ -42,8 +42,8 @@
                   etc
               }
               etc
          -}

          Features:

          • title: optional. displayed at the top in a larger font. It can also be a function that returns updating text.

          • effect(): optional. A function that calculates and returns the current values of bonuses of this clickable. Can return a value or an object containing multiple values.

          • display(): A function returning everything that should be displayed on the clickable after the title, likely changing based on its state. Can use basic HTML.

          • unlocked(): optional. A function returning a bool to determine if the clickable is visible or not. Default is unlocked.

          • canClick(): A function returning a bool to determine if you can click the clickable.

          • onClick(): A function that implements clicking one of the clickable.

          • style: optional. Applies CSS to this clickable, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the clickable was stored under, for convenient access. The clickable in the example's id is 11.

          You can also use these features on the clickables object to add a button above all the clickables, for implementing a respec button or similar.

          • masterButtonPress(): optional. If present, an additional button will appear above the clickables. Pressing it will call this function.

          • masterButtonText: optional. Text to display on the Master Button.

          • showMasterButton(): optional. A function determining whether or not to show the button. Defaults to true if absent.

          - +}

          Features:

          • title: optional. displayed at the top in a larger font. It can also be a function that returns updating text.

          • effect(): optional. A function that calculates and returns the current values of bonuses of this clickable. Can return a value or an object containing multiple values.

          • display(): A function returning everything that should be displayed on the clickable after the title, likely changing based on its state. Can use basic HTML.

          • unlocked(): optional. A function returning a bool to determine if the clickable is visible or not. Default is unlocked.

          • canClick(): A function returning a bool to determine if you can click the clickable.

          • onClick(): A function that implements clicking one of the clickable.

          • style: optional. Applies CSS to this clickable, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the clickable was stored under, for convenient access. The clickable in the example's id is 11.

          You can also use these features on the clickables object to add a button above all the clickables, for implementing a respec button or similar.

          • masterButtonPress(): optional. If present, an additional button will appear above the clickables. Pressing it will call this function.

          • masterButtonText: optional. Text to display on the Master Button.

          • showMasterButton(): optional. A function determining whether or not to show the button. Defaults to true if absent.

          + \ No newline at end of file diff --git a/public/lit/docs/custom-tab-layouts.html b/public/lit/docs/custom-tab-layouts.html index ae3d57ba..2559da50 100644 --- a/public/lit/docs/custom-tab-layouts.html +++ b/public/lit/docs/custom-tab-layouts.html @@ -6,13 +6,13 @@ Custom tab layouts | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
          Skip to content

          Custom tab layouts

          Note: If you are using subtabs, tabFormat is used differently, but you still use the same format within each subtabs. See here for more on subtabs.

          Custom tab layouts can be used to do basically anything in a tab window, especially combined with the "style" layer feature. The tabFormat feature is an array of things, like this:

          js
          tabFormat: [
          +    
          Skip to content

          Custom tab layouts

          Note: If you are using subtabs, tabFormat is used differently, but you still use the same format within each subtabs. See here for more on subtabs.

          Custom tab layouts can be used to do basically anything in a tab window, especially combined with the "style" layer feature. The tabFormat feature is an array of things, like this:

          js
          tabFormat: [
               "main-display",
               ["prestige-button", function() { return "Melt your points into " }],
               "blank",
          @@ -47,8 +47,8 @@
               "blank",
               "blank",
               "upgrades"
          -]

          It is a list of components, which can be either just a name, or an array with arguments. If it's an array, the first item is the name of the component, the second is the data passed into it, and the third (optional) applies a CSS style to it with a "CSS object", where the keys are CSS attributes.

          These are the existing components, but you can create more in components.js:

          • display-text: Displays some text (can use basic HTML). The argument is the text to display. It can also be a function that returns updating text.

          • raw-html: Displays some basic HTML, can also be a function.

          • blank: Adds empty space. The default dimensions are 8px x 17px. The argument changes the dimensions. If it's a single value (e.g. "20px"), that determines the height. If you have a pair of arguments, the first is width and the second is height.

          • row: Display a list of components horizontally. The argument is an array of components in the tab layout format.

          • column: Display a list of components vertically. The argument is an array of components in the tab layout format. This is useful to display columns within a row.

          • main-display: The text that displays the main currency for the layer and its effects.

          • resource-display: The text that displays the currency that this layer is based on, as well as the best and/or total values for this layer's prestige currency (if they are put in startData for this layer).

          • prestige-button: The argument is a string that the prestige button should say before the amount of currency you will gain. It can also be a function that returns updating text.

          • upgrades: The layer's upgrades. The argument is optional, and is a the list of rows this component should include, if it doesn't have all of them.

          • milestones, challenges, achievements: Display the upgrades, milestones, and challenges for a layer, as appropriate.

          • buyables, clickables: Display all of the buyables/clickables for this layer, as appropriate. The argument is optional and is the size of the boxes in pixels.

          • microtabs: Display a set of subtabs for an area. The argument is the name of the set of microtabs in the "microtabs" feature.

          • bar: Display a bar. The argument is the id of the bar to display.

          • infobox: Display an infobox. The argument is the id of the infobox to display.

          • tree: Displays a tree. The argument is an array of arrays containing the names of the nodes in the tree (first by row, then by column) See here for more information on tree layouts and nodes!

          • toggle: A toggle button that toggles a bool value. The data is a pair that identifies what bool to toggle, e.g. [layer, id]

          The rest of the components are sub-components. They can be used just like other components, but are typically part of another component.

          • upgrade, milestone, challenge, buyable, clickable, achievement: An individual upgrade, challenge, etc. The argument is the id. This can be used if you want to have upgrades split up across multiple subtabs, for example.

          • respec-button, master-button: The respec and master buttons for buyables and clickables, respectively.

          • sell-one, sell-all: The "sell one" and "sell all" for buyables, respectively. The argument is the id of the buyable.

          - +]

          It is a list of components, which can be either just a name, or an array with arguments. If it's an array, the first item is the name of the component, the second is the data passed into it, and the third (optional) applies a CSS style to it with a "CSS object", where the keys are CSS attributes.

          These are the existing components, but you can create more in components.js:

          • display-text: Displays some text (can use basic HTML). The argument is the text to display. It can also be a function that returns updating text.

          • raw-html: Displays some basic HTML, can also be a function.

          • blank: Adds empty space. The default dimensions are 8px x 17px. The argument changes the dimensions. If it's a single value (e.g. "20px"), that determines the height. If you have a pair of arguments, the first is width and the second is height.

          • row: Display a list of components horizontally. The argument is an array of components in the tab layout format.

          • column: Display a list of components vertically. The argument is an array of components in the tab layout format. This is useful to display columns within a row.

          • main-display: The text that displays the main currency for the layer and its effects.

          • resource-display: The text that displays the currency that this layer is based on, as well as the best and/or total values for this layer's prestige currency (if they are put in startData for this layer).

          • prestige-button: The argument is a string that the prestige button should say before the amount of currency you will gain. It can also be a function that returns updating text.

          • upgrades: The layer's upgrades. The argument is optional, and is a the list of rows this component should include, if it doesn't have all of them.

          • milestones, challenges, achievements: Display the upgrades, milestones, and challenges for a layer, as appropriate.

          • buyables, clickables: Display all of the buyables/clickables for this layer, as appropriate. The argument is optional and is the size of the boxes in pixels.

          • microtabs: Display a set of subtabs for an area. The argument is the name of the set of microtabs in the "microtabs" feature.

          • bar: Display a bar. The argument is the id of the bar to display.

          • infobox: Display an infobox. The argument is the id of the infobox to display.

          • tree: Displays a tree. The argument is an array of arrays containing the names of the nodes in the tree (first by row, then by column) See here for more information on tree layouts and nodes!

          • toggle: A toggle button that toggles a bool value. The data is a pair that identifies what bool to toggle, e.g. [layer, id]

          The rest of the components are sub-components. They can be used just like other components, but are typically part of another component.

          • upgrade, milestone, challenge, buyable, clickable, achievement: An individual upgrade, challenge, etc. The argument is the id. This can be used if you want to have upgrades split up across multiple subtabs, for example.

          • respec-button, master-button: The respec and master buttons for buyables and clickables, respectively.

          • sell-one, sell-all: The "sell one" and "sell all" for buyables, respectively. The argument is the id of the buyable.

          + \ No newline at end of file diff --git a/public/lit/docs/getting-started.html b/public/lit/docs/getting-started.html index 46a6d63f..bd16a118 100644 --- a/public/lit/docs/getting-started.html +++ b/public/lit/docs/getting-started.html @@ -6,13 +6,13 @@ Getting started | The Paper Pilot - + - + - - - + + + @@ -34,8 +34,8 @@ -
          Skip to content

          Getting started

          Welcome to The Modding Tree!

          Using the Modding Tree, at its simplest level, just requires getting a copy of it onto your computer. However, if you do it the right way, it will help in many ways.

          Don't let the word "Github" scare you away. It's actually much easier to use than most people think, especially because most people use it the hard way. The key is Github Desktop, which lets you do everything you need to, without even touching the command line.

          The benefits of using Github:

          • It makes it much, much easier to update The Modding Tree.
          • You can share your work without any extra effort using githack, or with a bit more effort, set up a github.io site.
          • It lets you undo changes to your code, and to have multiple versions of it.
          • It lets you collaborate with other people, if you want to.

          Getting set up with Github Desktop, Visual Studio Code, and The Modding Tree:

          1. Install Github Desktop and Visual Studio Code.

          2. Make a Github account. You can handle this on your own.

          3. Log in on your browser, and go back to The Modding Tree page. At the top right, there should be a button that says "fork". Click on it, and then on your username. You now have your own fork, or copy, of The Modding Tree.

          4. Open Github Desktop and log in. Ignore everything else and choose "clone a repository". A "repository" is basically a "Github project", like The Modding Tree. "Cloning" is downloading a copy of the repository to your computer.

          5. Look for The Modding Tree in the list of repositiories (it should be the only one) and click "clone".

          6. Select that you're using it for your own purposes, and click continue. It will download the files and handle everything.

          Using your repository

          1. Click on "show in explorer/finder" to the right, and then open the index.html file in the folder. The page should open up on your browser. This will let you view and test your project locally!

          2. To edit your project, click "open in VSCode" in Github Desktop.

          3. Open mod.js in VSCode, and look at the top part where it has a "modInfo" object. Fill in your mod's name to whatever you want, and change the id as well. (It can be any string value, and it's used to determine where the savefile is. Make it something that's probably unique, and don't change it again later or else it'll effectively wipe existing saves)

          4. Save mod.js, and then reload index.html in your browser. The title on the tab, as well as on the info page, will now be updated! You can reload the page every time you change the code to test it quickly and easily.

          5. Go back to Github Desktop. It's time to save your changes into the git system by making a "commit". This basically saves your work and creates a snapshot of what your code looks like at this moment, allowing you to look back at it later.

          6. At the bottom right corner, add a summary of your changes, and then click "commit to master".

          7. Finally, at the top middle, click "push origin" to push your changes out onto the online repository.

          8. You can view your project on line, or share it with others, by going to https://raw.githack.com/[YOUR-GITHUB-USERNAME]/The-Modding-Tree/master/index.html

          And now, you have successfully used Github! You can look at the documentation to see how The Modding Tree's system works and to make your mod a reality.

          - +
          Skip to content

          Getting started

          Welcome to The Modding Tree!

          Using the Modding Tree, at its simplest level, just requires getting a copy of it onto your computer. However, if you do it the right way, it will help in many ways.

          Don't let the word "Github" scare you away. It's actually much easier to use than most people think, especially because most people use it the hard way. The key is Github Desktop, which lets you do everything you need to, without even touching the command line.

          The benefits of using Github:

          • It makes it much, much easier to update The Modding Tree.
          • You can share your work without any extra effort using githack, or with a bit more effort, set up a github.io site.
          • It lets you undo changes to your code, and to have multiple versions of it.
          • It lets you collaborate with other people, if you want to.

          Getting set up with Github Desktop, Visual Studio Code, and The Modding Tree:

          1. Install Github Desktop and Visual Studio Code.

          2. Make a Github account. You can handle this on your own.

          3. Log in on your browser, and go back to The Modding Tree page. At the top right, there should be a button that says "fork". Click on it, and then on your username. You now have your own fork, or copy, of The Modding Tree.

          4. Open Github Desktop and log in. Ignore everything else and choose "clone a repository". A "repository" is basically a "Github project", like The Modding Tree. "Cloning" is downloading a copy of the repository to your computer.

          5. Look for The Modding Tree in the list of repositiories (it should be the only one) and click "clone".

          6. Select that you're using it for your own purposes, and click continue. It will download the files and handle everything.

          Using your repository

          1. Click on "show in explorer/finder" to the right, and then open the index.html file in the folder. The page should open up on your browser. This will let you view and test your project locally!

          2. To edit your project, click "open in VSCode" in Github Desktop.

          3. Open mod.js in VSCode, and look at the top part where it has a "modInfo" object. Fill in your mod's name to whatever you want, and change the id as well. (It can be any string value, and it's used to determine where the savefile is. Make it something that's probably unique, and don't change it again later or else it'll effectively wipe existing saves)

          4. Save mod.js, and then reload index.html in your browser. The title on the tab, as well as on the info page, will now be updated! You can reload the page every time you change the code to test it quickly and easily.

          5. Go back to Github Desktop. It's time to save your changes into the git system by making a "commit". This basically saves your work and creates a snapshot of what your code looks like at this moment, allowing you to look back at it later.

          6. At the bottom right corner, add a summary of your changes, and then click "commit to master".

          7. Finally, at the top middle, click "push origin" to push your changes out onto the online repository.

          8. You can view your project on line, or share it with others, by going to https://raw.githack.com/[YOUR-GITHUB-USERNAME]/The-Modding-Tree/master/index.html

          And now, you have successfully used Github! You can look at the documentation to see how The Modding Tree's system works and to make your mod a reality.

          + \ No newline at end of file diff --git a/public/lit/docs/infoboxes.html b/public/lit/docs/infoboxes.html index 84acf0e7..88cd9644 100644 --- a/public/lit/docs/infoboxes.html +++ b/public/lit/docs/infoboxes.html @@ -6,13 +6,13 @@ Infoboxes | The Paper Pilot - + - + - - - + + + @@ -34,15 +34,15 @@ -
          Skip to content

          Infoboxes

          Infoboxes are good for displaying "lore", or story elements, as well as for explaining complicated things.

          In the default tab layout, the first infobox will be displayed at the very top of the tab.

          Infoboxes are defined like other Big Features:

          js
          infoboxes: {
          +    
          Skip to content

          Infoboxes

          Infoboxes are good for displaying "lore", or story elements, as well as for explaining complicated things.

          In the default tab layout, the first infobox will be displayed at the very top of the tab.

          Infoboxes are defined like other Big Features:

          js
          infoboxes: {
               lore: {
                   title: "foo",
                   body() { return "bar" },
                   etc
               },
               etc
          -}

          Features:

          • title: The text displayed above the main box. Can be a function to be dynamic, and can use basic HTML.

          • body: The text displayed inside the box. Can be a function to be dynamic, and can use basic HTML.

          • style, titleStyle, bodyStyle: optional. Apply CSS to the infobox, or to the title button or body of the infobox, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • unlocked(): optional. A function returning a bool to determine if the infobox is visible or not. Default is unlocked.

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar

          • id: assigned automagically. It's the "key" which the bar was stored under, for convenient access. The infobox in the example's id is "lore".

          - +}

          Features:

          • title: The text displayed above the main box. Can be a function to be dynamic, and can use basic HTML.

          • body: The text displayed inside the box. Can be a function to be dynamic, and can use basic HTML.

          • style, titleStyle, bodyStyle: optional. Apply CSS to the infobox, or to the title button or body of the infobox, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • unlocked(): optional. A function returning a bool to determine if the infobox is visible or not. Default is unlocked.

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar

          • id: assigned automagically. It's the "key" which the bar was stored under, for convenient access. The infobox in the example's id is "lore".

          + \ No newline at end of file diff --git a/public/lit/docs/layer-features.html b/public/lit/docs/layer-features.html index 294c06df..1c61026d 100644 --- a/public/lit/docs/layer-features.html +++ b/public/lit/docs/layer-features.html @@ -6,13 +6,13 @@ Layer Features | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
          Skip to content

          Layer Features

          This is a more comprehensive list of established features to add to layers. You can add more freely, if you want to have other functions or values associated with your layer. These have special functionality, though.

          You can make almost any value dynamic by using a function in its place, including all display strings and styling/color features.

          Layer Definition features

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar to access the saved value. It makes copying code to new layers easier. It is also assigned to all upgrades and buyables and such.

          • name: optional. used in reset confirmations (and the default infobox title). If absent, it just uses the layer's id.

          • startData(): A function to return the default save data for this layer. Add any variables you have to it. Make sure to use Decimal values rather than normal numbers.

            Standard values: - Required: - unlocked: a bool determining if this layer is unlocked or not - points: a Decimal, the main currency for the layer - Optional: - total: A Decimal, tracks total amount of main prestige currency. Always tracked, but only shown if you add it here. - best: A Decimal, tracks highest amount of main prestige currency. Always tracked, but only shown if you add it here. - unlockOrder: used to keep track of relevant layers unlocked before this one. - resetTime: A number, time since this layer was last prestiged (or reset by another layer)

          • color: A color associated with this layer, used in many places. (A string in hex format with a #)

          • row: The row of the layer, starting at 0. This affects where the node appears on the standard tree, and which resets affect the layer.

            Using "side" instead of a number will cause the layer to appear off to the side as a smaller node (useful for achievements and statistics). Side layers are not affected by resets unless you add a doReset to them.

          • displayRow: OVERRIDE Changes where the layer node appears without changing where it is in the reset order.

          • resource: Name of the main currency you gain by resetting on this layer.

          • effect(): optional. A function that calculates and returns the current values of any bonuses inherent to the main currency. Can return a value or an object containing multiple values. You will also have to implement the effect where it is applied.

          • effectDescription: optional. A function that returns a description of this effect. If the text stays constant, it can just be a string.

          • layerShown(): optional, A function returning a bool which determines if this layer's node should be visible on the tree. It can also return "ghost", which will hide the layer, but its node will still take up space in the tree. Defaults to true.

          • hotkeys: optional. An array containing information on any hotkeys associated with this layer:

            js
            hotkeys: [
            +    
            Skip to content

            Layer Features

            This is a more comprehensive list of established features to add to layers. You can add more freely, if you want to have other functions or values associated with your layer. These have special functionality, though.

            You can make almost any value dynamic by using a function in its place, including all display strings and styling/color features.

            Layer Definition features

            • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar to access the saved value. It makes copying code to new layers easier. It is also assigned to all upgrades and buyables and such.

            • name: optional. used in reset confirmations (and the default infobox title). If absent, it just uses the layer's id.

            • startData(): A function to return the default save data for this layer. Add any variables you have to it. Make sure to use Decimal values rather than normal numbers.

              Standard values: - Required: - unlocked: a bool determining if this layer is unlocked or not - points: a Decimal, the main currency for the layer - Optional: - total: A Decimal, tracks total amount of main prestige currency. Always tracked, but only shown if you add it here. - best: A Decimal, tracks highest amount of main prestige currency. Always tracked, but only shown if you add it here. - unlockOrder: used to keep track of relevant layers unlocked before this one. - resetTime: A number, time since this layer was last prestiged (or reset by another layer)

            • color: A color associated with this layer, used in many places. (A string in hex format with a #)

            • row: The row of the layer, starting at 0. This affects where the node appears on the standard tree, and which resets affect the layer.

              Using "side" instead of a number will cause the layer to appear off to the side as a smaller node (useful for achievements and statistics). Side layers are not affected by resets unless you add a doReset to them.

            • displayRow: OVERRIDE Changes where the layer node appears without changing where it is in the reset order.

            • resource: Name of the main currency you gain by resetting on this layer.

            • effect(): optional. A function that calculates and returns the current values of any bonuses inherent to the main currency. Can return a value or an object containing multiple values. You will also have to implement the effect where it is applied.

            • effectDescription: optional. A function that returns a description of this effect. If the text stays constant, it can just be a string.

            • layerShown(): optional, A function returning a bool which determines if this layer's node should be visible on the tree. It can also return "ghost", which will hide the layer, but its node will still take up space in the tree. Defaults to true.

            • hotkeys: optional. An array containing information on any hotkeys associated with this layer:

              js
              hotkeys: [
                   {
                       key: "p", // What the hotkey button is. Use uppercase if it's combined with shift, or "ctrl+x" for holding down ctrl.
                       description: "p: reset your points for prestige points", // The description of the hotkey that is displayed in the game's How To Play tab
              @@ -43,8 +43,8 @@
               ]
            • style: optional. a "CSS object" where the keys are CSS attributes, containing any CSS that should affect this layer's entire tab.

            • tabFormat: optional. use this if you want to add extra things to your tab or change the layout. See here for more info.

            • midsection: optional, an alternative to tabFormat, which is inserted in between Milestones and Buyables in the standard tab layout. (cannot do subtabs)

            Big features (all optional)

            • upgrades: A grid of one-time purchases which can have unique upgrade conditions, currency costs, and bonuses. See here for more info.

            • milestones: A list of bonuses gained upon reaching certain thresholds of a resource. Often used for automation/QOL. See here for more info.

            • challenges: The player can enter challenges, which make the game harder. If they reach a goal and beat the challenge, they recieve a bonus. See here for more info.

            • buyables: Effectively upgrades that can be bought multiple times, and are optionally respeccable. Many uses. See here for more info.

            • clickables: Extremely versatile and generalized buttons which can only be clicked sometimes. See here for more info.

            • microtabs: An area that functions like a set of subtabs, with buttons at the top changing the content within. (Advanced) See here for more info.

            • bars: Display some information as a progress bar, gague, or similar. They are highly customizable, and can be vertical as well. See here for more info.

            • achievements: Kind of like milestones, but with a different display style and some other differences. Extra features are on the way at a later date! See here for more info.

            • infoboxes: Displays some text in a box that can be shown or hidden. See here for more info.

            • achievementPopups, milestonePopups: optional, If false, disables popup message when you get the achievement/milestone. True by default.

            Prestige formula features

            • type: optional. Determines which prestige formula you use. Defaults to "none".

              • "normal": The amount of currency you gain is independent of its current amount (like Prestige). The formula before bonuses is based on baseResource^exponent
              • "static": The cost is dependent on your total after reset. The formula before bonuses is based on base^(x^exponent)
              • "custom": You can define everything, from the calculations to the text on the button, yourself. (See more at the bottom)
              • "none": This layer does not prestige, and therefore does not need any of the other features in this section.
            • baseResource: The name of the resource that determines how much of the main currency you gain on reset.

            • baseAmount(): A function that gets the current value of the base resource.

            • requires: A Decimal, the amount of the base needed to gain 1 of the prestige currency. Also the amount required to unlock the layer. You can instead make this a function, to make it harder if another layer was unlocked first (based on unlockOrder).

            • exponent: Used as described above.

            • base: sometimes required. required for "static" layers, used as described above. If absent, defaults to 2. Must be greater than 1.

            • roundUpCost: optional. a bool, which is true if the resource cost needs to be rounded up. (use if the base resource is a "static" currency.)

            • gainMult(), gainExp(): optional. Functions that calculate the multiplier and exponent on resource gain from upgrades and boosts and such. Plug in any bonuses here.

            • softcap, softcapPower: optional. For normal layers, gain beyond [softcap] points is put to the [softcapPower]th power Default for softcap is e1e7, and for power is 0.5.

            • canBuyMax(): sometimes required. required for static layers, function used to determine if buying max is permitted.

            • onPrestige(gain): optional. A function that triggers when this layer prestiges, just before you gain the currency. Can be used to have secondary resource gain on prestige, or to recalculate things or whatnot.

            • resetDescription: optional. Use this to replace "Reset for " on the Prestige button with something else.

            • prestigeButtonText(): sometimes required. Use this to make the entirety of the text a Prestige button contains. Only required for custom layers, but usable by all types.

            • passiveGeneration(): optional, returns a regular number. You automatically generate your gain times this number every second (does nothing if absent) This is good for automating Normal layers.

            • autoPrestige(): optional, returns a boolean, if true, the layer will always automatically do a prestige if it can. This is good for automating Static layers.

            Tree/node features

            • symbol: optional. The text that appears on this layer's node. Default is the layer id with the first letter capitalized.

            • image: override. The url (local or global) of an image that goes on the node. (Overrides symbol)

            • position: optional. Determines the horizontal position of the layer in its row in a standard tree. By default, it uses the layer id, and layers are sorted in alphabetical order.

            • branches: optional. An array of layer/node ids. On a tree, a line will appear from this layer to all of the layers in the list. Alternatively, an entry in the array can be a 2-element array consisting of the layer id and a color value. The color value can either be a string with a hex color code, or a number from 1-3 (theme-affected colors).

            • nodeStyle: optional. A CSS object, where the keys are CSS attributes, which styles this layer's node on the tree.

            • tooltip() / tooltipLocked(): optional. Functions that return text, which is the tooltip for the node when the layer is unlocked or locked, respectively. By default the tooltips behave the same as in the original Prestige Tree. If the value is "", the tooltip will be disabled.

            Other features

            • doReset(resettingLayer): optional. Is triggered when a layer on a row greater than or equal to this one does a reset. The default behavior is to reset everything on the row, but only if it was triggered by a layer in a higher row. doReset is always called for side layers, but for these the default behavior is to reset nothing.

              If you want to keep things, determine what to keep based on resettingLayer, milestones, and such, then call layerDataReset(layer, keep), where layer is this layer, and keep is an array of the names of things to keep. It can include things like "points", "best", "total" (for this layer's prestige currency), "upgrades", any unique variables like "generatorPower", etc. If you want to only keep specific upgrades or something like that, save them in a separate variable, then call layerDataReset, and then set player[this.layer].upgrades to the saved upgrades.

            • update(diff): optional. This function is called every game tick. Use it for any passive resource production or time-based things. diff is the time since the last tick.

            • autoUpgrade: optional, a boolean value, if true, the game will attempt to buy this layer's upgrades every tick. Defaults to false.

            • automate(): optional. This function is called every game tick, after production. Use it to activate automation things that aren't otherwise supported.

            • resetsNothing: optional. Returns true if this layer shouldn't trigger any resets when you prestige.

            • increaseUnlockOrder: optional. An array of layer ids. When this layer is unlocked for the first time, the unlockOrder value for any not-yet-unlocked layers in this list increases. This can be used to make them harder to unlock.

            • shouldNotify: optional. A function to return true if this layer should be highlighted in the tree. The layer will automatically be highlighted if you can buy an upgrade whether you have this or not.

            • componentStyles: optional. An object that contains a set of functions returning CSS objects. Each of these will be applied to any components on the layer with the type of its id. Example:

            js
            componentStyles: {
                 "challenge"() { return {'height': '200px'} },
                 "prestige-button"() { return {'color': '#AA66AA'} }
            -}

            Custom Prestige type

            (All of these can also be used by other prestige types)

            • getResetGain(): mostly for custom prestige type. Returns how many points you should get if you reset now. You can call getResetGain(this.layer, useType = "static") or similar to calculate what your gain would be under another prestige type (provided you have all of the required features in the layer).

            • getNextAt(canMax=false): mostly for custom prestige type. Returns how many of the base currency you need to get to the next point. canMax is an optional variable used with Static-ish layers to differentiate between if it's looking for the first point you can reset at, or the requirement for any gain at all (Supporting both is good). You can also call getNextAt(this.layer, canMax=false, useType = "static") or similar to calculate what your next at would be under another prestige type (provided you have all of the required features in the layer).

            • canReset(): mostly for custom prestige type. Return true only if you have the resources required to do a prestige here.

            • prestigeNotify(): mostly for custom prestige types, returns true if this layer should be subtly highlighted to indicate you can prestige for a meaningful gain.

            - +}

            Custom Prestige type

            (All of these can also be used by other prestige types)

            • getResetGain(): mostly for custom prestige type. Returns how many points you should get if you reset now. You can call getResetGain(this.layer, useType = "static") or similar to calculate what your gain would be under another prestige type (provided you have all of the required features in the layer).

            • getNextAt(canMax=false): mostly for custom prestige type. Returns how many of the base currency you need to get to the next point. canMax is an optional variable used with Static-ish layers to differentiate between if it's looking for the first point you can reset at, or the requirement for any gain at all (Supporting both is good). You can also call getNextAt(this.layer, canMax=false, useType = "static") or similar to calculate what your next at would be under another prestige type (provided you have all of the required features in the layer).

            • canReset(): mostly for custom prestige type. Return true only if you have the resources required to do a prestige here.

            • prestigeNotify(): mostly for custom prestige types, returns true if this layer should be subtly highlighted to indicate you can prestige for a meaningful gain.

          + \ No newline at end of file diff --git a/public/lit/docs/main-mod-info.html b/public/lit/docs/main-mod-info.html index eb4a3022..08abeecb 100644 --- a/public/lit/docs/main-mod-info.html +++ b/public/lit/docs/main-mod-info.html @@ -6,13 +6,13 @@ mod.js | The Paper Pilot - + - + - - - + + + @@ -34,12 +34,12 @@ -
          Skip to content

          mod.js

          All of the non-layer code and data that you're likely to edit is here in mod.js! Everything in mod.js will not be altered by updates, besides the addition of new things.

          Here's a breakdown of what's in it:

          • modInfo is where most of the basic configuration for the mod is. It contains:

            • name: The name of your mod. (a string)

            • id: The id for your mod, a unique string that is used to determine savefile location. Setting it is important!

            • author: The name of the author, displayed in the info tab.

            • pointsName: This changes what is displayed instead of "points" for the main currency. (It does not affect it in the code.)

            • discordName, discordLink: If you have a Discord server or other discussion place, you can add a link to it.

              "discordName" is the text on the link, and "discordLink" is the url of an invite. If you're using a Discord invite, please make sure it's set to never expire.

            • offlineLimit: The maximum amount of offline time that the player can accumulate, in hours. Any extra time is lost. (a number)

              This is useful because most of these mods are fast-paced enough that too much offline time ruins the balance, such as the time in between updates. That is why I suggest developers disable offline time on their own savefile.

            • initialStartPoints: A Decimal for the amount of points a new player should start with.

          • VERSION is used to describe the current version of your mod. It contains:

            • num: The mod's version number, displayed at the top right of the tree tab.
            • name: The version's name, displayed alongside the number in the info tab.
          • changelog is the HTML displayed in the changelog tab.

          • doNotCallTheseFunctionsEveryTick is very important. TMT calls every function anywhere in "layers" every tick to store the result, unless specifically told not to. Functions that have are used to do an action need to be identified. "Official" functions (those in the documentation) are all fine, but if you make any new ones, add their names to this array.

          js
          // (The ones here are examples, all official functions are already taken care of)
          +    
          Skip to content

          mod.js

          All of the non-layer code and data that you're likely to edit is here in mod.js! Everything in mod.js will not be altered by updates, besides the addition of new things.

          Here's a breakdown of what's in it:

          • modInfo is where most of the basic configuration for the mod is. It contains:

            • name: The name of your mod. (a string)

            • id: The id for your mod, a unique string that is used to determine savefile location. Setting it is important!

            • author: The name of the author, displayed in the info tab.

            • pointsName: This changes what is displayed instead of "points" for the main currency. (It does not affect it in the code.)

            • discordName, discordLink: If you have a Discord server or other discussion place, you can add a link to it.

              "discordName" is the text on the link, and "discordLink" is the url of an invite. If you're using a Discord invite, please make sure it's set to never expire.

            • offlineLimit: The maximum amount of offline time that the player can accumulate, in hours. Any extra time is lost. (a number)

              This is useful because most of these mods are fast-paced enough that too much offline time ruins the balance, such as the time in between updates. That is why I suggest developers disable offline time on their own savefile.

            • initialStartPoints: A Decimal for the amount of points a new player should start with.

          • VERSION is used to describe the current version of your mod. It contains:

            • num: The mod's version number, displayed at the top right of the tree tab.
            • name: The version's name, displayed alongside the number in the info tab.
          • changelog is the HTML displayed in the changelog tab.

          • doNotCallTheseFunctionsEveryTick is very important. TMT calls every function anywhere in "layers" every tick to store the result, unless specifically told not to. Functions that have are used to do an action need to be identified. "Official" functions (those in the documentation) are all fine, but if you make any new ones, add their names to this array.

          js
          // (The ones here are examples, all official functions are already taken care of)
           var doNotCallTheseFunctionsEveryTick = ["doReset", "buy", "onPurchase", "blowUpEverything"]
          • getStartPoints(): A function to determine the amount of points the player starts with after a reset. (returns a Decimal value)

          • canGenPoints(): A function returning a boolean for if points should be generated. Use this if you want an upgrade to unlock generating points.

          • getPointGen(): A function that calculates your points per second. Anything that affects your point gain should go into the calculation here.

          • addedPlayerData(): A function that returns any non-layer-related data that you want to be added to the save data and "player" object.

          js
          function addedPlayerData() { return {
           	weather: "Yes",
           	happiness: new Decimal(72),
          -}}
          • displayThings: An array of functions used to display extra things at the top of the tree tab. Each function returns a string, which is a line to display (with basic HTML support). If a function returns nothing, nothing is displayed (and it doesn't take up a line).

          • isEndgame(): A function to determine if the player has reached the end of the game, at which point the "you win!" screen appears.

          Less important things beyond this point!

          • maxTickLength(): Returns the maximum tick length, in milliseconds. Only really useful if you have something that reduces over time, which long ticks mess up (usually a challenge).
          - +}}
          • displayThings: An array of functions used to display extra things at the top of the tree tab. Each function returns a string, which is a line to display (with basic HTML support). If a function returns nothing, nothing is displayed (and it doesn't take up a line).

          • isEndgame(): A function to determine if the player has reached the end of the game, at which point the "you win!" screen appears.

          Less important things beyond this point!

          • maxTickLength(): Returns the maximum tick length, in milliseconds. Only really useful if you have something that reduces over time, which long ticks mess up (usually a challenge).
          + \ No newline at end of file diff --git a/public/lit/docs/milestones.html b/public/lit/docs/milestones.html index 85cde32d..71e54987 100644 --- a/public/lit/docs/milestones.html +++ b/public/lit/docs/milestones.html @@ -6,13 +6,13 @@ Milestones | The Paper Pilot - + - + - - - + + + @@ -34,15 +34,15 @@ -
          Skip to content

          Milestones

          Milestones are awarded to the player when they meet a certain goal, and give some benefit. Milestones should be formatted like this:

          js
          milestones: {
          +    
          Skip to content

          Milestones

          Milestones are awarded to the player when they meet a certain goal, and give some benefit. Milestones should be formatted like this:

          js
          milestones: {
               0: {
                   requirementDescription: "123 waffles",
                   effectDescription: "blah",
                   done() { return player.w.points.gte(123) }
               }
               etc
          -}

          You can use hasMilestone(layer, id) to determine if the player has a given milestone

          Milestone features:

          • requirementDescription: A string describing the requirement for unlocking this milestone. Suggestion: Use a "total". It can also be a function that returns updating text. Can use basic HTML.

          • effectDescription: A string describing the reward for having the milestone. You will have to implement the reward elsewhere. It can also be a function that returns updating text. Can use basic HTML.

          • done(): A function returning a boolean to determine if the milestone should be awarded.

          • toggles: optional. Creates toggle buttons that appear on the milestone when it is unlocked. The toggles can toggle a given boolean value in a layer. It is defined as an array of paired items, one pair per toggle. The first is the internal name of the layer the value being toggled is stored in, and the second is the internal name of the variable to toggle. (e.g. [["b", "auto"], ["g", "auto"])

            Tip: Toggles are not de-set if the milestone becomes locked! In this case, you should also check if the player has the milestone.

          • style: optional. Applies CSS to this milestone, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • unlocked(): optional. A function returning a boolean to determine if the milestone should be shown. If absent, it is always shown.

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the milestone was stored under, for convenient access. The milestone in the example's id is 0.

          Disaable milestone popups by adding milestonePopups: false to the layer.

          - +}

          You can use hasMilestone(layer, id) to determine if the player has a given milestone

          Milestone features:

          • requirementDescription: A string describing the requirement for unlocking this milestone. Suggestion: Use a "total". It can also be a function that returns updating text. Can use basic HTML.

          • effectDescription: A string describing the reward for having the milestone. You will have to implement the reward elsewhere. It can also be a function that returns updating text. Can use basic HTML.

          • done(): A function returning a boolean to determine if the milestone should be awarded.

          • toggles: optional. Creates toggle buttons that appear on the milestone when it is unlocked. The toggles can toggle a given boolean value in a layer. It is defined as an array of paired items, one pair per toggle. The first is the internal name of the layer the value being toggled is stored in, and the second is the internal name of the variable to toggle. (e.g. [["b", "auto"], ["g", "auto"])

            Tip: Toggles are not de-set if the milestone becomes locked! In this case, you should also check if the player has the milestone.

          • style: optional. Applies CSS to this milestone, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • unlocked(): optional. A function returning a boolean to determine if the milestone should be shown. If absent, it is always shown.

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the milestone was stored under, for convenient access. The milestone in the example's id is 0.

          Disaable milestone popups by adding milestonePopups: false to the layer.

          + \ No newline at end of file diff --git a/public/lit/docs/subtabs-and-microtabs.html b/public/lit/docs/subtabs-and-microtabs.html index 8015fa14..04d3e59f 100644 --- a/public/lit/docs/subtabs-and-microtabs.html +++ b/public/lit/docs/subtabs-and-microtabs.html @@ -6,13 +6,13 @@ Subtabs and Microtabs | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
          Skip to content

          Subtabs and Microtabs

          Subtabs are separate sections of a tab that you can view by selecting one at the top of the tab. Microtabs are smaller areas that function in much the same way. You can also embed layers inside of subtabs/microtabs.

          Subtabs are defined by using the tab format like this, where each element of tabFormat is given the name of that subtab:

          js
          tabFormat: {
          +    
          Skip to content

          Subtabs and Microtabs

          Subtabs are separate sections of a tab that you can view by selecting one at the top of the tab. Microtabs are smaller areas that function in much the same way. You can also embed layers inside of subtabs/microtabs.

          Subtabs are defined by using the tab format like this, where each element of tabFormat is given the name of that subtab:

          js
          tabFormat: {
               "Main tab": {
                   content: [tab format things],
                   *subtab features*
          @@ -58,8 +58,8 @@
               otherStuff: {
                   // There could be another set of microtabs here
               }
          -}

          Normal subtabs and microtab subtabs both use the same features:

          Features:

          • content: The tab layout code for the subtab, in the tab layout format.

          • style: optional. Applies CSS to the whole subtab when switched to, in the form of an "CSS Object", where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • buttonStyle: optional. A CSS object, which affects the appearance of the button for that subtab.

          • unlocked(): optional. a function to determine if the button for this subtab should be visible. By default, a subtab is always unlocked. You can't use the "this" keyword in this function.

          • shouldNotify(): optional, if true, the tab button will be highlighted to notify the player that there is something there.

          • embedLayer: SIGNIFICANT, the id of another layer. If you have this, it will override "content", "style" and "shouldNotify", instead displaying the entire layer in the subtab.

          - +}

          Normal subtabs and microtab subtabs both use the same features:

          Features:

          • content: The tab layout code for the subtab, in the tab layout format.

          • style: optional. Applies CSS to the whole subtab when switched to, in the form of an "CSS Object", where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • buttonStyle: optional. A CSS object, which affects the appearance of the button for that subtab.

          • unlocked(): optional. a function to determine if the button for this subtab should be visible. By default, a subtab is always unlocked. You can't use the "this" keyword in this function.

          • shouldNotify(): optional, if true, the tab button will be highlighted to notify the player that there is something there.

          • embedLayer: SIGNIFICANT, the id of another layer. If you have this, it will override "content", "style" and "shouldNotify", instead displaying the entire layer in the subtab.

          + \ No newline at end of file diff --git a/public/lit/docs/trees-and-tree-customization.html b/public/lit/docs/trees-and-tree-customization.html index 64b3d86e..af6e2134 100644 --- a/public/lit/docs/trees-and-tree-customization.html +++ b/public/lit/docs/trees-and-tree-customization.html @@ -6,13 +6,13 @@ Trees and tree customization | The Paper Pilot - + - + - - - + + + @@ -34,10 +34,10 @@ -
          Skip to content

          Trees and tree customization

          If you want to have something beyond the standard tree on the left tab, you can do that in tree.js. You can change the layout of the tree, including making non-layer nodes, change it into something other than a tree, or hide the left tab altogether. This also introduces the "tree" component, which can be used in your layers as well.

          layoutInfo

          The most important part is layoutInfo, containing:

          • startTab: The id of the default tab to show on the left at the start.
          • showTree: True if the tree tab should be shown at the start of the game. (The other tab will fill the whole page)
          • treeLayout: If present, overrides the tree layout and places nodes as you describe instead (explained in the next section).

          Additionally, if you want the main layout to not be a tree, you can edit the "tree-tab" layer at the bottom of tree.js to modify it just like a normal layer's tab. You can even switch between left tabs, using showNavTab(layer) to make that layer appear on the left.

          Trees

          The tree component is defined as an array of arrays of names of layers or nodes to show in the tree. They work just like layers/ nodes in the main tree (but branches between nodes will only work on the first node if you have duplicates.)

          Here is an example tree:

          js
          [["p"],
          +    
          Skip to content

          Trees and tree customization

          If you want to have something beyond the standard tree on the left tab, you can do that in tree.js. You can change the layout of the tree, including making non-layer nodes, change it into something other than a tree, or hide the left tab altogether. This also introduces the "tree" component, which can be used in your layers as well.

          layoutInfo

          The most important part is layoutInfo, containing:

          • startTab: The id of the default tab to show on the left at the start.
          • showTree: True if the tree tab should be shown at the start of the game. (The other tab will fill the whole page)
          • treeLayout: If present, overrides the tree layout and places nodes as you describe instead (explained in the next section).

          Additionally, if you want the main layout to not be a tree, you can edit the "tree-tab" layer at the bottom of tree.js to modify it just like a normal layer's tab. You can even switch between left tabs, using showNavTab(layer) to make that layer appear on the left.

          Trees

          The tree component is defined as an array of arrays of names of layers or nodes to show in the tree. They work just like layers/ nodes in the main tree (but branches between nodes will only work on the first node if you have duplicates.)

          Here is an example tree:

          js
          [["p"],
            ["left", "blank", "right", "blank"]
          - ["a", "b", "blank", "c", "weirdButton"]]

          Nodes

          Nodes are non-layer buttons that can go in trees. They are defined similarly to layers, but with addNode instead of addLayer.

          Features:

          • color: optional, The node's color. (A string in hex format with a #)

          • symbol: optional The text on the button (The id capitalized by default)

          • canClick(): Returns true if the player can click the node. ()

          • onClick(): The function called when the node is clicked.

          • layerShown(): optional, A function returning a bool which determines if this node should be visible. It can also return "ghost", which will hide the layer, but its node will still take up space in its tree.

          • branches: optional. An array of layer/node ids. On a tree, a line will appear from this node to all of the nodes in the list. Alternatively, an entry in the array can be a 2-element array consisting of the id and a color value. The color value can either be a string with a hex color code, or a number from 1-3 (theme-affected colors).

          • nodeStyle: optional. A CSS object, where the keys are CSS attributes, which styles this node on the tree.

          • tooltip() / tooltipLocked(): optional. Functions that return text, which is the tooltip for the node when the layer is unlocked or locked, respectively. By default the tooltips behave the same as in the original Prestige Tree.

          • row: optional, the row that this node appears in (for the default tree).

          • position: optional, Determines the horizontal position of the layer in its row in a default tree. By default, it uses the id, and layers/nodes are sorted in alphabetical order.

          - + ["a", "b", "blank", "c", "weirdButton"]]

          Nodes

          Nodes are non-layer buttons that can go in trees. They are defined similarly to layers, but with addNode instead of addLayer.

          Features:

          • color: optional, The node's color. (A string in hex format with a #)

          • symbol: optional The text on the button (The id capitalized by default)

          • canClick(): Returns true if the player can click the node. ()

          • onClick(): The function called when the node is clicked.

          • layerShown(): optional, A function returning a bool which determines if this node should be visible. It can also return "ghost", which will hide the layer, but its node will still take up space in its tree.

          • branches: optional. An array of layer/node ids. On a tree, a line will appear from this node to all of the nodes in the list. Alternatively, an entry in the array can be a 2-element array consisting of the id and a color value. The color value can either be a string with a hex color code, or a number from 1-3 (theme-affected colors).

          • nodeStyle: optional. A CSS object, where the keys are CSS attributes, which styles this node on the tree.

          • tooltip() / tooltipLocked(): optional. Functions that return text, which is the tooltip for the node when the layer is unlocked or locked, respectively. By default the tooltips behave the same as in the original Prestige Tree.

          • row: optional, the row that this node appears in (for the default tree).

          • position: optional, Determines the horizontal position of the layer in its row in a default tree. By default, it uses the id, and layers/nodes are sorted in alphabetical order.

          + \ No newline at end of file diff --git a/public/lit/docs/updating-tmt.html b/public/lit/docs/updating-tmt.html index 01dbac66..ffb9f2f6 100644 --- a/public/lit/docs/updating-tmt.html +++ b/public/lit/docs/updating-tmt.html @@ -6,13 +6,13 @@ Updating The Modding Tree | The Paper Pilot - + - + - - - + + + @@ -34,8 +34,8 @@ -
          Skip to content

          Updating The Modding Tree

          This tutorial assumes that you have used the Getting Started Tutorial, and are using Github Desktop and VSCode for your mod.

          Here's what you have to do when there's a TMT update:

          1. Look at the changelog. It will warn you if the update will break anything or require any changes. Decide if you want to try to update.

          2. Open Github Desktop, and at the top middle, click "fetch origin". This will make Github Desktop get information about the update.

          3. Click where it says "current branch: master" at the top middle, and at the bottom of the thing that appears, click "choose a branch to merge into master".

          4. Select upstream/master. It will likely say there are conflicts, but you have tools to resolve them. Click "Merge upstream/master into master".

          5. A conflict happens when the things you're trying to merge have both made changes in the same place. Click "open in Visual Studio Code" next to the first file.

          6. Scroll down through the file, and look for the parts highlighted in red and green. One of these is your code, and the other is some code that will be modified by the update. Do your best to try to edit things to keep the updated changes, but keep your content.

          7. Continue to do this for all remaining changes.

          8. Do any other changes required by the update, run the game, fix issues, etc.

          - +
          Skip to content

          Updating The Modding Tree

          This tutorial assumes that you have used the Getting Started Tutorial, and are using Github Desktop and VSCode for your mod.

          Here's what you have to do when there's a TMT update:

          1. Look at the changelog. It will warn you if the update will break anything or require any changes. Decide if you want to try to update.

          2. Open Github Desktop, and at the top middle, click "fetch origin". This will make Github Desktop get information about the update.

          3. Click where it says "current branch: master" at the top middle, and at the bottom of the thing that appears, click "choose a branch to merge into master".

          4. Select upstream/master. It will likely say there are conflicts, but you have tools to resolve them. Click "Merge upstream/master into master".

          5. A conflict happens when the things you're trying to merge have both made changes in the same place. Click "open in Visual Studio Code" next to the first file.

          6. Scroll down through the file, and look for the parts highlighted in red and green. One of these is your code, and the other is some code that will be modified by the update. Do your best to try to edit things to keep the updated changes, but keep your content.

          7. Continue to do this for all remaining changes.

          8. Do any other changes required by the update, run the game, fix issues, etc.

          + \ No newline at end of file diff --git a/public/lit/docs/upgrades.html b/public/lit/docs/upgrades.html index 69e649fd..4075a477 100644 --- a/public/lit/docs/upgrades.html +++ b/public/lit/docs/upgrades.html @@ -6,13 +6,13 @@ Upgrades | The Paper Pilot - + - + - - - + + + @@ -34,7 +34,7 @@ -
          Skip to content

          Upgrades

          Useful functions for dealing with Upgrades and implementing their effects:

          • hasUpgrade(layer, id): determine if the player has the upgrade
          • upgradeEffect(layer, id): Returns the current effects of the upgrade, if any
          • buyUpgrade(layer, id): Buys an upgrade directly (if affordable)

          Hint: Basic point gain is calculated in mod.js's "getPointGen" function.

          Upgrades are stored in the following format:

          js
          upgrades: {
          +    
          Skip to content

          Upgrades

          Useful functions for dealing with Upgrades and implementing their effects:

          • hasUpgrade(layer, id): determine if the player has the upgrade
          • upgradeEffect(layer, id): Returns the current effects of the upgrade, if any
          • buyUpgrade(layer, id): Buys an upgrade directly (if affordable)

          Hint: Basic point gain is calculated in mod.js's "getPointGen" function.

          Upgrades are stored in the following format:

          js
          upgrades: {
               rows: # of rows,
               cols: # of columns,
               11: {
          @@ -43,8 +43,8 @@
                   etc
               },
               etc
          -}

          Each upgrade should have an id where the first digit is the row and the second digit is the column.

          Individual upgrades can have these features:

          • title: optional. Displayed at the top in a larger font. It can also be a function that returns updating text. Can use basic HTML.

          • description: A description of the upgrade's effect. You will also have to implement the effect where it is applied. It can also be a function that returns updating text. Can use basic HTML.

          • effect(): optional. A function that calculates and returns the current values of any bonuses from the upgrade. Can return a value or an object containing multiple values.

          • effectDisplay(): optional. A function that returns a display of the current effects of the upgrade with formatting. Default displays nothing. Can use basic HTML.

          • fullDisplay(): OVERRIDE. Overrides the other displays and descriptions, and lets you set the full text for the upgrade. Can use basic HTML.

          • cost: A Decimal for the cost of the upgrade. By default, upgrades cost the main prestige currency for the layer.

          • unlocked(): optional. A function returning a bool to determine if the upgrade is visible or not. Default is unlocked.

          • onPurchase(): optional. This function will be called when the upgrade is purchased. Good for upgrades like "makes this layer act like it was unlocked first".

          • style: optional. Applies CSS to this upgrade, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the upgrade was stored under, for convenient access. The upgrade in the example's id is 11.

          By default, upgrades use the main prestige currency for the layer. You can include these to change them (but it needs to be a Decimal):

          • currencyDisplayName: optional. The name to display for the currency for the upgrade.

          • currencyInternalName: optional. The internal name for that currency.

          • currencyLayer: optional. The internal name of the layer that currency is stored in. If it's not in a layer (like Points), omit. If it's not stored directly in a layer, instead use the next feature.

          • currencyLocation: optional. If your currency is stored in something inside a layer (e.g. a buyable's amount), you can access it this way. This is a function returning the object in "player" that contains the value (like player[this.layer].buyables)

          If you want to do something more complicated like upgrades that cost two currencies, you can override the purchase system with these (and you need to use fullDisplay as well)

          • canAfford(): OVERRIDE, a function determining if you are able to buy the upgrade

          • pay(): OVERRIDE, a function that reduces your currencies when you buy the upgrade

          - +}

          Each upgrade should have an id where the first digit is the row and the second digit is the column.

          Individual upgrades can have these features:

          • title: optional. Displayed at the top in a larger font. It can also be a function that returns updating text. Can use basic HTML.

          • description: A description of the upgrade's effect. You will also have to implement the effect where it is applied. It can also be a function that returns updating text. Can use basic HTML.

          • effect(): optional. A function that calculates and returns the current values of any bonuses from the upgrade. Can return a value or an object containing multiple values.

          • effectDisplay(): optional. A function that returns a display of the current effects of the upgrade with formatting. Default displays nothing. Can use basic HTML.

          • fullDisplay(): OVERRIDE. Overrides the other displays and descriptions, and lets you set the full text for the upgrade. Can use basic HTML.

          • cost: A Decimal for the cost of the upgrade. By default, upgrades cost the main prestige currency for the layer.

          • unlocked(): optional. A function returning a bool to determine if the upgrade is visible or not. Default is unlocked.

          • onPurchase(): optional. This function will be called when the upgrade is purchased. Good for upgrades like "makes this layer act like it was unlocked first".

          • style: optional. Applies CSS to this upgrade, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).

          • layer: assigned automagically. It's the same value as the name of this layer, so you can do player[this.layer].points or similar.

          • id: assigned automagically. It's the "key" which the upgrade was stored under, for convenient access. The upgrade in the example's id is 11.

          By default, upgrades use the main prestige currency for the layer. You can include these to change them (but it needs to be a Decimal):

          • currencyDisplayName: optional. The name to display for the currency for the upgrade.

          • currencyInternalName: optional. The internal name for that currency.

          • currencyLayer: optional. The internal name of the layer that currency is stored in. If it's not in a layer (like Points), omit. If it's not stored directly in a layer, instead use the next feature.

          • currencyLocation: optional. If your currency is stored in something inside a layer (e.g. a buyable's amount), you can access it this way. This is a function returning the object in "player" that contains the value (like player[this.layer].buyables)

          If you want to do something more complicated like upgrades that cost two currencies, you can override the purchase system with these (and you need to use fullDisplay as well)

          • canAfford(): OVERRIDE, a function determining if you are able to buy the upgrade

          • pay(): OVERRIDE, a function that reduces your currencies when you buy the upgrade

          + \ No newline at end of file