@3driseai/3drise-viewer 0.1.28 → 0.1.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (684) hide show
  1. package/dist/animationsV2/ClipPlayer.d.ts.map +1 -1
  2. package/dist/animationsV2/ClipPlayer.js +13 -9
  3. package/dist/animationsV2/ClipsRuntime.d.ts +44 -3
  4. package/dist/animationsV2/ClipsRuntime.d.ts.map +1 -1
  5. package/dist/animationsV2/ClipsRuntime.js +173 -55
  6. package/dist/animationsV2/appliers.d.ts.map +1 -1
  7. package/dist/animationsV2/appliers.js +21 -5
  8. package/dist/animationsV2/index.d.ts +1 -1
  9. package/dist/animationsV2/index.d.ts.map +1 -1
  10. package/dist/animationsV2/normalize.d.ts.map +1 -1
  11. package/dist/animationsV2/normalize.js +7 -3
  12. package/dist/animationsV2/sequenceUtils.d.ts +44 -6
  13. package/dist/animationsV2/sequenceUtils.d.ts.map +1 -1
  14. package/dist/animationsV2/sequenceUtils.js +58 -12
  15. package/dist/animationsV2/types.d.ts +22 -12
  16. package/dist/animationsV2/types.d.ts.map +1 -1
  17. package/dist/api/sceneHandle.d.ts +35 -1
  18. package/dist/api/sceneHandle.d.ts.map +1 -1
  19. package/dist/api/sceneHandle.js +88 -17
  20. package/dist/components/AdvancedGrid.d.ts +1 -5
  21. package/dist/components/AdvancedGrid.d.ts.map +1 -1
  22. package/dist/components/AdvancedGrid.js +6 -35
  23. package/dist/components/AnimatedObject.d.ts.map +1 -1
  24. package/dist/components/AnimatedObject.js +9 -4
  25. package/dist/components/ApollonianGrid.d.ts +1 -1
  26. package/dist/components/ApollonianGrid.d.ts.map +1 -1
  27. package/dist/components/ApollonianGrid.js +3 -28
  28. package/dist/components/ChladniGrid.d.ts +1 -1
  29. package/dist/components/ChladniGrid.d.ts.map +1 -1
  30. package/dist/components/ChladniGrid.js +6 -35
  31. package/dist/components/CircuitGrid.d.ts +1 -1
  32. package/dist/components/CircuitGrid.d.ts.map +1 -1
  33. package/dist/components/CircuitGrid.js +6 -34
  34. package/dist/components/ConformalGrid.d.ts +1 -1
  35. package/dist/components/ConformalGrid.d.ts.map +1 -1
  36. package/dist/components/ConformalGrid.js +3 -34
  37. package/dist/components/ContourGrid.d.ts +1 -1
  38. package/dist/components/ContourGrid.d.ts.map +1 -1
  39. package/dist/components/ContourGrid.js +6 -34
  40. package/dist/components/CustomPrimitive.js +1 -1
  41. package/dist/components/EnvironmentObject.d.ts.map +1 -1
  42. package/dist/components/EnvironmentObject.js +9 -7
  43. package/dist/components/FlowNetGrid.d.ts +1 -1
  44. package/dist/components/FlowNetGrid.d.ts.map +1 -1
  45. package/dist/components/FlowNetGrid.js +6 -34
  46. package/dist/components/FractalGrid.d.ts +1 -1
  47. package/dist/components/FractalGrid.d.ts.map +1 -1
  48. package/dist/components/FractalGrid.js +6 -37
  49. package/dist/components/Galaxy.d.ts.map +1 -1
  50. package/dist/components/Galaxy.js +9 -23
  51. package/dist/components/GirihGrid.d.ts +1 -1
  52. package/dist/components/GirihGrid.d.ts.map +1 -1
  53. package/dist/components/GirihGrid.js +6 -35
  54. package/dist/components/GravWaveGrid.d.ts +1 -1
  55. package/dist/components/GravWaveGrid.d.ts.map +1 -1
  56. package/dist/components/GravWaveGrid.js +6 -35
  57. package/dist/components/HexGrid.d.ts +1 -5
  58. package/dist/components/HexGrid.d.ts.map +1 -1
  59. package/dist/components/HexGrid.js +6 -36
  60. package/dist/components/HilbertGrid.d.ts +1 -1
  61. package/dist/components/HilbertGrid.d.ts.map +1 -1
  62. package/dist/components/HilbertGrid.js +3 -30
  63. package/dist/components/HyperbolicGrid.d.ts +1 -1
  64. package/dist/components/HyperbolicGrid.d.ts.map +1 -1
  65. package/dist/components/HyperbolicGrid.js +6 -34
  66. package/dist/components/LandObject.d.ts +9 -0
  67. package/dist/components/LandObject.d.ts.map +1 -0
  68. package/dist/components/LandObject.js +15 -0
  69. package/dist/components/LensingGrid.d.ts +1 -1
  70. package/dist/components/LensingGrid.d.ts.map +1 -1
  71. package/dist/components/LensingGrid.js +3 -29
  72. package/dist/components/LightsManager.d.ts.map +1 -1
  73. package/dist/components/LightsManager.js +8 -0
  74. package/dist/components/ModelBoundary.d.ts +2 -0
  75. package/dist/components/ModelBoundary.d.ts.map +1 -1
  76. package/dist/components/ModelBoundary.js +3 -0
  77. package/dist/components/ModelPrimitive.d.ts.map +1 -1
  78. package/dist/components/ModelPrimitive.js +6 -0
  79. package/dist/components/MoireGrid.d.ts +1 -1
  80. package/dist/components/MoireGrid.d.ts.map +1 -1
  81. package/dist/components/MoireGrid.js +6 -35
  82. package/dist/components/MoonDisc.d.ts +11 -0
  83. package/dist/components/MoonDisc.d.ts.map +1 -0
  84. package/dist/components/MoonDisc.js +128 -0
  85. package/dist/components/ObjectNode.d.ts.map +1 -1
  86. package/dist/components/ObjectNode.js +15 -4
  87. package/dist/components/ObjectsRenderer.d.ts.map +1 -1
  88. package/dist/components/ObjectsRenderer.js +7 -5
  89. package/dist/components/OceanBuilder.d.ts.map +1 -1
  90. package/dist/components/OceanBuilder.js +2 -0
  91. package/dist/components/ParastichyGrid.d.ts +1 -1
  92. package/dist/components/ParastichyGrid.d.ts.map +1 -1
  93. package/dist/components/ParastichyGrid.js +3 -30
  94. package/dist/components/PhyllotaxisGrid.d.ts +1 -1
  95. package/dist/components/PhyllotaxisGrid.d.ts.map +1 -1
  96. package/dist/components/PhyllotaxisGrid.js +3 -32
  97. package/dist/components/ProjectLoader.d.ts +5 -3
  98. package/dist/components/ProjectLoader.d.ts.map +1 -1
  99. package/dist/components/ProjectLoader.js +6 -3
  100. package/dist/components/QuasiGrid.d.ts +1 -1
  101. package/dist/components/QuasiGrid.d.ts.map +1 -1
  102. package/dist/components/QuasiGrid.js +6 -33
  103. package/dist/components/RadarGrid.d.ts +1 -1
  104. package/dist/components/RadarGrid.d.ts.map +1 -1
  105. package/dist/components/RadarGrid.js +6 -34
  106. package/dist/components/ReactionDiffusionGrid.d.ts +1 -1
  107. package/dist/components/ReactionDiffusionGrid.d.ts.map +1 -1
  108. package/dist/components/ReactionDiffusionGrid.js +6 -35
  109. package/dist/components/SceneBuilder.d.ts +25 -3
  110. package/dist/components/SceneBuilder.d.ts.map +1 -1
  111. package/dist/components/SceneBuilder.js +68 -38
  112. package/dist/components/SkyController.d.ts +25 -1
  113. package/dist/components/SkyController.d.ts.map +1 -1
  114. package/dist/components/SkyController.js +189 -130
  115. package/dist/components/SkyMesh.d.ts.map +1 -1
  116. package/dist/components/SkyMesh.js +26 -1
  117. package/dist/components/SkyStars.d.ts +11 -0
  118. package/dist/components/SkyStars.d.ts.map +1 -0
  119. package/dist/components/SkyStars.js +187 -0
  120. package/dist/components/SkySystem.d.ts +3 -3
  121. package/dist/components/SkySystem.d.ts.map +1 -1
  122. package/dist/components/SkySystem.js +8 -2
  123. package/dist/components/Sun.d.ts +15 -1
  124. package/dist/components/Sun.d.ts.map +1 -1
  125. package/dist/components/Sun.js +64 -3
  126. package/dist/components/SunLight.d.ts +6 -1
  127. package/dist/components/SunLight.d.ts.map +1 -1
  128. package/dist/components/SunLight.js +96 -44
  129. package/dist/components/TerrainBuilder.d.ts.map +1 -1
  130. package/dist/components/TerrainBuilder.js +2 -0
  131. package/dist/components/TextGenerator.d.ts +9 -0
  132. package/dist/components/TextGenerator.d.ts.map +1 -0
  133. package/dist/components/TextGenerator.js +29 -0
  134. package/dist/components/TruchetGrid.d.ts +1 -1
  135. package/dist/components/TruchetGrid.d.ts.map +1 -1
  136. package/dist/components/TruchetGrid.js +3 -30
  137. package/dist/components/VoronoiGrid.d.ts +1 -1
  138. package/dist/components/VoronoiGrid.d.ts.map +1 -1
  139. package/dist/components/VoronoiGrid.js +6 -33
  140. package/dist/components/WallpaperGrid.d.ts +1 -1
  141. package/dist/components/WallpaperGrid.d.ts.map +1 -1
  142. package/dist/components/WallpaperGrid.js +6 -35
  143. package/dist/components/environment/Rain.d.ts +15 -0
  144. package/dist/components/environment/Rain.d.ts.map +1 -0
  145. package/dist/components/environment/Rain.js +110 -0
  146. package/dist/components/environment/Rainbow.d.ts +20 -0
  147. package/dist/components/environment/Rainbow.d.ts.map +1 -0
  148. package/dist/components/environment/Rainbow.js +974 -0
  149. package/dist/components/environment/Sandstorm.d.ts +20 -0
  150. package/dist/components/environment/Sandstorm.d.ts.map +1 -0
  151. package/dist/components/environment/Sandstorm.js +776 -0
  152. package/dist/components/environment/Snow.d.ts +20 -0
  153. package/dist/components/environment/Snow.d.ts.map +1 -0
  154. package/dist/components/environment/Snow.js +609 -0
  155. package/dist/components/environment/Thunderstorm.d.ts +20 -0
  156. package/dist/components/environment/Thunderstorm.d.ts.map +1 -0
  157. package/dist/components/environment/Thunderstorm.js +731 -0
  158. package/dist/components/environment/Tornado.d.ts +20 -0
  159. package/dist/components/environment/Tornado.d.ts.map +1 -0
  160. package/dist/components/environment/Tornado.js +762 -0
  161. package/dist/components/environment/index.d.ts +13 -0
  162. package/dist/components/environment/index.d.ts.map +1 -0
  163. package/dist/components/environment/index.js +7 -0
  164. package/dist/components/index.d.ts +10 -10
  165. package/dist/components/index.d.ts.map +1 -1
  166. package/dist/components/index.js +8 -6
  167. package/dist/components/land/LandPatch.d.ts +15 -0
  168. package/dist/components/land/LandPatch.d.ts.map +1 -0
  169. package/dist/components/land/LandPatch.js +170 -0
  170. package/dist/components/land/index.d.ts +3 -0
  171. package/dist/components/land/index.d.ts.map +1 -0
  172. package/dist/components/land/index.js +1 -0
  173. package/dist/components/space/Earth.d.ts +16 -0
  174. package/dist/components/space/Earth.d.ts.map +1 -0
  175. package/dist/components/space/Earth.js +75 -0
  176. package/dist/components/space/ShootingStar.d.ts +21 -0
  177. package/dist/components/space/ShootingStar.d.ts.map +1 -0
  178. package/dist/components/space/ShootingStar.js +101 -0
  179. package/dist/components/space/ShootingStars.d.ts +16 -0
  180. package/dist/components/space/ShootingStars.d.ts.map +1 -0
  181. package/dist/components/space/ShootingStars.js +71 -0
  182. package/dist/components/space/SolarSystem.d.ts +16 -0
  183. package/dist/components/space/SolarSystem.d.ts.map +1 -0
  184. package/dist/components/space/SolarSystem.js +141 -0
  185. package/dist/components/space/Stars.d.ts +20 -0
  186. package/dist/components/space/Stars.d.ts.map +1 -0
  187. package/dist/components/space/Stars.js +160 -0
  188. package/dist/components/space/index.d.ts +11 -0
  189. package/dist/components/space/index.d.ts.map +1 -0
  190. package/dist/components/space/index.js +8 -0
  191. package/dist/components/terrain/TerrainSurface.d.ts.map +1 -1
  192. package/dist/components/terrain/TerrainSurface.js +27 -3
  193. package/dist/components/terrain/types.d.ts +5 -1
  194. package/dist/components/terrain/types.d.ts.map +1 -1
  195. package/dist/components/text/BurnAwayText.d.ts +15 -0
  196. package/dist/components/text/BurnAwayText.d.ts.map +1 -0
  197. package/dist/components/text/BurnAwayText.js +4 -0
  198. package/dist/components/text/ChalkboardText.d.ts +15 -0
  199. package/dist/components/text/ChalkboardText.d.ts.map +1 -0
  200. package/dist/components/text/ChalkboardText.js +4 -0
  201. package/dist/components/text/ConstellationText.d.ts +15 -0
  202. package/dist/components/text/ConstellationText.d.ts.map +1 -0
  203. package/dist/components/text/ConstellationText.js +4 -0
  204. package/dist/components/text/EmbroideryText.d.ts +15 -0
  205. package/dist/components/text/EmbroideryText.d.ts.map +1 -0
  206. package/dist/components/text/EmbroideryText.js +4 -0
  207. package/dist/components/text/FourierSketchText.d.ts +15 -0
  208. package/dist/components/text/FourierSketchText.d.ts.map +1 -0
  209. package/dist/components/text/FourierSketchText.js +4 -0
  210. package/dist/components/text/FrostGrowthText.d.ts +15 -0
  211. package/dist/components/text/FrostGrowthText.d.ts.map +1 -0
  212. package/dist/components/text/FrostGrowthText.js +4 -0
  213. package/dist/components/text/HandwritingText.d.ts +15 -0
  214. package/dist/components/text/HandwritingText.d.ts.map +1 -0
  215. package/dist/components/text/HandwritingText.js +4 -0
  216. package/dist/components/text/InkBleedText.d.ts +15 -0
  217. package/dist/components/text/InkBleedText.d.ts.map +1 -0
  218. package/dist/components/text/InkBleedText.js +4 -0
  219. package/dist/components/text/LightPaintingText.d.ts +15 -0
  220. package/dist/components/text/LightPaintingText.d.ts.map +1 -0
  221. package/dist/components/text/LightPaintingText.js +4 -0
  222. package/dist/components/text/LiquidMetalText.d.ts +15 -0
  223. package/dist/components/text/LiquidMetalText.d.ts.map +1 -0
  224. package/dist/components/text/LiquidMetalText.js +4 -0
  225. package/dist/components/text/NeonTubeText.d.ts +15 -0
  226. package/dist/components/text/NeonTubeText.d.ts.map +1 -0
  227. package/dist/components/text/NeonTubeText.js +4 -0
  228. package/dist/components/text/PlasmaDischargeText.d.ts +15 -0
  229. package/dist/components/text/PlasmaDischargeText.d.ts.map +1 -0
  230. package/dist/components/text/PlasmaDischargeText.js +4 -0
  231. package/dist/components/text/TextObjectView.d.ts +12 -0
  232. package/dist/components/text/TextObjectView.d.ts.map +1 -0
  233. package/dist/components/text/TextObjectView.js +11 -0
  234. package/dist/components/text/engine/fieldkit.d.ts +24 -0
  235. package/dist/components/text/engine/fieldkit.d.ts.map +1 -0
  236. package/dist/components/text/engine/fieldkit.js +201 -0
  237. package/dist/components/text/engine/glyphs.d.ts +19 -0
  238. package/dist/components/text/engine/glyphs.d.ts.map +1 -0
  239. package/dist/components/text/engine/glyphs.js +269 -0
  240. package/dist/components/text/engine/looks/burnAway.d.ts +144 -0
  241. package/dist/components/text/engine/looks/burnAway.d.ts.map +1 -0
  242. package/dist/components/text/engine/looks/burnAway.js +593 -0
  243. package/dist/components/text/engine/looks/chalkboard.d.ts +135 -0
  244. package/dist/components/text/engine/looks/chalkboard.d.ts.map +1 -0
  245. package/dist/components/text/engine/looks/chalkboard.js +426 -0
  246. package/dist/components/text/engine/looks/constellation.d.ts +111 -0
  247. package/dist/components/text/engine/looks/constellation.d.ts.map +1 -0
  248. package/dist/components/text/engine/looks/constellation.js +496 -0
  249. package/dist/components/text/engine/looks/embroidery.d.ts +165 -0
  250. package/dist/components/text/engine/looks/embroidery.d.ts.map +1 -0
  251. package/dist/components/text/engine/looks/embroidery.js +645 -0
  252. package/dist/components/text/engine/looks/frostGrowth.d.ts +109 -0
  253. package/dist/components/text/engine/looks/frostGrowth.d.ts.map +1 -0
  254. package/dist/components/text/engine/looks/frostGrowth.js +727 -0
  255. package/dist/components/text/engine/looks/index.d.ts +2 -0
  256. package/dist/components/text/engine/looks/index.d.ts.map +1 -0
  257. package/dist/components/text/engine/looks/index.js +48 -0
  258. package/dist/components/text/engine/looks/inkBleed.d.ts +103 -0
  259. package/dist/components/text/engine/looks/inkBleed.d.ts.map +1 -0
  260. package/dist/components/text/engine/looks/inkBleed.js +590 -0
  261. package/dist/components/text/engine/looks/lightPainting.d.ts +132 -0
  262. package/dist/components/text/engine/looks/lightPainting.d.ts.map +1 -0
  263. package/dist/components/text/engine/looks/lightPainting.js +567 -0
  264. package/dist/components/text/engine/looks/liquidMetal.d.ts +135 -0
  265. package/dist/components/text/engine/looks/liquidMetal.d.ts.map +1 -0
  266. package/dist/components/text/engine/looks/liquidMetal.js +655 -0
  267. package/dist/components/text/engine/looks/plasmaDischarge.d.ts +126 -0
  268. package/dist/components/text/engine/looks/plasmaDischarge.d.ts.map +1 -0
  269. package/dist/components/text/engine/looks/plasmaDischarge.js +763 -0
  270. package/dist/components/text/engine/methods.d.ts +19 -0
  271. package/dist/components/text/engine/methods.d.ts.map +1 -0
  272. package/dist/components/text/engine/methods.js +126 -0
  273. package/dist/components/text/engine/playback.d.ts +40 -0
  274. package/dist/components/text/engine/playback.d.ts.map +1 -0
  275. package/dist/components/text/engine/playback.js +114 -0
  276. package/dist/components/text/engine/ribbon.d.ts +58 -0
  277. package/dist/components/text/engine/ribbon.d.ts.map +1 -0
  278. package/dist/components/text/engine/ribbon.js +250 -0
  279. package/dist/components/text/engine/variants.d.ts +159 -0
  280. package/dist/components/text/engine/variants.d.ts.map +1 -0
  281. package/dist/components/text/engine/variants.js +378 -0
  282. package/dist/components/text/fonts/architects-daughter.outline.d.ts +3 -0
  283. package/dist/components/text/fonts/architects-daughter.outline.d.ts.map +1 -0
  284. package/dist/components/text/fonts/architects-daughter.outline.js +4 -0
  285. package/dist/components/text/fonts/architects-daughter.strokes.d.ts +3 -0
  286. package/dist/components/text/fonts/architects-daughter.strokes.d.ts.map +1 -0
  287. package/dist/components/text/fonts/architects-daughter.strokes.js +4 -0
  288. package/dist/components/text/fonts/caveat.outline.d.ts +3 -0
  289. package/dist/components/text/fonts/caveat.outline.d.ts.map +1 -0
  290. package/dist/components/text/fonts/caveat.outline.js +4 -0
  291. package/dist/components/text/fonts/caveat.strokes.d.ts +3 -0
  292. package/dist/components/text/fonts/caveat.strokes.d.ts.map +1 -0
  293. package/dist/components/text/fonts/caveat.strokes.js +4 -0
  294. package/dist/components/text/fonts/courgette.outline.d.ts +3 -0
  295. package/dist/components/text/fonts/courgette.outline.d.ts.map +1 -0
  296. package/dist/components/text/fonts/courgette.outline.js +4 -0
  297. package/dist/components/text/fonts/courgette.strokes.d.ts +3 -0
  298. package/dist/components/text/fonts/courgette.strokes.d.ts.map +1 -0
  299. package/dist/components/text/fonts/courgette.strokes.js +4 -0
  300. package/dist/components/text/fonts/dancing-script.outline.d.ts +3 -0
  301. package/dist/components/text/fonts/dancing-script.outline.d.ts.map +1 -0
  302. package/dist/components/text/fonts/dancing-script.outline.js +4 -0
  303. package/dist/components/text/fonts/dancing-script.strokes.d.ts +3 -0
  304. package/dist/components/text/fonts/dancing-script.strokes.d.ts.map +1 -0
  305. package/dist/components/text/fonts/dancing-script.strokes.js +4 -0
  306. package/dist/components/text/fonts/gochi-hand.outline.d.ts +3 -0
  307. package/dist/components/text/fonts/gochi-hand.outline.d.ts.map +1 -0
  308. package/dist/components/text/fonts/gochi-hand.outline.js +4 -0
  309. package/dist/components/text/fonts/gochi-hand.strokes.d.ts +3 -0
  310. package/dist/components/text/fonts/gochi-hand.strokes.d.ts.map +1 -0
  311. package/dist/components/text/fonts/gochi-hand.strokes.js +4 -0
  312. package/dist/components/text/fonts/handlee.outline.d.ts +3 -0
  313. package/dist/components/text/fonts/handlee.outline.d.ts.map +1 -0
  314. package/dist/components/text/fonts/handlee.outline.js +4 -0
  315. package/dist/components/text/fonts/handlee.strokes.d.ts +3 -0
  316. package/dist/components/text/fonts/handlee.strokes.d.ts.map +1 -0
  317. package/dist/components/text/fonts/handlee.strokes.js +4 -0
  318. package/dist/components/text/fonts/index.d.ts +5 -0
  319. package/dist/components/text/fonts/index.d.ts.map +1 -0
  320. package/dist/components/text/fonts/index.js +44 -0
  321. package/dist/components/text/fonts/indie-flower.outline.d.ts +3 -0
  322. package/dist/components/text/fonts/indie-flower.outline.d.ts.map +1 -0
  323. package/dist/components/text/fonts/indie-flower.outline.js +4 -0
  324. package/dist/components/text/fonts/indie-flower.strokes.d.ts +3 -0
  325. package/dist/components/text/fonts/indie-flower.strokes.d.ts.map +1 -0
  326. package/dist/components/text/fonts/indie-flower.strokes.js +4 -0
  327. package/dist/components/text/fonts/kalam.outline.d.ts +3 -0
  328. package/dist/components/text/fonts/kalam.outline.d.ts.map +1 -0
  329. package/dist/components/text/fonts/kalam.outline.js +4 -0
  330. package/dist/components/text/fonts/kalam.strokes.d.ts +3 -0
  331. package/dist/components/text/fonts/kalam.strokes.d.ts.map +1 -0
  332. package/dist/components/text/fonts/kalam.strokes.js +4 -0
  333. package/dist/components/text/fonts/kaushan-script.outline.d.ts +3 -0
  334. package/dist/components/text/fonts/kaushan-script.outline.d.ts.map +1 -0
  335. package/dist/components/text/fonts/kaushan-script.outline.js +4 -0
  336. package/dist/components/text/fonts/kaushan-script.strokes.d.ts +3 -0
  337. package/dist/components/text/fonts/kaushan-script.strokes.d.ts.map +1 -0
  338. package/dist/components/text/fonts/kaushan-script.strokes.js +4 -0
  339. package/dist/components/text/fonts/mynerve.outline.d.ts +3 -0
  340. package/dist/components/text/fonts/mynerve.outline.d.ts.map +1 -0
  341. package/dist/components/text/fonts/mynerve.outline.js +4 -0
  342. package/dist/components/text/fonts/mynerve.strokes.d.ts +3 -0
  343. package/dist/components/text/fonts/mynerve.strokes.d.ts.map +1 -0
  344. package/dist/components/text/fonts/mynerve.strokes.js +4 -0
  345. package/dist/components/text/fonts/nanum-pen-script.outline.d.ts +3 -0
  346. package/dist/components/text/fonts/nanum-pen-script.outline.d.ts.map +1 -0
  347. package/dist/components/text/fonts/nanum-pen-script.outline.js +4 -0
  348. package/dist/components/text/fonts/nanum-pen-script.strokes.d.ts +3 -0
  349. package/dist/components/text/fonts/nanum-pen-script.strokes.d.ts.map +1 -0
  350. package/dist/components/text/fonts/nanum-pen-script.strokes.js +4 -0
  351. package/dist/components/text/fonts/pacifico.outline.d.ts +3 -0
  352. package/dist/components/text/fonts/pacifico.outline.d.ts.map +1 -0
  353. package/dist/components/text/fonts/pacifico.outline.js +4 -0
  354. package/dist/components/text/fonts/pacifico.strokes.d.ts +3 -0
  355. package/dist/components/text/fonts/pacifico.strokes.d.ts.map +1 -0
  356. package/dist/components/text/fonts/pacifico.strokes.js +4 -0
  357. package/dist/components/text/fonts/patrick-hand.outline.d.ts +3 -0
  358. package/dist/components/text/fonts/patrick-hand.outline.d.ts.map +1 -0
  359. package/dist/components/text/fonts/patrick-hand.outline.js +4 -0
  360. package/dist/components/text/fonts/patrick-hand.strokes.d.ts +3 -0
  361. package/dist/components/text/fonts/patrick-hand.strokes.d.ts.map +1 -0
  362. package/dist/components/text/fonts/patrick-hand.strokes.js +4 -0
  363. package/dist/components/text/fonts/poppins.outline.d.ts +3 -0
  364. package/dist/components/text/fonts/poppins.outline.d.ts.map +1 -0
  365. package/dist/components/text/fonts/poppins.outline.js +4 -0
  366. package/dist/components/text/fonts/poppins.strokes.d.ts +3 -0
  367. package/dist/components/text/fonts/poppins.strokes.d.ts.map +1 -0
  368. package/dist/components/text/fonts/poppins.strokes.js +4 -0
  369. package/dist/components/text/fonts/satisfy.outline.d.ts +3 -0
  370. package/dist/components/text/fonts/satisfy.outline.d.ts.map +1 -0
  371. package/dist/components/text/fonts/satisfy.outline.js +4 -0
  372. package/dist/components/text/fonts/satisfy.strokes.d.ts +3 -0
  373. package/dist/components/text/fonts/satisfy.strokes.d.ts.map +1 -0
  374. package/dist/components/text/fonts/satisfy.strokes.js +4 -0
  375. package/dist/components/text/fonts/sriracha.outline.d.ts +3 -0
  376. package/dist/components/text/fonts/sriracha.outline.d.ts.map +1 -0
  377. package/dist/components/text/fonts/sriracha.outline.js +4 -0
  378. package/dist/components/text/fonts/sriracha.strokes.d.ts +3 -0
  379. package/dist/components/text/fonts/sriracha.strokes.d.ts.map +1 -0
  380. package/dist/components/text/fonts/sriracha.strokes.js +4 -0
  381. package/dist/components/text/index.d.ts +27 -0
  382. package/dist/components/text/index.d.ts.map +1 -0
  383. package/dist/components/text/index.js +13 -0
  384. package/dist/components/text/useTextObject.d.ts +21 -0
  385. package/dist/components/text/useTextObject.d.ts.map +1 -0
  386. package/dist/components/text/useTextObject.js +118 -0
  387. package/dist/components/water/OceanSurface.d.ts.map +1 -1
  388. package/dist/components/water/OceanSurface.js +3 -1
  389. package/dist/components/water/WaterBody.d.ts.map +1 -1
  390. package/dist/components/water/WaterBody.js +3 -1
  391. package/dist/components/water/types.d.ts +5 -1
  392. package/dist/components/water/types.d.ts.map +1 -1
  393. package/dist/constants.d.ts.map +1 -1
  394. package/dist/constants.js +4 -0
  395. package/dist/hooks/index.d.ts +2 -0
  396. package/dist/hooks/index.d.ts.map +1 -1
  397. package/dist/hooks/index.js +1 -0
  398. package/dist/hooks/useCloudSun.d.ts +9 -4
  399. package/dist/hooks/useCloudSun.d.ts.map +1 -1
  400. package/dist/hooks/useCloudSun.js +17 -7
  401. package/dist/hooks/useConfigLive.d.ts +3 -2
  402. package/dist/hooks/useConfigLive.d.ts.map +1 -1
  403. package/dist/hooks/useContinuousEffects.d.ts.map +1 -1
  404. package/dist/hooks/useContinuousEffects.js +4 -10
  405. package/dist/hooks/useEnvironmentProbe.d.ts +3 -22
  406. package/dist/hooks/useEnvironmentProbe.d.ts.map +1 -1
  407. package/dist/hooks/useEnvironmentProbe.js +47 -8
  408. package/dist/hooks/useGridSurface.d.ts +3 -10
  409. package/dist/hooks/useGridSurface.d.ts.map +1 -1
  410. package/dist/hooks/useGridSurface.js +5 -31
  411. package/dist/hooks/useInteraction.d.ts.map +1 -1
  412. package/dist/hooks/useInteraction.js +19 -72
  413. package/dist/hooks/useLightConfig.d.ts +2 -1
  414. package/dist/hooks/useLightConfig.d.ts.map +1 -1
  415. package/dist/hooks/useOceanMaterial.d.ts +6 -2
  416. package/dist/hooks/useOceanMaterial.d.ts.map +1 -1
  417. package/dist/hooks/useOceanMaterial.js +37 -2
  418. package/dist/hooks/useSkyLive.d.ts +23 -0
  419. package/dist/hooks/useSkyLive.d.ts.map +1 -0
  420. package/dist/hooks/useSkyLive.js +30 -0
  421. package/dist/hooks/useSkyUniforms.d.ts.map +1 -1
  422. package/dist/hooks/useSkyUniforms.js +2 -10
  423. package/dist/hooks/useTerrainLive.d.ts +3 -1
  424. package/dist/hooks/useTerrainLive.d.ts.map +1 -1
  425. package/dist/hooks/useTerrainTextures.d.ts +38 -0
  426. package/dist/hooks/useTerrainTextures.d.ts.map +1 -0
  427. package/dist/hooks/useTerrainTextures.js +149 -0
  428. package/dist/index.d.ts +11 -2
  429. package/dist/index.d.ts.map +1 -1
  430. package/dist/index.js +8 -1
  431. package/dist/operations/catalogue/blastOff.d.ts +3 -0
  432. package/dist/operations/catalogue/blastOff.d.ts.map +1 -0
  433. package/dist/operations/catalogue/blastOff.js +118 -0
  434. package/dist/operations/catalogue/bounce.d.ts +3 -0
  435. package/dist/operations/catalogue/bounce.d.ts.map +1 -0
  436. package/dist/operations/catalogue/bounce.js +34 -0
  437. package/dist/operations/catalogue/curlSmoke.d.ts.map +1 -1
  438. package/dist/operations/catalogue/curlSmoke.js +3 -1
  439. package/dist/operations/catalogue/dissolve.d.ts.map +1 -1
  440. package/dist/operations/catalogue/dissolve.js +2 -1
  441. package/dist/operations/catalogue/driftUp.d.ts +3 -0
  442. package/dist/operations/catalogue/driftUp.d.ts.map +1 -0
  443. package/dist/operations/catalogue/driftUp.js +57 -0
  444. package/dist/operations/catalogue/emberAsh.d.ts.map +1 -1
  445. package/dist/operations/catalogue/emberAsh.js +2 -1
  446. package/dist/operations/catalogue/flip.d.ts.map +1 -1
  447. package/dist/operations/catalogue/flip.js +19 -9
  448. package/dist/operations/catalogue/float.d.ts +3 -0
  449. package/dist/operations/catalogue/float.d.ts.map +1 -0
  450. package/dist/operations/catalogue/float.js +39 -0
  451. package/dist/operations/catalogue/flyBy.d.ts +3 -0
  452. package/dist/operations/catalogue/flyBy.d.ts.map +1 -0
  453. package/dist/operations/catalogue/flyBy.js +79 -0
  454. package/dist/operations/catalogue/frost.d.ts.map +1 -1
  455. package/dist/operations/catalogue/frost.js +10 -3
  456. package/dist/operations/catalogue/grow.d.ts +3 -0
  457. package/dist/operations/catalogue/grow.d.ts.map +1 -0
  458. package/dist/operations/catalogue/grow.js +19 -0
  459. package/dist/operations/catalogue/hologram.d.ts.map +1 -1
  460. package/dist/operations/catalogue/hologram.js +11 -5
  461. package/dist/operations/catalogue/jelly.d.ts.map +1 -1
  462. package/dist/operations/catalogue/jelly.js +18 -8
  463. package/dist/operations/catalogue/knockAway.d.ts +3 -0
  464. package/dist/operations/catalogue/knockAway.d.ts.map +1 -0
  465. package/dist/operations/catalogue/knockAway.js +74 -0
  466. package/dist/operations/catalogue/leafFall.d.ts +3 -0
  467. package/dist/operations/catalogue/leafFall.d.ts.map +1 -0
  468. package/dist/operations/catalogue/leafFall.js +74 -0
  469. package/dist/operations/catalogue/lidarScan.d.ts.map +1 -1
  470. package/dist/operations/catalogue/lidarScan.js +4 -1
  471. package/dist/operations/catalogue/metalize.d.ts.map +1 -1
  472. package/dist/operations/catalogue/metalize.js +8 -2
  473. package/dist/operations/catalogue/motionTrail.d.ts +6 -0
  474. package/dist/operations/catalogue/motionTrail.d.ts.map +1 -0
  475. package/dist/operations/catalogue/motionTrail.js +221 -0
  476. package/dist/operations/catalogue/petrify.d.ts.map +1 -1
  477. package/dist/operations/catalogue/petrify.js +9 -3
  478. package/dist/operations/catalogue/physicalExit.d.ts +55 -0
  479. package/dist/operations/catalogue/physicalExit.d.ts.map +1 -0
  480. package/dist/operations/catalogue/physicalExit.js +165 -0
  481. package/dist/operations/catalogue/physicalHeld.d.ts +41 -0
  482. package/dist/operations/catalogue/physicalHeld.d.ts.map +1 -0
  483. package/dist/operations/catalogue/physicalHeld.js +78 -0
  484. package/dist/operations/catalogue/physicalMix.d.ts +45 -0
  485. package/dist/operations/catalogue/physicalMix.d.ts.map +1 -0
  486. package/dist/operations/catalogue/physicalMix.js +144 -0
  487. package/dist/operations/catalogue/pop.d.ts +3 -0
  488. package/dist/operations/catalogue/pop.d.ts.map +1 -0
  489. package/dist/operations/catalogue/pop.js +44 -0
  490. package/dist/operations/catalogue/print3d.d.ts.map +1 -1
  491. package/dist/operations/catalogue/print3d.js +5 -1
  492. package/dist/operations/catalogue/pulse.d.ts +3 -0
  493. package/dist/operations/catalogue/pulse.d.ts.map +1 -0
  494. package/dist/operations/catalogue/pulse.js +29 -0
  495. package/dist/operations/catalogue/restPose.d.ts +5 -7
  496. package/dist/operations/catalogue/restPose.d.ts.map +1 -1
  497. package/dist/operations/catalogue/restPose.js +18 -48
  498. package/dist/operations/catalogue/rotate.d.ts +3 -0
  499. package/dist/operations/catalogue/rotate.d.ts.map +1 -0
  500. package/dist/operations/catalogue/rotate.js +49 -0
  501. package/dist/operations/catalogue/shake.d.ts +3 -0
  502. package/dist/operations/catalogue/shake.d.ts.map +1 -0
  503. package/dist/operations/catalogue/shake.js +31 -0
  504. package/dist/operations/catalogue/shatter.d.ts.map +1 -1
  505. package/dist/operations/catalogue/shatter.js +5 -1
  506. package/dist/operations/catalogue/slam.d.ts +3 -0
  507. package/dist/operations/catalogue/slam.d.ts.map +1 -0
  508. package/dist/operations/catalogue/slam.js +89 -0
  509. package/dist/operations/catalogue/slingshot.d.ts +3 -0
  510. package/dist/operations/catalogue/slingshot.d.ts.map +1 -0
  511. package/dist/operations/catalogue/slingshot.js +88 -0
  512. package/dist/operations/catalogue/spin.d.ts.map +1 -1
  513. package/dist/operations/catalogue/spin.js +24 -13
  514. package/dist/operations/catalogue/sway.d.ts +3 -0
  515. package/dist/operations/catalogue/sway.d.ts.map +1 -0
  516. package/dist/operations/catalogue/sway.js +23 -0
  517. package/dist/operations/catalogue/swirl.d.ts.map +1 -1
  518. package/dist/operations/catalogue/swirl.js +6 -5
  519. package/dist/operations/catalogue/trailCore.d.ts +89 -0
  520. package/dist/operations/catalogue/trailCore.d.ts.map +1 -0
  521. package/dist/operations/catalogue/trailCore.js +190 -0
  522. package/dist/operations/catalogue/trailGhosts.d.ts +5 -0
  523. package/dist/operations/catalogue/trailGhosts.d.ts.map +1 -0
  524. package/dist/operations/catalogue/trailGhosts.js +179 -0
  525. package/dist/operations/catalogue/trailStampStyles.d.ts +11 -0
  526. package/dist/operations/catalogue/trailStampStyles.d.ts.map +1 -0
  527. package/dist/operations/catalogue/trailStampStyles.js +479 -0
  528. package/dist/operations/catalogue/trailStamps.d.ts +57 -0
  529. package/dist/operations/catalogue/trailStamps.d.ts.map +1 -0
  530. package/dist/operations/catalogue/trailStamps.js +349 -0
  531. package/dist/operations/catalogue/trailStreaks.d.ts +3 -0
  532. package/dist/operations/catalogue/trailStreaks.d.ts.map +1 -0
  533. package/dist/operations/catalogue/trailStreaks.js +147 -0
  534. package/dist/operations/catalogue/transitionField.d.ts +30 -0
  535. package/dist/operations/catalogue/transitionField.d.ts.map +1 -1
  536. package/dist/operations/catalogue/transitionField.js +21 -0
  537. package/dist/operations/catalogue/turnAway.d.ts +3 -0
  538. package/dist/operations/catalogue/turnAway.d.ts.map +1 -0
  539. package/dist/operations/catalogue/turnAway.js +54 -0
  540. package/dist/operations/catalogue/vortexDrain.d.ts +3 -0
  541. package/dist/operations/catalogue/vortexDrain.d.ts.map +1 -0
  542. package/dist/operations/catalogue/vortexDrain.js +68 -0
  543. package/dist/operations/catalogue/warp.d.ts +3 -0
  544. package/dist/operations/catalogue/warp.d.ts.map +1 -0
  545. package/dist/operations/catalogue/warp.js +73 -0
  546. package/dist/operations/catalogue/whoosh.d.ts +3 -0
  547. package/dist/operations/catalogue/whoosh.d.ts.map +1 -0
  548. package/dist/operations/catalogue/whoosh.js +84 -0
  549. package/dist/operations/catalogue/wobble.d.ts +3 -0
  550. package/dist/operations/catalogue/wobble.d.ts.map +1 -0
  551. package/dist/operations/catalogue/wobble.js +23 -0
  552. package/dist/operations/clipPreview.d.ts +3 -0
  553. package/dist/operations/clipPreview.d.ts.map +1 -0
  554. package/dist/operations/clipPreview.js +20 -0
  555. package/dist/operations/groupFanout.d.ts +96 -0
  556. package/dist/operations/groupFanout.d.ts.map +1 -0
  557. package/dist/operations/groupFanout.js +365 -0
  558. package/dist/operations/groups.d.ts +20 -0
  559. package/dist/operations/groups.d.ts.map +1 -0
  560. package/dist/operations/groups.js +66 -0
  561. package/dist/operations/index.d.ts +5 -2
  562. package/dist/operations/index.d.ts.map +1 -1
  563. package/dist/operations/index.js +5 -2
  564. package/dist/operations/objectEffects.d.ts +161 -6
  565. package/dist/operations/objectEffects.d.ts.map +1 -1
  566. package/dist/operations/objectEffects.js +1091 -17
  567. package/dist/operations/registry.d.ts.map +1 -1
  568. package/dist/operations/registry.js +24 -2
  569. package/dist/operations/runtime.d.ts +57 -2
  570. package/dist/operations/runtime.d.ts.map +1 -1
  571. package/dist/operations/runtime.js +161 -18
  572. package/dist/operations/types.d.ts +60 -3
  573. package/dist/operations/types.d.ts.map +1 -1
  574. package/dist/operations/types.js +5 -1
  575. package/dist/operations/useObjectEffectLayers.d.ts +2 -2
  576. package/dist/operations/useObjectEffectLayers.d.ts.map +1 -1
  577. package/dist/operations/useObjectEffectLayers.js +31 -10
  578. package/dist/operations/usePresentedVisibility.d.ts +10 -0
  579. package/dist/operations/usePresentedVisibility.d.ts.map +1 -0
  580. package/dist/operations/usePresentedVisibility.js +53 -0
  581. package/dist/presets/terrainBiomes.d.ts +67 -0
  582. package/dist/presets/terrainBiomes.d.ts.map +1 -0
  583. package/dist/presets/terrainBiomes.js +294 -0
  584. package/dist/presets/terrainPresets.d.ts +6 -0
  585. package/dist/presets/terrainPresets.d.ts.map +1 -1
  586. package/dist/presets/terrainPresets.js +26 -38
  587. package/dist/shaders/glsl/oceanCore.glsl.d.ts +2 -2
  588. package/dist/shaders/glsl/oceanCore.glsl.d.ts.map +1 -1
  589. package/dist/shaders/glsl/oceanCore.glsl.js +17 -0
  590. package/dist/shaders/glsl/surfaceCore.glsl.d.ts +21 -0
  591. package/dist/shaders/glsl/surfaceCore.glsl.d.ts.map +1 -0
  592. package/dist/shaders/glsl/surfaceCore.glsl.js +120 -0
  593. package/dist/shaders/glsl/terrainCore.glsl.d.ts +16 -3
  594. package/dist/shaders/glsl/terrainCore.glsl.d.ts.map +1 -1
  595. package/dist/shaders/glsl/terrainCore.glsl.js +266 -20
  596. package/dist/shaders/ocean/OceanSurfaceMaterial.d.ts +2 -0
  597. package/dist/shaders/ocean/OceanSurfaceMaterial.d.ts.map +1 -1
  598. package/dist/shaders/ocean/OceanSurfaceMaterial.js +3 -0
  599. package/dist/shaders/terrain/TerrainMaterial.d.ts +17 -0
  600. package/dist/shaders/terrain/TerrainMaterial.d.ts.map +1 -1
  601. package/dist/shaders/terrain/TerrainMaterial.js +107 -8
  602. package/dist/triggers/engine.d.ts +44 -0
  603. package/dist/triggers/engine.d.ts.map +1 -0
  604. package/dist/triggers/engine.js +165 -0
  605. package/dist/triggers/hosts/actions.d.ts +8 -0
  606. package/dist/triggers/hosts/actions.d.ts.map +1 -0
  607. package/dist/triggers/hosts/actions.js +22 -0
  608. package/dist/triggers/hosts/interactions.d.ts +6 -0
  609. package/dist/triggers/hosts/interactions.d.ts.map +1 -0
  610. package/dist/triggers/hosts/interactions.js +4 -0
  611. package/dist/triggers/hosts/timelineCues.d.ts +2 -0
  612. package/dist/triggers/hosts/timelineCues.d.ts.map +1 -0
  613. package/dist/triggers/hosts/timelineCues.js +22 -0
  614. package/dist/triggers/index.d.ts +13 -0
  615. package/dist/triggers/index.d.ts.map +1 -0
  616. package/dist/triggers/index.js +9 -0
  617. package/dist/triggers/kinds/action.d.ts +2 -0
  618. package/dist/triggers/kinds/action.d.ts.map +1 -0
  619. package/dist/triggers/kinds/action.js +31 -0
  620. package/dist/triggers/kinds/animations.d.ts +2 -0
  621. package/dist/triggers/kinds/animations.d.ts.map +1 -0
  622. package/dist/triggers/kinds/animations.js +75 -0
  623. package/dist/triggers/kinds/effects.d.ts +2 -0
  624. package/dist/triggers/kinds/effects.d.ts.map +1 -0
  625. package/dist/triggers/kinds/effects.js +27 -0
  626. package/dist/triggers/kinds/index.d.ts +4 -0
  627. package/dist/triggers/kinds/index.d.ts.map +1 -0
  628. package/dist/triggers/kinds/index.js +4 -0
  629. package/dist/triggers/log.d.ts +21 -0
  630. package/dist/triggers/log.d.ts.map +1 -0
  631. package/dist/triggers/log.js +43 -0
  632. package/dist/triggers/readiness.d.ts +40 -0
  633. package/dist/triggers/readiness.d.ts.map +1 -0
  634. package/dist/triggers/readiness.js +158 -0
  635. package/dist/triggers/registry.d.ts +41 -0
  636. package/dist/triggers/registry.d.ts.map +1 -0
  637. package/dist/triggers/registry.js +7 -0
  638. package/dist/types/gridConfigs.d.ts +18 -23
  639. package/dist/types/gridConfigs.d.ts.map +1 -1
  640. package/dist/ui/UiAnchorUpdater.d.ts +10 -0
  641. package/dist/ui/UiAnchorUpdater.d.ts.map +1 -0
  642. package/dist/ui/UiAnchorUpdater.js +111 -0
  643. package/dist/ui/UiLayers.d.ts +20 -0
  644. package/dist/ui/UiLayers.d.ts.map +1 -0
  645. package/dist/ui/UiLayers.js +57 -0
  646. package/dist/ui/index.d.ts +9 -0
  647. package/dist/ui/index.d.ts.map +1 -0
  648. package/dist/ui/index.js +6 -0
  649. package/dist/ui/uiAnchors.d.ts +21 -0
  650. package/dist/ui/uiAnchors.d.ts.map +1 -0
  651. package/dist/ui/uiAnchors.js +22 -0
  652. package/dist/ui/uiBaseStyles.d.ts +2 -0
  653. package/dist/ui/uiBaseStyles.d.ts.map +1 -0
  654. package/dist/ui/uiBaseStyles.js +100 -0
  655. package/dist/ui/uiBinder.d.ts +30 -0
  656. package/dist/ui/uiBinder.d.ts.map +1 -0
  657. package/dist/ui/uiBinder.js +344 -0
  658. package/dist/utils/configAnimations.d.ts.map +1 -1
  659. package/dist/utils/configAnimations.js +5 -1
  660. package/dist/utils/gridConfig.d.ts +1 -1
  661. package/dist/utils/gridConfig.d.ts.map +1 -1
  662. package/dist/utils/gridConfig.js +1 -1
  663. package/dist/utils/landPatch.d.ts +33 -0
  664. package/dist/utils/landPatch.d.ts.map +1 -0
  665. package/dist/utils/landPatch.js +114 -0
  666. package/dist/utils/renderedSky.d.ts +32 -0
  667. package/dist/utils/renderedSky.d.ts.map +1 -0
  668. package/dist/utils/renderedSky.js +57 -0
  669. package/dist/utils/skyMoon.d.ts +35 -0
  670. package/dist/utils/skyMoon.d.ts.map +1 -0
  671. package/dist/utils/skyMoon.js +41 -0
  672. package/dist/utils/terrainHeight.d.ts +4 -0
  673. package/dist/utils/terrainHeight.d.ts.map +1 -0
  674. package/dist/utils/terrainHeight.js +150 -0
  675. package/dist/utils/terrainTextureResolver.d.ts +18 -0
  676. package/dist/utils/terrainTextureResolver.d.ts.map +1 -0
  677. package/dist/utils/terrainTextureResolver.js +17 -0
  678. package/dist/utils/terrainUniforms.d.ts +17 -0
  679. package/dist/utils/terrainUniforms.d.ts.map +1 -1
  680. package/dist/utils/terrainUniforms.js +84 -0
  681. package/dist/utils/textureArrays.d.ts +29 -0
  682. package/dist/utils/textureArrays.d.ts.map +1 -0
  683. package/dist/utils/textureArrays.js +140 -0
  684. package/package.json +2 -2
@@ -1,8 +1,10 @@
1
1
  import { findNodesByName } from '@3driseai/3drise-core';
2
+ import { GroupFanout, isFanRow } from './groupFanout.js';
2
3
  import { getOperation, resolveParams } from './registry.js';
3
- import { applyOperation, forceRevert, runOf } from './runtime.js';
4
- /** An operation can be an object effect. */
5
- export const isObjectOperation = (def) => !!def && def.usableIn.includes('object') && !!def.revert;
4
+ import { applyOperation, forceRevert, registerAddedEffects, runOf, warmOperation } from './runtime.js';
5
+ import { periodicEase } from './catalogue/physicalHeld.js';
6
+ /** An operation can be an object effect (one-shots too: they have no way back, and play with loop). */
7
+ export const isObjectOperation = (def) => !!def && def.usableIn.includes('object');
6
8
  /**
7
9
  * The effects that actually run: on, known, usable on objects, one per operation,
8
10
  * and one of each stack (the first wins).
@@ -27,17 +29,133 @@ export function runningObjectEffects(effects) {
27
29
  }
28
30
  return out;
29
31
  }
30
- /** An object effect's parameters: defaults, its overrides, then what object effects force. */
31
- export const objectEffectParams = (def, effect) => ({ ...resolveParams(def, effect.params), ...(def.objectParams ?? {}) });
32
+ export function effectPresence(def, effect, follows, inStep = false) {
33
+ if (!follows)
34
+ return 'decorate';
35
+ // a step's effect is a look that takes turns: only Base effects are entrances / exits
36
+ if (def.presence === 'vanish')
37
+ return inStep ? 'decorate' : 'vanish';
38
+ // Disappear is the user's choice: on, the effect takes the object away — an entrance and an exit
39
+ const spec = def.params?.disappear;
40
+ if (spec) {
41
+ const v = { ...(def.objectParams ?? {}), ...(effect.params ?? {}) }.disappear ?? spec.default;
42
+ if (v === true)
43
+ return inStep ? 'decorate' : 'vanish';
44
+ }
45
+ return def.presence === 'paint' ? 'paint' : 'decorate';
46
+ }
47
+ /** An object effect's parameters: the operation's defaults, the object defaults, then its own values. */
48
+ export const objectEffectParams = (def, effect, follows = false, inStep = false) => ({
49
+ // an object effect starts from the operation's object defaults (objectParams: a hologram that stays),
50
+ // and the user's own values go on top — so `disappear` is theirs to switch on
51
+ ...resolveParams(def, { ...(def.objectParams ?? {}), ...(effect.params ?? {}) }),
52
+ // a take-over that follows visibility draws the object only where it has painted it
53
+ ...(effectPresence(def, effect, follows, inStep) === 'paint' ? { __reveal: true } : {}),
54
+ });
55
+ /** An effect's playback with the defaults filled in. */
56
+ export const playbackOf = (effect) => ({
57
+ autoplay: effect.playback?.autoplay !== false,
58
+ reverse: !!effect.playback?.reverse,
59
+ loop: !!effect.playback?.loop,
60
+ yoyo: !!effect.playback?.yoyo,
61
+ });
62
+ const playbackKey = (pb) => `${+pb.autoplay}${+pb.reverse}${+pb.loop}${+pb.yoyo}`;
63
+ /** What makes a row "another effect" when it changes: its playback, and how it follows visibility. */
64
+ const rowKey = (def, e, follows, inStep) => playbackKey(playbackOf(e)) + (follows ? 'v' : '') + (def ? effectPresence(def, e, follows, inStep) : '');
65
+ /** An object's effects controller; `create` makes one for an object that has no effects of its own yet. */
66
+ export function objectEffectsControllerFor(root, create = false) {
67
+ return controllers.get(root) ?? (create ? new ObjectEffectsController(root) : undefined);
68
+ }
69
+ // effects added by interactions and actions are run by the object's controller (see runtime.runEffect)
70
+ registerAddedEffects({
71
+ add: (root, key, effect) => !!objectEffectsControllerFor(root, true)?.addEffect(key, effect),
72
+ remove: (root, key) => !!controllers.get(root)?.removeEffect(key),
73
+ has: (root, key) => !!controllers.get(root)?.hasEffect(key),
74
+ applyClip: (root, key, clip, parts) => !!objectEffectsControllerFor(root, true)?.applyClip(key, clip, parts),
75
+ removeClip: (root, key) => !!controllers.get(root)?.removeClip(key),
76
+ hasClip: (root, key) => !!controllers.get(root)?.hasClip(key),
77
+ });
78
+ /** The step of an object's effect steps that is on now (-1: none) — for the editor. */
79
+ export function currentEffectStep(root) {
80
+ return (root && controllers.get(root)?.step) ?? -1;
81
+ }
82
+ /** An object's own effect clip follows its visibility (`visible`) and has an effect that is on. */
83
+ export const clipFollowsVisibility = (clip) => !!clip?.visible && (!!clip.effects?.some(e => e?.enabled) || !!clip.steps?.some(s => s?.effects?.some(e => e && e.enabled !== false)));
84
+ /**
85
+ * The object was shown or hidden: its visibility effects play in, or play out.
86
+ * Returns a promise (null = nothing to wait for) that resolves
87
+ * shown when the effects are ready and the object is drawn (its entrance is starting)
88
+ * hidden when they have played out and the object is no longer drawn
89
+ * The controller sets the group's `visible` itself at those two moments.
90
+ */
91
+ export function setObjectEffectsVisible(root, visible) {
92
+ return (root && controllers.get(root)?.setVisible(visible)) || null;
93
+ }
94
+ /** Plays in once and holds — what an object effect does with no playback set. */
95
+ const isPlain = (pb) => !pb.reverse && !pb.loop && !pb.yoyo;
96
+ /** The controller of each object that has effects, by its group — for playing an effect from outside. */
97
+ const controllers = new WeakMap();
98
+ /**
99
+ * Play one of an object's effects from its start, with its playback settings
100
+ * (the editor's ▶; an effect with autoplay off starts this way). False when the
101
+ * object or the effect is not there.
102
+ */
103
+ export function playObjectEffect(root, effectId) {
104
+ return !!root && !!controllers.get(root)?.play(effectId);
105
+ }
32
106
  const namesKey = (e) => (e.meshNames ?? []).join('|');
107
+ const seconds = (v, fallback) => (Number.isFinite(Number(v)) && Number(v) >= 0 ? Number(v) : fallback);
108
+ export const STEP_IN = 1;
109
+ export const STEP_HOLD = 1;
110
+ /** What makes a step sequence "another sequence" (it restarts): its structure and timing — not the effects' own values. */
111
+ const stepsKeyOf = (cfg) => (cfg?.steps?.length
112
+ ? JSON.stringify([!!cfg.loop, !!cfg.yoyo, cfg.steps.map(s => [s.id, s.in, s.hold, !!s.playOut, (s.effects ?? []).map(e => [e.id, e.operation, e.enabled !== false, namesKey(e)])])])
113
+ : '');
114
+ /** A step's effect as a row of the running list: a look takes the step's `in` as its duration, a motion runs while the step is on. */
115
+ function stepRow(step, e, on, prefix = '', parts) {
116
+ const def = getOperation(e.operation);
117
+ const look = !!def?.revert && !def.periodic;
118
+ return {
119
+ id: `${prefix}${step.id}:${e.id}`, operation: e.operation, enabled: on && e.enabled !== false, meshNames: parts?.length ? parts : e.meshNames,
120
+ params: look ? { ...(e.params ?? {}), duration: seconds(step.in, STEP_IN) } : e.params,
121
+ ...(look ? {} : { playback: { loop: true } }),
122
+ ...(e.scope ? { scope: e.scope } : {}),
123
+ };
124
+ }
33
125
  export class ObjectEffectsController {
34
126
  root;
35
127
  running = new Map(); // effect id →
128
+ /** Effects playing out (removed / switched off): their op → when they are gone. */
129
+ leaving = new Set();
36
130
  effects = [];
37
131
  refreshing = null;
38
132
  disposed = false;
133
+ /** The object is shown — visibility effects wait while it is not. */
134
+ shown = true;
135
+ /** The object is on screen: it stays drawn while its effects play out, and is not yet drawn while they get ready. */
136
+ drawn = true;
137
+ visRun = 0;
138
+ /** The object's own list (always on) and its steps; `effects` is what runs: the two laid together. */
139
+ own = { key: '', prefix: '', effects: [], cfg: null, stepsKey: '', index: 0, dir: 1, run: 0 };
140
+ /** Clips applied from outside (key → run), in the order they were applied. */
141
+ clips = new Map();
142
+ /** The object's own steps wait while an applied clip has steps. */
143
+ ownPaused = false;
144
+ /** Effects added by interactions / actions (key → row; disabled while it plays out). */
145
+ added = new Map();
146
+ /** The object's own rows (Base and steps) as last composed: id → it is a step's. */
147
+ ownRows = new Map();
148
+ /** A group: its visual effects and physical 'each' effects go to the children (see ./groupFanout.ts). */
149
+ fan = null;
150
+ spread = {};
151
+ /** Added effects that follow visibility: a group's effects on this child, when the group's follow it. */
152
+ addedFollows = new Set();
39
153
  constructor(root) {
40
154
  this.root = root;
155
+ controllers.set(root, this);
156
+ // a group never draws an effect itself: its visual / 'each' effects — its own, and those triggered on it — go to its children
157
+ if (root.userData?.objectType === 'group')
158
+ this.fan = new GroupFanout(root, (r, create) => objectEffectsControllerFor(r, create));
41
159
  }
42
160
  /** The object's targets for an effect: the object, or its named nodes. */
43
161
  targetsOf(e) {
@@ -53,11 +171,29 @@ export class ObjectEffectsController {
53
171
  applyOperation(def, t, params, this.root, { bare: true });
54
172
  }
55
173
  off(r, instant) {
174
+ if (r.cycle) {
175
+ r.cycle.cancelled = true;
176
+ r.cycle.wake?.();
177
+ }
178
+ r.cycle = undefined;
179
+ r.phase = undefined;
180
+ if (r.wipe) {
181
+ r.wipe.cancelled = true;
182
+ r.wipe = undefined;
183
+ }
56
184
  const def = getOperation(r.op);
57
- if (!def)
185
+ if (!def || !r.started)
58
186
  return;
187
+ // a one-shot has no way back: at once = stop its move where it is and put the object back
188
+ if (!def.revert) {
189
+ if (instant)
190
+ for (const t of r.targets)
191
+ def.cancel?.(t);
192
+ return;
193
+ }
59
194
  // with its own parameters — it may have gone on at once (load / edit), but goes off with its transition
60
- const params = instant ? { ...r.params, duration: 0 } : r.params;
195
+ // (a take-over switched off on an object that stays: it gives the object back, it does not take it away)
196
+ const params = instant ? { ...r.params, duration: 0 } : r.kind === 'paint' ? { ...r.params, __reveal: false } : r.params;
61
197
  for (const t of r.targets)
62
198
  forceRevert(def, t, params);
63
199
  }
@@ -65,34 +201,955 @@ export class ObjectEffectsController {
65
201
  * Bring what runs in line with `effects`.
66
202
  * animate switching an effect on / off plays its transition (studio, actions)
67
203
  * instant everything lands in its end state at once (scene load)
68
- * A changed parameter always lands at once.
204
+ * A changed parameter always lands at once. A row switched to another
205
+ * operation clears the old one at once, then plays the new one in from the
206
+ * original object.
69
207
  */
70
- sync(effects, mode) {
208
+ sync(effects, mode, steps, parts, follows = false, group) {
71
209
  if (this.disposed)
72
210
  return;
211
+ // a group (`group` = its spread): the rows that go to the children are handed out by syncList
212
+ if (group) {
213
+ this.fan ??= new GroupFanout(this.root, (r, create) => objectEffectsControllerFor(r, create));
214
+ this.spread = group;
215
+ }
216
+ else if (this.fan && this.root.userData?.objectType !== 'group') {
217
+ this.fan.dispose();
218
+ this.fan = null;
219
+ }
220
+ const c = this.own;
221
+ c.effects = effects ?? [];
222
+ c.follows = follows;
223
+ c.parts = parts?.length ? parts : undefined;
224
+ const key = stepsKeyOf(steps);
225
+ c.cfg = key ? steps : null;
226
+ if (key !== c.stepsKey) { // another sequence: from its first step
227
+ c.stepsKey = key;
228
+ c.index = 0;
229
+ c.dir = 1;
230
+ if (!this.ownPaused)
231
+ this.scheduleStep(c);
232
+ }
233
+ this.syncList(this.compose(), mode);
234
+ }
235
+ /** A clip's rows: the step that is on, its always-on effects, and the steps that wait (listed, off). */
236
+ rowsOf(c) {
237
+ const on = [], waiting = [];
238
+ const stepsOn = !c.off && !(c === this.own && this.ownPaused);
239
+ c.cfg?.steps.forEach((s, i) => {
240
+ for (const e of s.effects ?? []) {
241
+ const row = stepRow(s, e, stepsOn && i === c.index, c.prefix, c.parts);
242
+ (row.enabled ? on : waiting).push(row);
243
+ }
244
+ });
245
+ const base = c.prefix || c.parts || c.off
246
+ ? c.effects.map(e => ({ ...e, id: `${c.prefix}${e.id}`, enabled: !!e.enabled && !c.off, ...(c.parts ? { meshNames: c.parts } : {}) }))
247
+ : c.effects;
248
+ if (c === this.own) {
249
+ this.ownRows = new Map();
250
+ for (const e of [...on, ...waiting])
251
+ this.ownRows.set(e.id, true);
252
+ for (const e of base)
253
+ this.ownRows.set(e.id, false);
254
+ }
255
+ return { on, base, waiting };
256
+ }
257
+ /** A row follows the object's visibility (one of its own, with `visible` on) · it is a step's. */
258
+ visOf(id) {
259
+ // a group's effect on this child, following the group's visibility (see fanLeave / fanEnter)
260
+ if (this.addedFollows.has(id))
261
+ return [true, false];
262
+ const inStep = this.ownRows.get(id);
263
+ return [!!this.own.follows && inStep !== undefined, !!inStep];
264
+ }
265
+ /**
266
+ * The running list, top first (the first of two that clash wins): added effects, applied clips
267
+ * (newest first; in each, the step that is on, then its always-on effects), the object's own clip,
268
+ * then everything that waits or is playing out.
269
+ */
270
+ compose() {
271
+ const own = this.rowsOf(this.own);
272
+ if (!this.added.size && !this.clips.size)
273
+ return own.on.length || own.waiting.length ? [...own.on, ...own.base, ...own.waiting] : own.base;
274
+ const top = [], rest = [];
275
+ for (const e of [...this.added.values()].reverse())
276
+ (e.enabled ? top : rest).push(e);
277
+ for (const c of [...this.clips.values()].reverse()) {
278
+ const r = this.rowsOf(c);
279
+ if (c.off)
280
+ rest.push(...r.on, ...r.base, ...r.waiting);
281
+ else {
282
+ top.push(...r.on, ...r.base);
283
+ rest.push(...r.waiting);
284
+ }
285
+ }
286
+ return [...top, ...own.on, ...own.base, ...own.waiting, ...rest];
287
+ }
288
+ /**
289
+ * Put an effect on the object on top of its own (an interaction, an action). `key` names it for
290
+ * removeEffect. Already on: a one-shot plays again, anything else is left as it is.
291
+ */
292
+ addEffect(key, effect, opts) {
293
+ const def = getOperation(effect.operation);
294
+ if (this.disposed || !isObjectOperation(def))
295
+ return false;
296
+ // a group: an effect triggered on it that goes to the children is handed out (staggered)
297
+ if (this.fan && isFanRow(effect))
298
+ return this.fan.addTriggered(key, effect);
299
+ const id = `+${key}`;
300
+ const follows = !!opts?.follows;
301
+ if (follows !== this.addedFollows.has(id)) {
302
+ if (follows)
303
+ this.addedFollows.add(id);
304
+ else
305
+ this.addedFollows.delete(id);
306
+ this.added.delete(key); // following visibility or not makes it another effect
307
+ }
308
+ const cur = this.added.get(key);
309
+ const { autoplay: _a, ...pb } = effect.playback ?? {};
310
+ // a motion added with no playback runs until it is reverted
311
+ const playback = Object.keys(pb).length ? pb : def.periodic ? { loop: true } : undefined;
312
+ const row = { id, operation: effect.operation, enabled: true, meshNames: effect.meshNames, params: effect.params, ...(playback ? { playback } : {}) };
313
+ if (cur?.enabled && cur.operation === effect.operation) {
314
+ // the same values: a one-shot plays again, anything else is left as it is; new values land at once
315
+ if (JSON.stringify([cur.params ?? null, cur.playback ?? null, cur.meshNames ?? null]) === JSON.stringify([row.params ?? null, row.playback ?? null, row.meshNames ?? null])) {
316
+ if (!def.revert && this.running.has(id))
317
+ this.play(id);
318
+ return true;
319
+ }
320
+ }
321
+ this.added.set(key, row);
322
+ // instant: put on in its held state (a group's effects reaching a child on scene load / as it joins)
323
+ this.syncList(this.compose(), opts?.instant ? 'instant' : 'direct');
324
+ return true;
325
+ }
326
+ /** Take an added effect off: it plays out (or what is below it takes over again). */
327
+ removeEffect(key) {
328
+ if (this.fan?.hasTriggered(key))
329
+ return this.fan.removeTriggered(key);
330
+ const cur = this.added.get(key);
331
+ if (this.disposed || !cur?.enabled)
332
+ return false;
333
+ const off = { ...cur, enabled: false };
334
+ this.added.set(key, off);
335
+ this.syncList(this.compose(), 'direct');
336
+ // it stays listed (off) until it has really gone, so a later sync does not cut its out short
337
+ const l = [...this.leaving].find(x => x.id === cur.id);
338
+ void (l?.done ?? Promise.resolve()).then(() => { if (this.added.get(key) === off)
339
+ this.added.delete(key); });
340
+ return true;
341
+ }
342
+ hasEffect(key) { return !!this.added.get(key)?.enabled || !!this.fan?.hasTriggered(key); }
343
+ /** The object's own steps wait while an applied clip has steps; afterwards they start again from the first. */
344
+ refreshPause() {
345
+ const paused = [...this.clips.values()].some(c => !c.off && !!c.cfg);
346
+ if (paused === this.ownPaused)
347
+ return;
348
+ this.ownPaused = paused;
349
+ const c = this.own;
350
+ clearTimeout(c.timer);
351
+ c.run++;
352
+ if (!paused) {
353
+ c.index = 0;
354
+ c.dir = 1;
355
+ this.scheduleStep(c);
356
+ }
357
+ }
358
+ /**
359
+ * Apply a whole effect clip over the object's own (an interaction, an action). `key` names this
360
+ * application for removeClip; `parts` narrows it to nodes of the model. Already on: left as it is.
361
+ */
362
+ applyClip(key, clip, parts) {
363
+ if (this.disposed)
364
+ return false;
365
+ if (this.fan) {
366
+ // a group: the clip's visual / 'each' effects go to the children (staggered), the rest runs on the group
367
+ const pick = (fan) => {
368
+ const keep = (e) => !!e && isFanRow(e) === fan;
369
+ const steps = (clip.steps ?? []).map(s => ({ ...s, effects: (s.effects ?? []).filter(keep) })).filter(s => s.effects.length);
370
+ return { ...clip, effects: (clip.effects ?? []).filter(keep), steps };
371
+ };
372
+ const kids = pick(true), mine = pick(false);
373
+ const handed = kids.effects.length || kids.steps.length ? this.fan.applyClip(key, kids) : false;
374
+ if (!mine.effects.length && !mine.steps.length)
375
+ return handed;
376
+ clip = mine;
377
+ }
378
+ const cur = this.clips.get(key);
379
+ if (cur && !cur.off)
380
+ return true;
381
+ if (cur) {
382
+ clearTimeout(cur.timer);
383
+ cur.run++;
384
+ }
385
+ // a triggered clip has no autoplay of its own and never follows visibility: it plays when it is applied
386
+ const effects = (clip.effects ?? []).filter(e => e && isObjectOperation(getOperation(e.operation))).map(e => {
387
+ const { autoplay: _a, ...pb } = e.playback ?? {};
388
+ const { playback: _p, meshNames: _m, ...row } = e;
389
+ return { ...row, ...(Object.keys(pb).length ? { playback: pb } : {}) };
390
+ });
391
+ const steps = (clip.steps ?? []).filter(s => s?.effects?.length);
392
+ const cfg = steps.length ? { steps, loop: clip.loop, yoyo: clip.yoyo } : null;
393
+ const c = { key, prefix: `~${key}:`, effects, cfg, stepsKey: stepsKeyOf(cfg), index: 0, dir: 1, run: (cur?.run ?? 0) + 1, parts: parts?.length ? parts : undefined };
394
+ this.clips.delete(key); // newest last
395
+ this.clips.set(key, c);
396
+ this.refreshPause();
397
+ this.scheduleStep(c);
398
+ this.syncList(this.compose(), 'direct');
399
+ return true;
400
+ }
401
+ /** Take an applied clip off: its effects play out, and what it had taken over comes back. */
402
+ removeClip(key) {
403
+ const handed = !this.disposed && !!this.fan?.removeClip(key);
404
+ const c = this.clips.get(key);
405
+ if (this.disposed || !c || c.off)
406
+ return handed;
407
+ c.off = true;
408
+ clearTimeout(c.timer);
409
+ c.run++;
410
+ this.refreshPause();
411
+ this.syncList(this.compose(), 'direct');
412
+ const gone = [...this.leaving].filter(x => x.id.startsWith(c.prefix)).map(x => x.done);
413
+ void Promise.all(gone).then(() => { if (this.clips.get(key) === c && c.off)
414
+ this.clips.delete(key); });
415
+ return true;
416
+ }
417
+ hasClip(key) { const c = this.clips.get(key); return (!!c && !c.off) || !!this.fan?.hasClip(key); }
418
+ /**
419
+ * A clip's current step's clock: its hold starts when its looks have really played in (they first
420
+ * wait for the outgoing step, and the first time for their shaders), so a slow start never eats a step.
421
+ */
422
+ scheduleStep(c) {
423
+ clearTimeout(c.timer);
424
+ const run = ++c.run;
425
+ const s = c.cfg?.steps[c.index];
426
+ if (!s)
427
+ return;
428
+ if (!this.shown)
429
+ return; // hidden: the steps wait for the object to be shown
430
+ const pause = (ms) => new Promise(res => { c.timer = setTimeout(res, ms); });
431
+ const live = () => !this.disposed && run === c.run;
432
+ void (async () => {
433
+ await pause(0); // after the sync that put the step on
434
+ const ids = (s.effects ?? []).map(e => `${c.prefix}${s.id}:${e.id}`);
435
+ const looks = () => ids.map(id => this.running.get(id)).filter((r) => { const d = r && getOperation(r.op); return !!r && !!d?.revert && !d.periodic; });
436
+ for (let waited = 0; live() && waited < 15000 && looks().some(r => !r.started); waited += 50)
437
+ await pause(50);
438
+ if (!live())
439
+ return;
440
+ await Promise.all(looks().map(r => this.done(r)));
441
+ if (!live())
442
+ return;
443
+ // a group: the step's effects reach the children one after another — the hold starts when the last child's looks are on
444
+ const fan = c === this.own ? this.fan : null;
445
+ if (fan && (s.effects ?? []).some(e => e && isFanRow(e))) {
446
+ // wait until the last child has been given the step's effects, then for its looks to play in
447
+ for (let waited = 0; live() && waited < 30000 && fan.pending(ids); waited += 50)
448
+ await pause(50);
449
+ if (!live())
450
+ return;
451
+ await pause(seconds(s.in, STEP_IN) * 1000);
452
+ if (!live())
453
+ return;
454
+ }
455
+ await pause(seconds(s.hold, STEP_HOLD) * 1000);
456
+ if (live())
457
+ this.nextStep(c);
458
+ })();
459
+ }
460
+ nextStep(c) {
461
+ const cfg = c.cfg;
462
+ if (!cfg || this.disposed || c.off)
463
+ return;
464
+ const n = cfg.steps.length;
465
+ let i = c.index + c.dir;
466
+ if (cfg.yoyo) { // there and back through the steps
467
+ if (n < 2)
468
+ return;
469
+ if (i >= n) {
470
+ c.dir = -1;
471
+ i = n - 2;
472
+ }
473
+ else if (i < 0) {
474
+ if (!cfg.loop)
475
+ return;
476
+ c.dir = 1;
477
+ i = 1;
478
+ }
479
+ }
480
+ else if (i >= n) {
481
+ if (!cfg.loop || n < 2)
482
+ return; // stays on its last step
483
+ i = 0;
484
+ }
485
+ const leaving = cfg.steps[c.index];
486
+ c.index = i;
487
+ // direct: the next step plays in over the outgoing one; a step that plays out goes first, and the next waits for it
488
+ this.syncList(this.compose(), leaving?.playOut ? 'animate' : 'direct');
489
+ this.scheduleStep(c);
490
+ }
491
+ /** The step of the object's own clip that is on (-1: no steps, or they wait for an applied clip). */
492
+ get step() { return this.own.cfg && !this.ownPaused ? this.own.index : -1; }
493
+ syncList(effects, mode) {
494
+ if (this.disposed)
495
+ return;
496
+ if (this.fan) {
497
+ // a group: its own rows that go to the children (visual, physical 'each' — Base and steps) are handed out
498
+ const fanRows = [], rest = [];
499
+ for (const e of effects ?? [])
500
+ (e && this.ownRows.has(e.id) && isFanRow(e) ? fanRows : rest).push(e);
501
+ effects = rest;
502
+ this.fan.sync(fanRows, this.spread, mode === 'instant' ? 'instant' : 'animate', !!this.own.follows);
503
+ }
73
504
  this.effects = effects ?? [];
74
505
  if (this.refreshing)
75
506
  return; // the refresh puts the latest list back when it is done
76
507
  const next = runningObjectEffects(effects);
77
508
  const byId = new Map(next.map(e => [e.id, e]));
509
+ const clearing = new Map(); // switched row → its old effect gone
510
+ const wiped = []; // direct handover: outgoing take-overs
511
+ // an effect that goes on under another row (the same effect, from above or below it): op → its targets
512
+ const comingOn = new Map();
513
+ for (const e of next)
514
+ if (!this.running.has(e.id))
515
+ comingOn.set(e.operation, namesKey(e));
516
+ const incoming = [];
517
+ const listed = new Set(this.effects.map(e => e?.id));
518
+ // removed while it was playing out: finish it at once
519
+ for (const l of this.leaving) {
520
+ if (listed.has(l.id))
521
+ continue;
522
+ this.off(l.r, true);
523
+ l.done = Promise.all(l.r.targets.map(t => runOf(l.r.op, t)));
524
+ void l.done.then(() => this.leaving.delete(l));
525
+ }
78
526
  for (const [id, r] of this.running) {
79
527
  const e = byId.get(id);
80
- if (e && e.operation === r.op && namesKey(e) === r.targetsKey)
528
+ if (e && e.operation === r.op && namesKey(e) === r.targetsKey && rowKey(getOperation(e.operation), e, ...this.visOf(e.id)) === r.playbackKey)
81
529
  continue;
82
- this.off(r, mode === 'instant');
530
+ if (e) {
531
+ // switched (another operation, or another playback): the old effect goes at once (no out transition under the new one's in)
532
+ if (r.started) {
533
+ this.off(r, true);
534
+ clearing.set(id, Promise.all(r.targets.map(t => runOf(r.op, t))));
535
+ }
536
+ else if (r.waitFor) {
537
+ clearing.set(id, r.waitFor); // switched again before it started: still wait for the first
538
+ }
539
+ }
540
+ else {
541
+ // switched off plays out; a row removed from the list is cleared at once
542
+ const gone = mode === 'instant' || !listed.has(id);
543
+ if (mode !== 'instant' && r.started && comingOn.get(r.op) === r.targetsKey) {
544
+ // the same effect carries on under another row: it is handed over as it stands (the new row's values take over)
545
+ this.cancelCycle(r);
546
+ r.phase = undefined;
547
+ if (r.wipe) {
548
+ r.wipe.cancelled = true;
549
+ r.wipe = undefined;
550
+ }
551
+ this.running.delete(id);
552
+ continue;
553
+ }
554
+ // a direct handover: a held take-over stays on until the incoming one has wiped it (paired below)
555
+ if (!gone && mode === 'direct' && r.started && !r.cycle && !r.stopping && getOperation(r.op)?.field)
556
+ wiped.push([id, r]);
557
+ else
558
+ this.playOut(id, r, gone, mode === 'instant');
559
+ }
83
560
  this.running.delete(id);
84
561
  }
85
562
  for (const e of next) {
86
563
  const def = getOperation(e.operation);
87
- const params = objectEffectParams(def, e);
564
+ const [follows, inStep] = this.visOf(e.id);
565
+ const params = objectEffectParams(def, e, follows, inStep);
88
566
  const paramsKey = JSON.stringify(params);
89
567
  const r = this.running.get(e.id);
90
568
  if (r && r.paramsKey === paramsKey)
91
569
  continue;
92
- const targets = r?.targets ?? this.targetsOf(e);
93
- this.on(def, targets, r || mode === 'instant' ? { ...params, duration: 0 } : params);
94
- this.running.set(e.id, { op: def.value, targets, targetsKey: namesKey(e), params, paramsKey });
570
+ if (r && !r.started) {
571
+ r.params = params;
572
+ r.paramsKey = paramsKey;
573
+ continue;
574
+ } // starts with the latest
575
+ const playback = playbackOf(e);
576
+ if (r?.cycle) {
577
+ // a parameter changed under a running cycle: its next pass picks it up;
578
+ // a periodic motion is on the whole time, so it takes it now
579
+ r.params = params;
580
+ r.paramsKey = paramsKey;
581
+ if (def.periodic)
582
+ this.on(def, r.targets, { ...params, __backward: !!r.cycle.back, duration: 0 });
583
+ continue;
584
+ }
585
+ const entry = { op: def.value, targets: r?.targets ?? this.targetsOf(e), targetsKey: namesKey(e), params, paramsKey, started: false, playback, playbackKey: rowKey(def, e, follows, inStep), kind: effectPresence(def, e, follows, inStep), follows, inStep };
586
+ this.running.set(e.id, entry);
587
+ const instant = !!r || mode === 'instant';
588
+ if (!r)
589
+ incoming.push([def, entry]);
590
+ // start from the original: after the effect this row replaces, and after others still playing out
591
+ // (the same operation coming back on just turns its own out transition around).
592
+ // A direct handover does not wait: the new look plays in over the old one.
593
+ const waits = mode === 'direct' ? [] : [...this.leaving].filter(l => l.op !== def.value).map(l => l.done);
594
+ const cleared = clearing.get(e.id);
595
+ if (cleared)
596
+ waits.push(cleared);
597
+ const wait = waits.length && !instant ? Promise.all(waits) : cleared;
598
+ if (!wait) {
599
+ this.start(def, entry, instant);
600
+ continue;
601
+ }
602
+ entry.waitFor = wait;
603
+ void wait.then(() => {
604
+ if (this.disposed || this.running.get(e.id) !== entry || entry.waitFor !== wait)
605
+ return; // removed, switched or played meanwhile
606
+ this.start(def, entry, instant);
607
+ });
608
+ }
609
+ // pair each outgoing take-over with the incoming one that wipes it (a surface take-over first)
610
+ const by = incoming.find(([d]) => d.field && d.stack) ?? incoming.find(([d]) => d.field);
611
+ for (const [id, r] of wiped) {
612
+ if (by && by[0].value !== r.op)
613
+ this.wipe(id, r, by[0], by[1]);
614
+ else
615
+ this.playOut(id, r, false, false);
616
+ }
617
+ }
618
+ /** Take a row that left the list off: at once (`gone`), or with its out transition — then it is tracked until it has gone. */
619
+ playOut(id, r, gone, untracked) {
620
+ this.off(r, gone);
621
+ if (!r.started || untracked)
622
+ return;
623
+ const l = { id, r, op: r.op, done: Promise.all(r.targets.map(t => runOf(r.op, t))) };
624
+ this.leaving.add(l);
625
+ void l.done.then(() => this.leaving.delete(l));
626
+ }
627
+ /**
628
+ * A direct handover: `r` (a held take-over) stays on while `inc` plays in, and is wiped by
629
+ * inc's front — its field takes inc's direction / scale / sweep, its `clear` follows inc's
630
+ * progress every frame. When inc is fully on, r is taken off at once (nothing of it shows any more).
631
+ */
632
+ wipe(id, r, incDef, inc) {
633
+ const def = getOperation(r.op);
634
+ const token = (r.wipe = { cancelled: false });
635
+ const saved = new Map();
636
+ let resolve;
637
+ const l = { id, r, op: r.op, done: new Promise(res => { resolve = res; }) };
638
+ this.leaving.add(l);
639
+ void l.done.then(() => this.leaving.delete(l));
640
+ const restore = () => saved.forEach((v, f) => { f.direction.value = v.direction; f.scale.value = v.scale; f.sweep.value.copy(v.sweep); f.clear.value = 0; });
641
+ const next = (fn) => (typeof requestAnimationFrame === 'function' ? requestAnimationFrame(() => fn()) : setTimeout(fn, 16));
642
+ const t0 = Date.now();
643
+ const tick = () => {
644
+ if (token.cancelled || this.disposed) {
645
+ resolve();
646
+ return;
647
+ } // taken off some other way (off() did it)
648
+ const live = [...this.running.values()].includes(inc);
649
+ if (!live) { // the incoming look left first: play out the old way
650
+ r.wipe = undefined;
651
+ restore();
652
+ for (const t of r.targets)
653
+ forceRevert(def, t, r.params);
654
+ void Promise.all(r.targets.map(t => runOf(r.op, t))).then(resolve);
655
+ return;
656
+ }
657
+ let done = inc.started;
658
+ r.targets.forEach((t, i) => {
659
+ const fo = def.field(t), fi = incDef.field(inc.targets[i] ?? inc.targets[0]);
660
+ if (!fo || !fi) {
661
+ if (!fo)
662
+ return;
663
+ done = done && !!fi;
664
+ return;
665
+ }
666
+ if (!saved.has(fo))
667
+ saved.set(fo, { direction: fo.direction.value, scale: fo.scale.value, sweep: fo.sweep.value.clone() });
668
+ fo.direction.value = fi.direction.value;
669
+ fo.scale.value = fi.scale.value;
670
+ fo.sweep.value.copy(fi.sweep.value);
671
+ fo.clearEdge.value = fi.edgeWidth.value;
672
+ fo.clear.value = Math.min(1, Math.max(0, fi.progress.value));
673
+ if (fi.progress.value < 0.999)
674
+ done = false;
675
+ });
676
+ if (!done && Date.now() - t0 < 60000) {
677
+ next(tick);
678
+ return;
679
+ }
680
+ r.wipe = undefined; // all of it is wiped: off, at once
681
+ for (const t of r.targets)
682
+ forceRevert(def, t, { ...r.params, duration: 0 });
683
+ void Promise.all(r.targets.map(t => runOf(r.op, t))).then(resolve);
684
+ };
685
+ tick();
686
+ }
687
+ /** Whether the object is shown when the controller starts (before the first sync). */
688
+ setShown(shown) { this.shown = shown; this.drawn = shown; }
689
+ /** See setObjectEffectsVisible. */
690
+ setVisible(visible) {
691
+ if (this.disposed || visible === this.shown)
692
+ return null;
693
+ const c = this.own;
694
+ const steps = !!c.follows && !!c.cfg;
695
+ if (steps && !visible) {
696
+ clearTimeout(c.timer);
697
+ c.run++;
698
+ } // hidden: the steps stop (the step that is on plays out below)
699
+ if (steps && visible && !this.drawn) {
700
+ // shown from hidden: the steps start again from the first, staged while the object is still hidden
701
+ c.index = 0;
702
+ c.dir = 1;
703
+ this.syncList(this.compose(), 'instant');
704
+ }
705
+ // Effects that don't follow visibility (an own clip without it, added effects, applied clips) stop
706
+ // at once while the object is hidden — nothing runs on a hidden object, and nothing may show it
707
+ // again (a physical exit's way back puts the object on) — and come back on at once when it is shown.
708
+ const loose = [...this.running].filter(([, r]) => !r.follows && getOperation(r.op));
709
+ const looseClips = [c, ...this.clips.values()].filter(x => !!x.cfg && !x.off && !(x === c && steps));
710
+ const following = [...this.running].some(([, r]) => r.follows && getOperation(r.op));
711
+ if (!visible) {
712
+ for (const x of looseClips) {
713
+ clearTimeout(x.timer);
714
+ x.run++;
715
+ }
716
+ for (const [, r] of loose)
717
+ this.clear(r);
718
+ if (loose.length && !following)
719
+ this.root.visible = false; // a cleared exit put the object back on
95
720
  }
721
+ this.shown = visible;
722
+ if (visible && (loose.length || looseClips.length)) {
723
+ for (const x of looseClips) {
724
+ x.index = 0;
725
+ x.dir = 1;
726
+ }
727
+ if (looseClips.length)
728
+ this.syncList(this.compose(), 'instant');
729
+ for (const [id, r] of loose) {
730
+ const def = getOperation(r.op);
731
+ if (def && this.running.get(id) === r && !r.started && !r.waitFor)
732
+ this.start(def, r, true);
733
+ }
734
+ for (const x of looseClips)
735
+ if (!(x === c && this.ownPaused))
736
+ this.scheduleStep(x);
737
+ }
738
+ const run = ++this.visRun;
739
+ const rows = [...this.running].filter(([, r]) => r.follows && getOperation(r.op));
740
+ // shown: the step that is on gets its clock once its effects are playing in (from the first step, or where it turned round)
741
+ const clock = () => { if (steps && visible && !this.ownPaused && !this.disposed && run === this.visRun)
742
+ this.scheduleStep(c); };
743
+ // a group whose effects follow visibility: hidden → its children play them out one after another and the
744
+ // group goes after the last; shown → the children start from nothing and play them in one after another
745
+ const fan = this.fan && c.follows ? this.fan : null;
746
+ if (fan && !visible) {
747
+ const outs = [fan.leave()];
748
+ if (rows.length) {
749
+ const p = this.leaveAll(rows, run, false);
750
+ if (p)
751
+ outs.push(p);
752
+ }
753
+ return Promise.all(outs).then(() => {
754
+ if (this.disposed || run !== this.visRun)
755
+ return; // shown again meanwhile
756
+ this.root.visible = false;
757
+ this.drawn = false;
758
+ });
759
+ }
760
+ if (fan && visible)
761
+ fan.park();
762
+ if (!rows.length) {
763
+ this.drawn = visible;
764
+ clock();
765
+ if (fan && visible)
766
+ fan.enter();
767
+ return null;
768
+ } // nothing follows it on the root: the renderer shows / hides
769
+ if (!visible)
770
+ return this.leaveAll(rows, run);
771
+ const entering = this.enterAll(rows, run);
772
+ void entering.then(() => { clock(); if (fan && !this.disposed && run === this.visRun)
773
+ fan.enter(); });
774
+ return entering;
775
+ }
776
+ // ---- a group's effects on this child, following the group's visibility (driven by the group's GroupFanout) ----
777
+ addedRows(keys) {
778
+ return keys.map(k => [`+${k}`, this.running.get(`+${k}`)])
779
+ .filter((x) => !!x[1] && !!getOperation(x[1].op));
780
+ }
781
+ /** The group is being hidden: this child plays the group's effects out, then is no longer drawn. */
782
+ fanLeave(keys) {
783
+ const rows = this.addedRows(keys);
784
+ if (this.disposed || !rows.length)
785
+ return Promise.resolve();
786
+ return this.leaveAll(rows, ++this.visRun) ?? Promise.resolve();
787
+ }
788
+ /** The group is about to be shown: this child starts from nothing (undrawn, the group's effects at their start). */
789
+ fanPark(keys) {
790
+ const rows = this.addedRows(keys);
791
+ if (this.disposed || !rows.length)
792
+ return;
793
+ ++this.visRun;
794
+ for (const [, r] of rows)
795
+ this.clear(r);
796
+ this.root.visible = false;
797
+ this.drawn = false;
798
+ }
799
+ /** Its turn after the group was shown: the group's effects get ready, the child is drawn, they play in. */
800
+ fanEnter(keys) {
801
+ const rows = this.addedRows(keys);
802
+ if (this.disposed || !rows.length) {
803
+ if (!this.disposed && !this.drawn) {
804
+ this.root.visible = true;
805
+ this.drawn = true;
806
+ }
807
+ return Promise.resolve();
808
+ }
809
+ return this.enterAll(rows, ++this.visRun);
810
+ }
811
+ cancelCycle(r) {
812
+ if (r.cycle) {
813
+ r.cycle.cancelled = true;
814
+ r.cycle.wake?.();
815
+ r.cycle = undefined;
816
+ }
817
+ }
818
+ /** Take an effect off at once and leave its row waiting. */
819
+ clear(r) {
820
+ this.off(r, true);
821
+ r.started = false;
822
+ r.stopping = undefined;
823
+ r.waitFor = undefined;
824
+ }
825
+ /** The object is shown: get every effect ready while it is still undrawn, draw it, play them in. */
826
+ async enterAll(rows, run) {
827
+ // shown again while its effects were still playing out: it is still drawn, they turn round where they are
828
+ const turn = this.drawn;
829
+ if (!turn) {
830
+ await Promise.all(rows.map(([, r]) => this.prepare(r)));
831
+ if (this.disposed || run !== this.visRun)
832
+ return; // hidden again meanwhile (leaveAll cleared it)
833
+ }
834
+ this.root.visible = true;
835
+ this.drawn = true;
836
+ // add-ons (trails) first: they are fully on when the entrances start moving the object
837
+ const first = [...rows].sort(([, a], [, b]) => Number(!!getOperation(b.op)?.addOn) - Number(!!getOperation(a.op)?.addOn));
838
+ for (const [id, r] of first)
839
+ if (this.running.get(id) === r)
840
+ this.enter(id, r, turn);
841
+ }
842
+ /** Before the object is drawn: compile the effect and put its start state on. */
843
+ prepare(r) {
844
+ const def = getOperation(r.op);
845
+ r.waitFor = undefined;
846
+ r.stopping = undefined;
847
+ if (r.kind === 'vanish') { // it starts gone
848
+ r.started = true;
849
+ r.phase = {};
850
+ this.on(def, r.targets, { ...r.params, duration: 0 });
851
+ return this.done(r);
852
+ }
853
+ if (def.channel !== 'visual' || !def.revert)
854
+ return Promise.resolve();
855
+ r.started = true; // staged at its start (a paint effect: nothing drawn yet)
856
+ return Promise.all(r.targets.map(t => warmOperation(def, t, r.params, this.root, { bare: true })));
857
+ }
858
+ enter(id, r, turn) {
859
+ const def = getOperation(r.op);
860
+ r.stopping = undefined;
861
+ if (def.addOn && def.revert) { // on at once: it draws the entrance from its first frame
862
+ this.cancelCycle(r);
863
+ r.started = true;
864
+ this.on(def, r.targets, { ...r.params, duration: 0 });
865
+ return;
866
+ }
867
+ if (r.kind === 'paint') {
868
+ this.cancelCycle(r);
869
+ r.started = true;
870
+ this.on(def, r.targets, r.params); // from where it stands: its start, or part-way out
871
+ return;
872
+ }
873
+ if (r.kind === 'vanish') {
874
+ if (r.started)
875
+ this.comeBack(def, r);
876
+ else
877
+ this.entrance(def, r);
878
+ return;
879
+ }
880
+ if (turn) {
881
+ // a plain look turns round from where it is; anything else plays again from its start
882
+ if (r.started && def.revert && !def.periodic && isPlain(r.playback))
883
+ this.on(def, r.targets, r.params);
884
+ else
885
+ this.play(id);
886
+ return;
887
+ }
888
+ r.started = false; // staged at its start: it plays from there
889
+ this.start(def, r, false, true);
890
+ }
891
+ /** A paint / vanish effect's entrance on an object that is already drawn (added, switched on, ▶). */
892
+ entrance(def, r) {
893
+ r.started = true;
894
+ // the object is drawn: a take-over plays in over it (it paints the object in only when the object is being shown)
895
+ if (r.kind === 'paint') {
896
+ this.on(def, r.targets, { ...r.params, __reveal: false });
897
+ return;
898
+ }
899
+ const phase = (r.phase = {});
900
+ this.on(def, r.targets, { ...r.params, duration: 0 }); // gone…
901
+ void this.done(r).then(() => { if (!this.disposed && r.phase === phase)
902
+ this.comeBack(def, r); }); // …and back
903
+ }
904
+ /** A vanish effect plays back from gone (or from part-way); then the object is at rest, with nothing on it. */
905
+ comeBack(def, r) {
906
+ const phase = (r.phase = {});
907
+ r.started = true;
908
+ for (const t of r.targets)
909
+ forceRevert(def, t, r.params);
910
+ void this.done(r).then(() => { if (r.phase === phase) {
911
+ r.phase = undefined;
912
+ r.started = false;
913
+ } });
914
+ }
915
+ /** The object is hidden: play every effect out, then stop drawing it. */
916
+ /** `hide`: stop drawing the object at the end (a group hides itself after its children instead). */
917
+ leaveAll(rows, run, hide = true) {
918
+ if (!this.drawn) { // it was still getting ready to be shown
919
+ for (const [, r] of rows)
920
+ this.clear(r);
921
+ if (hide)
922
+ this.root.visible = false;
923
+ return null;
924
+ }
925
+ // add-ons (trails) stay on through the exits and go off once the object is gone
926
+ const isAddOn = (r) => !!getOperation(r.op)?.addOn;
927
+ const outs = rows.filter(([, r]) => !isAddOn(r)).map(([id, r]) => this.leave(id, r));
928
+ return Promise.all(outs).then(() => {
929
+ if (this.disposed || run !== this.visRun)
930
+ return; // shown again meanwhile
931
+ // while hidden nothing is on, so the next show starts clean — and in the same tick the object goes
932
+ for (const [id, r] of rows)
933
+ if (this.running.get(id) === r && !isAddOn(r))
934
+ this.clear(r);
935
+ if (hide) {
936
+ this.root.visible = false;
937
+ this.drawn = false;
938
+ }
939
+ for (const [id, r] of rows) {
940
+ if (this.running.get(id) !== r || !isAddOn(r))
941
+ continue;
942
+ // it fades out and lets what is in flight finish (it lives in the scene, not on the hidden object)
943
+ const out = this.leave(id, r);
944
+ void Promise.resolve(out).then(() => {
945
+ if (!this.disposed && run === this.visRun && this.running.get(id) === r)
946
+ this.clear(r);
947
+ });
948
+ }
949
+ });
950
+ }
951
+ leave(id, r) {
952
+ const def = getOperation(r.op);
953
+ r.waitFor = undefined;
954
+ if (r.kind === 'vanish') { // from rest, or from part-way in: it plays to gone
955
+ r.started = true;
956
+ r.phase = {};
957
+ this.on(def, r.targets, r.params);
958
+ return this.done(r);
959
+ }
960
+ if (!r.started)
961
+ return null;
962
+ if (r.kind === 'paint') { // retreats with the reveal on: nothing is left behind it
963
+ this.cancelCycle(r);
964
+ for (const t of r.targets)
965
+ forceRevert(def, t, r.params);
966
+ return this.done(r);
967
+ }
968
+ if (!def.revert) { // a one-shot: its move once more, the other way
969
+ this.cancelCycle(r);
970
+ this.on(def, r.targets, { ...r.params, __backward: !r.playback.reverse });
971
+ return this.done(r);
972
+ }
973
+ this.stop(id);
974
+ return r.stopping ?? null;
975
+ }
976
+ /** `force`: play it even with autoplay off (it was asked for). */
977
+ start(def, r, instant, force = false) {
978
+ r.waitFor = undefined;
979
+ if (!this.shown)
980
+ return; // the object is hidden: nothing runs until it is shown
981
+ if (r.follows && r.kind !== 'decorate') {
982
+ // shown at load / a changed value: a take-over is simply on, a vanish effect has nothing on
983
+ if (instant) {
984
+ if (r.kind === 'paint') {
985
+ r.started = true;
986
+ this.on(def, r.targets, { ...r.params, duration: 0 });
987
+ }
988
+ }
989
+ else
990
+ this.entrance(def, r); // added, switched on, ▶: its entrance
991
+ return;
992
+ }
993
+ if (!r.playback.autoplay && !force)
994
+ return; // waits at its start for play()
995
+ r.started = true;
996
+ if (def.periodic) {
997
+ void this.periodic(def, r, instant);
998
+ return;
999
+ }
1000
+ if (isPlain(r.playback)) {
1001
+ this.on(def, r.targets, instant ? { ...r.params, duration: 0 } : r.params);
1002
+ return;
1003
+ }
1004
+ void this.cycle(def, r);
1005
+ }
1006
+ done(r) { return Promise.all(r.targets.map(t => runOf(r.op, t))); }
1007
+ /**
1008
+ * A periodic motion (float, sway…): on for one pass, then it settles — or on for good with Loop.
1009
+ * Reverse runs its clock backwards; yoyo turns the clock round after each pass.
1010
+ */
1011
+ async periodic(def, r, instant) {
1012
+ const token = { cancelled: false, back: r.playback.reverse };
1013
+ r.cycle = token;
1014
+ const { loop, yoyo } = r.playback;
1015
+ const wait = (seconds) => new Promise((resolve) => {
1016
+ const end = () => { clearTimeout(id); token.wake = undefined; resolve(); };
1017
+ const id = setTimeout(end, Math.max(16, seconds * 1000));
1018
+ token.wake = end;
1019
+ });
1020
+ /** The part of a pass at full strength (the rest is building up and settling). */
1021
+ const moving = () => { const d = Number(r.params.duration); return Math.max(0, d - 2 * periodicEase(d)); };
1022
+ const turnOn = (atOnce) => this.on(def, r.targets, { ...r.params, __backward: !!token.back, ...(atOnce ? { duration: 0 } : {}) });
1023
+ turnOn(instant);
1024
+ await this.done(r);
1025
+ if (token.cancelled)
1026
+ return;
1027
+ if (loop && !yoyo)
1028
+ return; // stays on until it is switched off (r.cycle stays: it is running)
1029
+ for (;;) {
1030
+ await wait(moving());
1031
+ if (token.cancelled)
1032
+ return;
1033
+ if (!yoyo && !loop)
1034
+ break;
1035
+ token.back = !token.back; // yoyo: the same motion, backwards
1036
+ turnOn(true);
1037
+ if (!loop) {
1038
+ await wait(moving());
1039
+ if (token.cancelled)
1040
+ return;
1041
+ break;
1042
+ }
1043
+ }
1044
+ for (const t of r.targets)
1045
+ forceRevert(def, t, r.params);
1046
+ await this.done(r);
1047
+ if (r.cycle === token)
1048
+ r.cycle = undefined;
1049
+ }
1050
+ /** Loop / yoyo / reverse, sequenced from apply (forward) and revert (backward). Reads r.params each pass. */
1051
+ async cycle(def, r) {
1052
+ const token = { cancelled: false };
1053
+ r.cycle = token;
1054
+ const { reverse, loop, yoyo } = r.playback;
1055
+ const at = (dur0) => (dur0 ? { ...r.params, duration: 0 } : r.params);
1056
+ // A one-shot (no revert: jelly, flip, spin) starts and ends at rest, so standing at either end is
1057
+ // nothing to do, and its way back is the same move played backwards in time (`__backward`).
1058
+ const oneShot = !def.revert;
1059
+ const forward = async (dur0 = false) => {
1060
+ if (oneShot && dur0)
1061
+ return;
1062
+ this.on(def, r.targets, at(dur0));
1063
+ await this.done(r);
1064
+ };
1065
+ const backward = async (dur0 = false) => {
1066
+ if (oneShot && dur0)
1067
+ return;
1068
+ if (oneShot)
1069
+ this.on(def, r.targets, { ...r.params, __backward: true });
1070
+ else
1071
+ for (const t of r.targets)
1072
+ forceRevert(def, t, at(dur0));
1073
+ await this.done(r);
1074
+ };
1075
+ // a pass: start → end (or end → start when reversed); `first` is the direction of its first leg
1076
+ const first = reverse ? backward : forward;
1077
+ const second = reverse ? forward : backward;
1078
+ if (reverse) {
1079
+ await forward(true);
1080
+ if (token.cancelled)
1081
+ return;
1082
+ } // stand at the end
1083
+ for (;;) {
1084
+ // a pass never takes less than a frame (a zero duration must not spin)
1085
+ const frame = new Promise(res => setTimeout(res, 16));
1086
+ await first();
1087
+ await frame;
1088
+ if (token.cancelled)
1089
+ return;
1090
+ if (yoyo) {
1091
+ await second();
1092
+ if (token.cancelled)
1093
+ return;
1094
+ }
1095
+ if (!loop)
1096
+ break;
1097
+ if (!yoyo) {
1098
+ await second(true);
1099
+ if (token.cancelled)
1100
+ return;
1101
+ } // jump back to the pass's start
1102
+ }
1103
+ if (r.cycle === token)
1104
+ r.cycle = undefined;
1105
+ }
1106
+ /** Play an effect out and leave it waiting (it stays in the list, ready to play again). */
1107
+ stop(effectId) {
1108
+ const r = this.running.get(effectId);
1109
+ const def = r && getOperation(r.op);
1110
+ if (!r || !def || this.disposed || this.refreshing)
1111
+ return false;
1112
+ r.waitFor = undefined; // a play that was about to start is called off
1113
+ if (!r.started || r.stopping)
1114
+ return true;
1115
+ if (!def.revert) { // a one-shot: stop its move, back at once
1116
+ if (r.cycle) {
1117
+ r.cycle.cancelled = true;
1118
+ r.cycle.wake?.();
1119
+ r.cycle = undefined;
1120
+ }
1121
+ for (const t of r.targets)
1122
+ def.cancel?.(t);
1123
+ r.started = false;
1124
+ return true;
1125
+ }
1126
+ this.off(r, false);
1127
+ const done = this.done(r);
1128
+ r.stopping = done;
1129
+ void done.then(() => { if (r.stopping === done) {
1130
+ r.stopping = undefined;
1131
+ r.started = false;
1132
+ } });
1133
+ return true;
1134
+ }
1135
+ /** Play an effect from its start (see playObjectEffect). */
1136
+ play(effectId) {
1137
+ const r = this.running.get(effectId);
1138
+ const def = r && getOperation(r.op);
1139
+ if (!r || !def || this.disposed || this.refreshing)
1140
+ return false;
1141
+ r.stopping = undefined;
1142
+ const wasOn = r.started;
1143
+ this.off(r, true); // cancels a running cycle, clears at once
1144
+ const cleared = wasOn ? this.done(r) : Promise.resolve();
1145
+ r.started = false;
1146
+ r.waitFor = cleared;
1147
+ void cleared.then(() => {
1148
+ if (this.disposed || this.running.get(effectId) !== r || r.waitFor !== cleared)
1149
+ return;
1150
+ this.start(def, r, false, true);
1151
+ });
1152
+ return true;
96
1153
  }
97
1154
  /**
98
1155
  * The object's meshes or materials were replaced: take every effect off the
@@ -107,14 +1164,29 @@ export class ObjectEffectsController {
107
1164
  const done = Promise.all(list.flatMap(r => r.targets.map(t => runOf(r.op, t))));
108
1165
  this.refreshing = done.then(() => {
109
1166
  this.refreshing = null;
110
- this.sync(this.effects, 'instant');
1167
+ this.syncList(this.compose(), 'instant');
111
1168
  });
112
1169
  return this.refreshing;
113
1170
  }
114
1171
  /** Take everything off at once (the object is going away). */
1172
+ /** A group: children joined or left (the effects hook checks every few frames). */
1173
+ checkFanout() { this.fan?.check(); }
1174
+ /** Ids of a group's children in cascade order (tests / studio). */
1175
+ get fanChildren() { return this.fan?.childIds ?? []; }
115
1176
  dispose() {
1177
+ this.fan?.dispose();
1178
+ this.fan = null;
1179
+ for (const c of [this.own, ...this.clips.values()]) {
1180
+ clearTimeout(c.timer);
1181
+ c.run++;
1182
+ }
1183
+ this.clips.clear();
1184
+ this.added.clear();
1185
+ if (controllers.get(this.root) === this)
1186
+ controllers.delete(this.root);
116
1187
  this.running.forEach(r => this.off(r, true));
117
1188
  this.running.clear();
1189
+ this.leaving.clear();
118
1190
  this.disposed = true;
119
1191
  }
120
1192
  /** Ids of the effects running now (tests / studio). */
@@ -129,7 +1201,9 @@ export function surfaceSignature(root) {
129
1201
  root.traverse((c) => {
130
1202
  if (!c.isMesh || c.userData?.__opFxHelper)
131
1203
  return;
132
- const mats = Array.isArray(c.material) ? c.material : [c.material];
1204
+ // an effect that swaps in its own copies while it plays (shatter) leaves the real material here
1205
+ const own = c.userData?.__opFxOwnMaterial ?? c.material;
1206
+ const mats = Array.isArray(own) ? own : [own];
133
1207
  parts.push(c.uuid + ':' + mats.map((m) => m?.uuid ?? '').join(','));
134
1208
  });
135
1209
  return parts.join(';');