cyberia 3.2.5 → 3.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. package/.github/workflows/engine-cyberia.cd.yml +2 -2
  2. package/.github/workflows/release.cd.yml +1 -2
  3. package/CHANGELOG.md +351 -1
  4. package/CLI-HELP.md +40 -13
  5. package/Dockerfile +0 -4
  6. package/README.md +242 -497
  7. package/bin/build.js +19 -5
  8. package/bin/cyberia.js +1149 -240
  9. package/bin/deploy.js +570 -1
  10. package/bin/file.js +6 -0
  11. package/bin/index.js +1149 -240
  12. package/bin/vs.js +1 -1
  13. package/conf.js +67 -89
  14. package/deployment.yaml +4 -222
  15. package/hardhat/package-lock.json +32 -32
  16. package/hardhat/package.json +3 -3
  17. package/jsconfig.json +1 -1
  18. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +2 -2
  19. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +2 -2
  20. package/manifests/deployment/dd-cyberia-development/deployment.yaml +4 -222
  21. package/manifests/deployment/dd-cyberia-development/proxy.yaml +10 -118
  22. package/manifests/deployment/dd-default-development/deployment.yaml +2 -6
  23. package/manifests/deployment/dd-test-development/deployment.yaml +136 -66
  24. package/manifests/deployment/dd-test-development/proxy.yaml +41 -5
  25. package/package.json +23 -14
  26. package/proxy.yaml +10 -118
  27. package/scripts/k3s-node-setup.sh +2 -2
  28. package/scripts/nat-iptables.sh +103 -18
  29. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +18 -18
  30. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +7 -14
  31. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +76 -21
  32. package/src/api/core/core.controller.js +10 -10
  33. package/src/api/core/core.service.js +10 -10
  34. package/src/api/crypto/crypto.controller.js +8 -8
  35. package/src/api/crypto/crypto.service.js +8 -8
  36. package/src/api/cyberia-action/cyberia-action.controller.js +74 -0
  37. package/src/api/cyberia-action/cyberia-action.model.js +87 -0
  38. package/src/api/cyberia-action/cyberia-action.router.js +27 -0
  39. package/src/api/cyberia-action/cyberia-action.service.js +42 -0
  40. package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +13 -13
  41. package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +11 -11
  42. package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +2 -2
  43. package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +16 -16
  44. package/src/api/cyberia-entity/cyberia-entity.controller.js +10 -10
  45. package/src/api/cyberia-entity/cyberia-entity.service.js +10 -10
  46. package/src/api/cyberia-instance/cyberia-fallback-world.js +19 -209
  47. package/src/api/cyberia-instance/cyberia-instance.controller.js +14 -14
  48. package/src/api/cyberia-instance/cyberia-instance.model.js +3 -0
  49. package/src/api/cyberia-instance/cyberia-instance.service.js +22 -57
  50. package/src/api/cyberia-instance/cyberia-portal-connector.js +20 -246
  51. package/src/api/cyberia-instance/cyberia-world-generator.js +505 -0
  52. package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +10 -10
  53. package/src/api/cyberia-instance-conf/cyberia-instance-conf.defaults.js +216 -55
  54. package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +4 -1
  55. package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +18 -14
  56. package/src/api/cyberia-map/cyberia-map.controller.js +10 -10
  57. package/src/api/cyberia-map/cyberia-map.service.js +10 -10
  58. package/src/api/cyberia-quest/cyberia-quest.controller.js +74 -0
  59. package/src/api/cyberia-quest/cyberia-quest.model.js +67 -0
  60. package/src/api/cyberia-quest/cyberia-quest.router.js +27 -0
  61. package/src/api/cyberia-quest/cyberia-quest.service.js +42 -0
  62. package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +74 -0
  63. package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.js +49 -0
  64. package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +27 -0
  65. package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +42 -0
  66. package/src/api/default/default.controller.js +10 -10
  67. package/src/api/default/default.service.js +10 -10
  68. package/src/api/document/document.controller.js +12 -12
  69. package/src/api/document/document.model.js +10 -16
  70. package/src/api/file/file.controller.js +8 -8
  71. package/src/api/file/file.model.js +10 -10
  72. package/src/api/file/file.service.js +36 -36
  73. package/src/api/instance/instance.controller.js +10 -10
  74. package/src/api/instance/instance.model.js +4 -10
  75. package/src/api/instance/instance.service.js +10 -10
  76. package/src/api/ipfs/ipfs.controller.js +12 -12
  77. package/src/api/ipfs/ipfs.model.js +4 -13
  78. package/src/api/ipfs/ipfs.service.js +14 -28
  79. package/src/api/object-layer/object-layer.controller.js +12 -12
  80. package/src/api/object-layer/object-layer.model.js +4 -17
  81. package/src/api/object-layer/object-layer.service.js +12 -12
  82. package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +10 -10
  83. package/src/api/object-layer-render-frames/object-layer-render-frames.model.js +6 -16
  84. package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +18 -14
  85. package/src/api/test/test.controller.js +8 -8
  86. package/src/api/test/test.service.js +8 -8
  87. package/src/api/user/guest.service.js +99 -0
  88. package/src/api/user/user.controller.js +6 -6
  89. package/src/api/user/user.model.js +8 -13
  90. package/src/api/user/user.service.js +3 -20
  91. package/src/cli/cluster.js +61 -14
  92. package/src/cli/db.js +47 -2
  93. package/src/cli/deploy.js +67 -35
  94. package/src/cli/fs.js +79 -8
  95. package/src/cli/image.js +43 -1
  96. package/src/cli/index.js +26 -1
  97. package/src/cli/release.js +57 -1
  98. package/src/cli/repository.js +69 -31
  99. package/src/cli/run.js +415 -36
  100. package/src/cli/ssh.js +1 -1
  101. package/src/cli/static.js +43 -115
  102. package/src/client/Cryptokoyn.index.js +18 -21
  103. package/src/client/CyberiaPortal.index.js +19 -23
  104. package/src/client/Default.index.js +21 -33
  105. package/src/client/Itemledger.index.js +20 -26
  106. package/src/client/Underpost.index.js +19 -23
  107. package/src/client/components/core/404.js +4 -4
  108. package/src/client/components/core/500.js +4 -4
  109. package/src/client/components/core/Account.js +73 -60
  110. package/src/client/components/core/AgGrid.js +23 -33
  111. package/src/client/components/core/Alert.js +12 -13
  112. package/src/client/components/core/AppStore.js +1 -1
  113. package/src/client/components/core/Auth.js +35 -37
  114. package/src/client/components/core/Badge.js +7 -13
  115. package/src/client/components/core/BtnIcon.js +15 -17
  116. package/src/client/components/core/CalendarCore.js +42 -63
  117. package/src/client/components/core/Chat.js +13 -15
  118. package/src/client/components/core/ClientEvents.js +87 -0
  119. package/src/client/components/core/ColorPaletteElement.js +309 -0
  120. package/src/client/components/core/Content.js +17 -14
  121. package/src/client/components/core/Css.js +15 -71
  122. package/src/client/components/core/CssCore.js +12 -16
  123. package/src/client/components/core/D3Chart.js +4 -4
  124. package/src/client/components/core/Docs.js +64 -91
  125. package/src/client/components/core/DropDown.js +69 -91
  126. package/src/client/components/core/EventBus.js +92 -0
  127. package/src/client/components/core/EventsUI.js +14 -17
  128. package/src/client/components/core/FileExplorer.js +96 -228
  129. package/src/client/components/core/FullScreen.js +47 -75
  130. package/src/client/components/core/Input.js +24 -69
  131. package/src/client/components/core/Keyboard.js +25 -18
  132. package/src/client/components/core/KeyboardAvoidance.js +145 -0
  133. package/src/client/components/core/LoadingAnimation.js +25 -31
  134. package/src/client/components/core/LogIn.js +41 -41
  135. package/src/client/components/core/LogOut.js +23 -14
  136. package/src/client/components/core/Modal.js +462 -178
  137. package/src/client/components/core/NotificationManager.js +14 -18
  138. package/src/client/components/core/Panel.js +54 -50
  139. package/src/client/components/core/PanelForm.js +25 -125
  140. package/src/client/components/core/Polyhedron.js +110 -214
  141. package/src/client/components/core/PublicProfile.js +39 -32
  142. package/src/client/components/core/Recover.js +48 -44
  143. package/src/client/components/core/Responsive.js +88 -32
  144. package/src/client/components/core/RichText.js +9 -18
  145. package/src/client/components/core/Router.js +24 -3
  146. package/src/client/components/core/SearchBox.js +37 -37
  147. package/src/client/components/core/SignUp.js +39 -30
  148. package/src/client/components/core/SocketIo.js +31 -2
  149. package/src/client/components/core/SocketIoHandler.js +6 -6
  150. package/src/client/components/core/ToggleSwitch.js +8 -20
  151. package/src/client/components/core/ToolTip.js +5 -17
  152. package/src/client/components/core/Translate.js +56 -59
  153. package/src/client/components/core/Validator.js +26 -16
  154. package/src/client/components/core/Wallet.js +15 -26
  155. package/src/client/components/core/Worker.js +163 -27
  156. package/src/client/components/core/windowGetDimensions.js +7 -7
  157. package/src/client/components/cryptokoyn/{MenuCryptokoyn.js → AppShellCryptokoyn.js} +57 -57
  158. package/src/client/components/cryptokoyn/CssCryptokoyn.js +15 -15
  159. package/src/client/components/cryptokoyn/LogInCryptokoyn.js +6 -4
  160. package/src/client/components/cryptokoyn/LogOutCryptokoyn.js +6 -4
  161. package/src/client/components/cryptokoyn/RouterCryptokoyn.js +37 -0
  162. package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +4 -4
  163. package/src/client/components/cryptokoyn/SignUpCryptokoyn.js +6 -4
  164. package/src/client/components/cyberia/InstanceEngineCyberia.js +141 -60
  165. package/src/client/components/cyberia/MapEngineCyberia.js +691 -214
  166. package/src/client/components/cyberia/ObjectLayerEngine.js +19 -0
  167. package/src/client/components/cyberia/ObjectLayerEngineModal.js +1204 -94
  168. package/src/client/components/cyberia/ObjectLayerEngineViewer.js +196 -298
  169. package/src/client/components/cyberia-portal/{MenuCyberiaPortal.js → AppShellCyberiaPortal.js} +102 -102
  170. package/src/client/components/cyberia-portal/CommonCyberiaPortal.js +305 -61
  171. package/src/client/components/cyberia-portal/CssCyberiaPortal.js +15 -15
  172. package/src/client/components/cyberia-portal/LogInCyberiaPortal.js +6 -4
  173. package/src/client/components/cyberia-portal/LogOutCyberiaPortal.js +6 -4
  174. package/src/client/components/cyberia-portal/MainBodyCyberiaPortal.js +4 -4
  175. package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +60 -0
  176. package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +4 -4
  177. package/src/client/components/cyberia-portal/SignUpCyberiaPortal.js +6 -4
  178. package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +4 -4
  179. package/src/client/components/default/{MenuDefault.js → AppShellDefault.js} +87 -87
  180. package/src/client/components/default/CssDefault.js +12 -12
  181. package/src/client/components/default/LogInDefault.js +6 -4
  182. package/src/client/components/default/LogOutDefault.js +6 -4
  183. package/src/client/components/default/RouterDefault.js +47 -0
  184. package/src/client/components/default/SettingsDefault.js +4 -4
  185. package/src/client/components/default/SignUpDefault.js +6 -4
  186. package/src/client/components/default/TranslateDefault.js +3 -3
  187. package/src/client/components/itemledger/{MenuItemledger.js → AppShellItemledger.js} +57 -57
  188. package/src/client/components/itemledger/CssItemledger.js +15 -15
  189. package/src/client/components/itemledger/LogInItemledger.js +6 -4
  190. package/src/client/components/itemledger/LogOutItemledger.js +6 -4
  191. package/src/client/components/itemledger/RouterItemledger.js +38 -0
  192. package/src/client/components/itemledger/SettingsItemledger.js +4 -4
  193. package/src/client/components/itemledger/SignUpItemledger.js +6 -4
  194. package/src/client/components/itemledger/TranslateItemledger.js +3 -3
  195. package/src/client/components/underpost/{MenuUnderpost.js → AppShellUnderpost.js} +88 -88
  196. package/src/client/components/underpost/CssUnderpost.js +14 -14
  197. package/src/client/components/underpost/CyberpunkBloggerUnderpost.js +4 -4
  198. package/src/client/components/underpost/DocumentSearchProvider.js +1 -1
  199. package/src/client/components/underpost/LabGalleryUnderpost.js +12 -15
  200. package/src/client/components/underpost/LogInUnderpost.js +6 -4
  201. package/src/client/components/underpost/LogOutUnderpost.js +6 -4
  202. package/src/client/components/underpost/RouterUnderpost.js +45 -0
  203. package/src/client/components/underpost/SettingsUnderpost.js +4 -4
  204. package/src/client/components/underpost/SignUpUnderpost.js +6 -4
  205. package/src/client/components/underpost/TranslateUnderpost.js +4 -4
  206. package/src/client/public/cyberia-docs/ACTION-SYSTEM.md +235 -0
  207. package/src/client/public/cyberia-docs/ARCHITECTURE.md +443 -0
  208. package/src/client/public/cyberia-docs/CYBERIA-CLI.md +417 -0
  209. package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +313 -0
  210. package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +260 -0
  211. package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +241 -0
  212. package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +300 -0
  213. package/src/client/public/cyberia-docs/OFF-CHAIN-ECONOMY.md +279 -0
  214. package/src/client/public/cyberia-docs/QUEST-SYSTEM.md +206 -0
  215. package/src/client/public/cyberia-docs/ROADMAP.md +240 -0
  216. package/src/client/public/cyberia-docs/WHITE-PAPER.md +732 -0
  217. package/src/client/services/atlas-sprite-sheet/atlas-sprite-sheet.service.js +14 -20
  218. package/src/client/services/core/core.service.js +17 -49
  219. package/src/client/services/crypto/crypto.service.js +8 -13
  220. package/src/client/services/cyberia-action/cyberia-action.service.js +99 -0
  221. package/src/client/services/cyberia-dialogue/cyberia-dialogue.service.js +10 -16
  222. package/src/client/services/cyberia-entity/cyberia-entity.management.js +5 -5
  223. package/src/client/services/cyberia-entity/cyberia-entity.service.js +10 -16
  224. package/src/client/services/cyberia-instance/cyberia-instance.management.js +6 -6
  225. package/src/client/services/cyberia-instance/cyberia-instance.service.js +12 -18
  226. package/src/client/services/cyberia-instance-conf/cyberia-instance-conf.service.js +10 -16
  227. package/src/client/services/cyberia-map/cyberia-map.management.js +6 -6
  228. package/src/client/services/cyberia-map/cyberia-map.service.js +12 -18
  229. package/src/client/services/cyberia-quest/cyberia-quest.service.js +99 -0
  230. package/src/client/services/cyberia-quest-progress/cyberia-quest-progress.service.js +99 -0
  231. package/src/client/services/default/default.management.js +159 -267
  232. package/src/client/services/default/default.service.js +10 -16
  233. package/src/client/services/document/document.service.js +14 -19
  234. package/src/client/services/file/file.service.js +8 -13
  235. package/src/client/services/instance/instance.management.js +5 -5
  236. package/src/client/services/instance/instance.service.js +10 -15
  237. package/src/client/services/ipfs/ipfs.service.js +12 -18
  238. package/src/client/services/object-layer/object-layer.management.js +12 -12
  239. package/src/client/services/object-layer/object-layer.service.js +20 -26
  240. package/src/client/services/object-layer-render-frames/object-layer-render-frames.service.js +10 -16
  241. package/src/client/services/test/test.service.js +8 -13
  242. package/src/client/services/user/guest.service.js +86 -0
  243. package/src/client/services/user/user.management.js +5 -5
  244. package/src/client/services/user/user.service.js +14 -20
  245. package/src/client/ssr/body/404.js +3 -3
  246. package/src/client/ssr/body/500.js +3 -3
  247. package/src/client/ssr/body/CacheControl.js +5 -2
  248. package/src/client/ssr/body/DefaultSplashScreen.js +19 -12
  249. package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +13 -6
  250. package/src/client/ssr/head/PwaItemledger.js +197 -60
  251. package/src/client/ssr/mailer/DefaultRecoverEmail.js +19 -20
  252. package/src/client/ssr/mailer/DefaultVerifyEmail.js +15 -16
  253. package/src/client/ssr/offline/Maintenance.js +12 -11
  254. package/src/client/ssr/offline/NoNetworkConnection.js +3 -3
  255. package/src/client/ssr/pages/Test.js +2 -2
  256. package/src/client/sw/core.sw.js +212 -0
  257. package/src/grpc/cyberia/grpc-server.js +179 -67
  258. package/src/index.js +1 -1
  259. package/src/runtime/cyberia-client/Dockerfile +80 -0
  260. package/src/runtime/cyberia-server/Dockerfile +37 -0
  261. package/src/runtime/express/Dockerfile +4 -4
  262. package/src/runtime/lampp/Dockerfile +8 -7
  263. package/src/runtime/wp/Dockerfile +11 -17
  264. package/src/server/atlas-sprite-sheet-generator.js +4 -2
  265. package/src/server/client-build-docs.js +45 -46
  266. package/src/server/client-build.js +334 -60
  267. package/src/server/client-formatted.js +47 -16
  268. package/src/server/conf.js +5 -4
  269. package/src/server/data-query.js +32 -20
  270. package/src/server/dns.js +22 -0
  271. package/src/server/ipfs-client.js +232 -91
  272. package/src/server/object-layer.js +1 -6
  273. package/src/server/process.js +13 -27
  274. package/src/server/semantic-layer-generator-floor.js +11 -51
  275. package/src/server/semantic-layer-generator-resource.js +259 -0
  276. package/src/server/semantic-layer-generator-skin.js +41 -171
  277. package/src/server/semantic-layer-generator.js +122 -14
  278. package/src/server/shape-generator.js +108 -0
  279. package/src/server/start.js +17 -3
  280. package/src/server/valkey.js +141 -235
  281. package/tsconfig.docs.json +15 -0
  282. package/typedoc.dd-cyberia.json +29 -0
  283. package/typedoc.json +29 -0
  284. package/WHITE-PAPER.md +0 -1540
  285. package/hardhat/README.md +0 -531
  286. package/hardhat/WHITE-PAPER.md +0 -1540
  287. package/jsdoc.dd-cyberia.json +0 -68
  288. package/jsdoc.json +0 -68
  289. package/src/api/object-layer/README.md +0 -672
  290. package/src/client/components/core/ColorPalette.js +0 -5267
  291. package/src/client/components/core/JoyStick.js +0 -80
  292. package/src/client/components/cryptokoyn/RoutesCryptokoyn.js +0 -39
  293. package/src/client/components/cyberia-portal/RoutesCyberiaPortal.js +0 -62
  294. package/src/client/components/cyberia-portal/ServerCyberiaPortal.js +0 -136
  295. package/src/client/components/default/RoutesDefault.js +0 -49
  296. package/src/client/components/itemledger/RoutesItemledger.js +0 -40
  297. package/src/client/components/underpost/RoutesUnderpost.js +0 -47
  298. package/src/client/sw/default.sw.js +0 -127
  299. package/src/client/sw/template.sw.js +0 -84
  300. package/src/grpc/cyberia/OFF_CHAIN_ECONOMY.md +0 -305
  301. package/src/grpc/cyberia/README.md +0 -326
@@ -11,7 +11,6 @@ import { ObjectLayerService } from '../../services/object-layer/object-layer.ser
11
11
  import { AtlasSpriteSheetService } from '../../services/atlas-sprite-sheet/atlas-sprite-sheet.service.js';
12
12
  import { NotificationManager } from '../core/NotificationManager.js';
13
13
  import { append, htmls, s } from '../core/VanillaJs.js';
14
-
15
14
  import { darkTheme, ThemeEvents, subThemeManager, lightenHex, darkenHex } from '../core/Css.js';
16
15
  import { ObjectLayerManagement } from '../../services/object-layer/object-layer.management.js';
17
16
  import { ObjectLayerEngineModal } from './ObjectLayerEngineModal.js';
@@ -20,11 +19,9 @@ import { DefaultManagement } from '../../services/default/default.management.js'
20
19
  import { AgGrid } from '../core/AgGrid.js';
21
20
  import { EventsUI } from '../core/EventsUI.js';
22
21
  import { createJSONEditor } from 'vanilla-jsoneditor';
23
-
24
22
  const logger = loggerFactory(import.meta);
25
-
26
- const ObjectLayerEngineViewer = {
27
- Data: {
23
+ class ObjectLayerEngineViewer {
24
+ static Data = {
28
25
  objectLayer: null,
29
26
  frameCounts: null,
30
27
  currentDirection: 'down',
@@ -36,10 +33,9 @@ const ObjectLayerEngineViewer = {
36
33
  isGeneratingAtlas: false,
37
34
  webpMetadata: null,
38
35
  metadataJsonEditor: null,
39
- },
40
-
36
+ };
41
37
  // Map user-friendly direction/mode to numeric direction codes
42
- getDirectionCode: function (direction, mode) {
38
+ static getDirectionCode(direction, mode) {
43
39
  const key = `${direction}_${mode}`;
44
40
  const directionCodeMap = {
45
41
  down_idle: '08',
@@ -52,36 +48,29 @@ const ObjectLayerEngineViewer = {
52
48
  right_walking: '16',
53
49
  };
54
50
  return directionCodeMap[key] || null;
55
- },
56
-
57
- Render: async function ({ appStore }) {
51
+ }
52
+ static async instance({ appStore }) {
58
53
  const id = 'object-layer-engine-viewer';
59
-
60
54
  // Reset currentObjectId when modal is rendered to ensure Reload triggers properly
61
- this.Data.currentObjectId = undefined;
62
-
55
+ ObjectLayerEngineViewer.Data.currentObjectId = undefined;
63
56
  Modal.Data[`modal-${id}`].onReloadModalListener[id] = async () => {
64
57
  ObjectLayerEngineViewer.Reload({ appStore });
65
58
  };
66
-
67
59
  // Listen for query parameter changes for smooth navigation
68
60
  listenQueryParamsChange({
69
61
  id: `${id}-query-listener`,
70
62
  event: async (queryParams) => {
71
63
  const objectId = queryParams.id || null;
72
-
73
64
  if (!s(`.modal-${id}`) || !s(`#${id}`)) {
74
65
  logger.warn('ObjectLayerEngineViewer DOM not ready for query param change');
75
66
  return;
76
67
  }
77
-
78
68
  // Only reload if object id actually changed (normalize undefined to null for comparison)
79
- if (objectId !== this.Data.currentObjectId) {
80
- await this.Reload({ appStore });
69
+ if (objectId !== ObjectLayerEngineViewer.Data.currentObjectId) {
70
+ await ObjectLayerEngineViewer.Reload({ appStore });
81
71
  }
82
72
  },
83
73
  });
84
-
85
74
  return html`
86
75
  <div class="fl">
87
76
  <div class="in ${id}" id="${id}">
@@ -91,101 +80,83 @@ const ObjectLayerEngineViewer = {
91
80
  </div>
92
81
  </div>
93
82
  `;
94
- },
95
-
96
- renderEmpty: async function ({ appStore }) {
83
+ }
84
+ static async renderEmpty({ appStore }) {
97
85
  const id = 'object-layer-engine-viewer';
98
86
  const idModal = 'modal-object-layer-engine-viewer';
99
-
100
87
  // Check if DOM element exists
101
88
  if (!s(`#${id}`)) {
102
89
  logger.warn('ObjectLayerEngineViewer DOM not ready for renderEmpty');
103
90
  return;
104
91
  }
105
-
106
92
  // Clear current object id when rendering empty state
107
- this.Data.currentObjectId = null;
108
-
93
+ ObjectLayerEngineViewer.Data.currentObjectId = null;
109
94
  // Check if the management table grid already exists AND its DOM is still present
110
95
  // If it does, don't re-render (just let DefaultManagement's RouterEvents handle URL changes)
111
96
  const gridId = `object-layer-engine-management-grid-${idModal}`;
112
97
  const gridExists = AgGrid.grids[gridId];
113
98
  const gridDomExists = s(`.${gridId}`);
114
-
115
99
  if (gridExists && gridDomExists) {
116
100
  // Grid already exists with DOM intact, no need to destroy and recreate it
117
101
  // The DefaultManagement RouterEvents listener will handle pagination/filter updates
118
102
  return;
119
103
  }
120
-
121
104
  // Grid doesn't exist or its DOM was destroyed, render/re-render it
122
105
  if (gridExists && !gridDomExists) {
123
106
  // Clean up orphaned grid reference
124
107
  AgGrid.grids[gridId].destroy();
125
108
  delete AgGrid.grids[gridId];
126
109
  }
127
-
128
110
  htmls(
129
111
  `#${id}`,
130
- await ObjectLayerManagement.RenderTable({
112
+ await ObjectLayerManagement.instance({
131
113
  appStore,
132
114
  idModal,
133
115
  }),
134
116
  );
135
- },
136
-
137
- loadObjectLayer: async function (objectLayerId, appStore, options = {}) {
117
+ }
118
+ static async loadObjectLayer(objectLayerId, appStore, options = {}) {
138
119
  const { skipWebp = false } = options;
139
120
  const id = 'object-layer-engine-viewer';
140
-
141
121
  // Check if DOM element exists
142
122
  if (!s(`#${id}`)) {
143
123
  logger.warn('ObjectLayerEngineViewer DOM not ready for loadObjectLayer');
144
124
  return;
145
125
  }
146
-
147
126
  try {
148
127
  // Load metadata first
149
128
  const { status: metaStatus, data: metadata } = await ObjectLayerService.getMetadata({ id: objectLayerId });
150
-
151
129
  if (metaStatus !== 'success' || !metadata) {
152
130
  throw new Error('Failed to load object layer metadata');
153
131
  }
154
-
155
- this.Data.objectLayer = metadata;
156
-
132
+ ObjectLayerEngineViewer.Data.objectLayer = metadata;
157
133
  if (metadata.atlasSpriteSheetId) {
158
134
  const { status: atlasStatus, data: atlasData } = await AtlasSpriteSheetService.get({
159
135
  id: metadata.atlasSpriteSheetId,
160
136
  });
161
137
  if (atlasStatus === 'success') {
162
- this.Data.atlasSpriteSheet = atlasData;
138
+ ObjectLayerEngineViewer.Data.atlasSpriteSheet = atlasData;
163
139
  }
164
140
  } else {
165
- this.Data.atlasSpriteSheet = null;
141
+ ObjectLayerEngineViewer.Data.atlasSpriteSheet = null;
166
142
  }
167
-
168
143
  // Load frame counts for all directions
169
144
  const { status: frameStatus, data: frameData } = await ObjectLayerService.getFrameCounts({ id: objectLayerId });
170
-
171
145
  if (frameStatus !== 'success' || !frameData) {
172
146
  throw new Error('Failed to load frame counts');
173
147
  }
174
-
175
- this.Data.frameCounts = frameData.frameCounts;
148
+ ObjectLayerEngineViewer.Data.frameCounts = frameData.frameCounts;
176
149
  // Priority order for directions
177
150
  const directions = ['down', 'up', 'left', 'right'];
178
151
  // Priority order for modes
179
152
  const modes = ['idle', 'walking'];
180
- this.Data.currentDirection = 'down';
181
- this.Data.currentMode = 'idle';
182
-
183
- // Render the viewer UI
184
- await this.renderViewer({ appStore });
185
-
153
+ ObjectLayerEngineViewer.Data.currentDirection = 'down';
154
+ ObjectLayerEngineViewer.Data.currentMode = 'idle';
155
+ // instance the viewer UI
156
+ await ObjectLayerEngineViewer.renderViewer({ appStore });
186
157
  // Generate WebP
187
158
  if (!skipWebp) {
188
- await this.generateWebp();
159
+ await ObjectLayerEngineViewer.generateWebp();
189
160
  }
190
161
  } catch (error) {
191
162
  logger.error('Error loading object layer:', error);
@@ -193,7 +164,6 @@ const ObjectLayerEngineViewer = {
193
164
  html: `Failed to load object layer: ${error.message}`,
194
165
  status: 'error',
195
166
  });
196
-
197
167
  htmls(
198
168
  `#${id}`,
199
169
  html`
@@ -206,42 +176,34 @@ const ObjectLayerEngineViewer = {
206
176
  `,
207
177
  );
208
178
  }
209
- },
210
-
211
- renderViewer: async function ({ appStore }) {
179
+ }
180
+ static async renderViewer({ appStore }) {
212
181
  const id = 'object-layer-engine-viewer';
213
- const { objectLayer, frameCounts } = this.Data;
214
-
182
+ const { objectLayer, frameCounts } = ObjectLayerEngineViewer.Data;
215
183
  if (!objectLayer || !frameCounts) return;
216
-
217
184
  // Check if DOM element exists
218
185
  if (!s(`#${id}`)) {
219
186
  logger.warn('ObjectLayerEngineViewer DOM not ready for renderViewer');
220
187
  return;
221
188
  }
222
-
223
189
  const itemType = objectLayer.data.item.type;
224
190
  const itemId = objectLayer.data.item.id;
225
191
  const itemDescription = objectLayer.data.item.description || '';
226
192
  const itemActivable = objectLayer.data.item.activable || false;
227
-
228
193
  // Get ledger data
229
194
  const ledger = objectLayer.data.ledger || {};
230
195
  const ledgerType = ledger.type || '';
231
196
  const ledgerAddress = ledger.address || '';
232
-
233
197
  // Get stats data
234
198
  const stats = objectLayer.data.stats || {};
235
-
236
199
  // Helper function to check if direction/mode has frames
237
200
  const hasFrames = (direction, mode) => {
238
- const numericCode = this.getDirectionCode(direction, mode);
201
+ const numericCode = ObjectLayerEngineViewer.getDirectionCode(direction, mode);
239
202
  return numericCode && frameCounts[numericCode] && frameCounts[numericCode] > 0;
240
203
  };
241
-
242
204
  // Helper function to get frame count
243
205
  const getFrameCount = (direction, mode) => {
244
- const numericCode = this.getDirectionCode(direction, mode);
206
+ const numericCode = ObjectLayerEngineViewer.getDirectionCode(direction, mode);
245
207
  return numericCode ? frameCounts[numericCode] || 0 : 0;
246
208
  };
247
209
  ThemeEvents[id] = () => {
@@ -662,7 +624,7 @@ const ObjectLayerEngineViewer = {
662
624
  <div class="hide style-${id}"></div>
663
625
 
664
626
  <div class="object-layer-viewer-container">
665
- ${this.Data.isGeneratingAtlas
627
+ ${ObjectLayerEngineViewer.Data.isGeneratingAtlas
666
628
  ? html`
667
629
  <div
668
630
  style="display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 500px; gap: 20px; text-align: center;"
@@ -789,7 +751,7 @@ const ObjectLayerEngineViewer = {
789
751
  <span>WebP</span>
790
752
  </button>
791
753
  <div class="webp-canvas-container chess in" id="webp-canvas-container">
792
- ${!this.Data.webp
754
+ ${!ObjectLayerEngineViewer.Data.webp
793
755
  ? html`
794
756
  <div class="webp-placeholder">
795
757
  <i class="fa-solid fa-image"></i>
@@ -811,47 +773,55 @@ const ObjectLayerEngineViewer = {
811
773
  <h4><i class="fa-solid fa-compass"></i> Direction</h4>
812
774
  <div class="button-group">
813
775
  <button
814
- class="control-btn ${this.Data.currentDirection === 'up' ? 'active' : ''}"
776
+ class="control-btn ${ObjectLayerEngineViewer.Data.currentDirection === 'up' ? 'active' : ''}"
815
777
  data-direction="up"
816
- ${!hasFrames('up', this.Data.currentMode) ? 'disabled' : ''}
778
+ ${!hasFrames('up', ObjectLayerEngineViewer.Data.currentMode) ? 'disabled' : ''}
817
779
  >
818
780
  <i class="fa-solid fa-arrow-up"></i>
819
781
  <span>Up</span>
820
- ${hasFrames('up', this.Data.currentMode)
821
- ? html`<span class="frame-count">(${getFrameCount('up', this.Data.currentMode)})</span>`
782
+ ${hasFrames('up', ObjectLayerEngineViewer.Data.currentMode)
783
+ ? html`<span class="frame-count"
784
+ >(${getFrameCount('up', ObjectLayerEngineViewer.Data.currentMode)})</span
785
+ >`
822
786
  : ''}
823
787
  </button>
824
788
  <button
825
- class="control-btn ${this.Data.currentDirection === 'down' ? 'active' : ''}"
789
+ class="control-btn ${ObjectLayerEngineViewer.Data.currentDirection === 'down' ? 'active' : ''}"
826
790
  data-direction="down"
827
- ${!hasFrames('down', this.Data.currentMode) ? 'disabled' : ''}
791
+ ${!hasFrames('down', ObjectLayerEngineViewer.Data.currentMode) ? 'disabled' : ''}
828
792
  >
829
793
  <i class="fa-solid fa-arrow-down"></i>
830
794
  <span>Down</span>
831
- ${hasFrames('down', this.Data.currentMode)
832
- ? html`<span class="frame-count">(${getFrameCount('down', this.Data.currentMode)})</span>`
795
+ ${hasFrames('down', ObjectLayerEngineViewer.Data.currentMode)
796
+ ? html`<span class="frame-count"
797
+ >(${getFrameCount('down', ObjectLayerEngineViewer.Data.currentMode)})</span
798
+ >`
833
799
  : ''}
834
800
  </button>
835
801
  <button
836
- class="control-btn ${this.Data.currentDirection === 'left' ? 'active' : ''}"
802
+ class="control-btn ${ObjectLayerEngineViewer.Data.currentDirection === 'left' ? 'active' : ''}"
837
803
  data-direction="left"
838
- ${!hasFrames('left', this.Data.currentMode) ? 'disabled' : ''}
804
+ ${!hasFrames('left', ObjectLayerEngineViewer.Data.currentMode) ? 'disabled' : ''}
839
805
  >
840
806
  <i class="fa-solid fa-arrow-left"></i>
841
807
  <span>Left</span>
842
- ${hasFrames('left', this.Data.currentMode)
843
- ? html`<span class="frame-count">(${getFrameCount('left', this.Data.currentMode)})</span>`
808
+ ${hasFrames('left', ObjectLayerEngineViewer.Data.currentMode)
809
+ ? html`<span class="frame-count"
810
+ >(${getFrameCount('left', ObjectLayerEngineViewer.Data.currentMode)})</span
811
+ >`
844
812
  : ''}
845
813
  </button>
846
814
  <button
847
- class="control-btn ${this.Data.currentDirection === 'right' ? 'active' : ''}"
815
+ class="control-btn ${ObjectLayerEngineViewer.Data.currentDirection === 'right' ? 'active' : ''}"
848
816
  data-direction="right"
849
- ${!hasFrames('right', this.Data.currentMode) ? 'disabled' : ''}
817
+ ${!hasFrames('right', ObjectLayerEngineViewer.Data.currentMode) ? 'disabled' : ''}
850
818
  >
851
819
  <i class="fa-solid fa-arrow-right"></i>
852
820
  <span>Right</span>
853
- ${hasFrames('right', this.Data.currentMode)
854
- ? html`<span class="frame-count">(${getFrameCount('right', this.Data.currentMode)})</span>`
821
+ ${hasFrames('right', ObjectLayerEngineViewer.Data.currentMode)
822
+ ? html`<span class="frame-count"
823
+ >(${getFrameCount('right', ObjectLayerEngineViewer.Data.currentMode)})</span
824
+ >`
855
825
  : ''}
856
826
  </button>
857
827
  </div>
@@ -861,28 +831,28 @@ const ObjectLayerEngineViewer = {
861
831
  <h4><i class="fa-solid fa-person-running"></i> Mode</h4>
862
832
  <div class="button-group">
863
833
  <button
864
- class="control-btn ${this.Data.currentMode === 'idle' ? 'active' : ''}"
834
+ class="control-btn ${ObjectLayerEngineViewer.Data.currentMode === 'idle' ? 'active' : ''}"
865
835
  data-mode="idle"
866
- ${!hasFrames(this.Data.currentDirection, 'idle') ? 'disabled' : ''}
836
+ ${!hasFrames(ObjectLayerEngineViewer.Data.currentDirection, 'idle') ? 'disabled' : ''}
867
837
  >
868
838
  <i class="fa-solid fa-user"></i>
869
839
  <span>Idle</span>
870
- ${hasFrames(this.Data.currentDirection, 'idle')
840
+ ${hasFrames(ObjectLayerEngineViewer.Data.currentDirection, 'idle')
871
841
  ? html`<span class="frame-count"
872
- >(${getFrameCount(this.Data.currentDirection, 'idle')})</span
842
+ >(${getFrameCount(ObjectLayerEngineViewer.Data.currentDirection, 'idle')})</span
873
843
  >`
874
844
  : ''}
875
845
  </button>
876
846
  <button
877
- class="control-btn ${this.Data.currentMode === 'walking' ? 'active' : ''}"
847
+ class="control-btn ${ObjectLayerEngineViewer.Data.currentMode === 'walking' ? 'active' : ''}"
878
848
  data-mode="walking"
879
- ${!hasFrames(this.Data.currentDirection, 'walking') ? 'disabled' : ''}
849
+ ${!hasFrames(ObjectLayerEngineViewer.Data.currentDirection, 'walking') ? 'disabled' : ''}
880
850
  >
881
851
  <i class="fa-solid fa-person-walking"></i>
882
852
  <span>Walking</span>
883
- ${hasFrames(this.Data.currentDirection, 'walking')
853
+ ${hasFrames(ObjectLayerEngineViewer.Data.currentDirection, 'walking')
884
854
  ? html`<span class="frame-count"
885
- >(${getFrameCount(this.Data.currentDirection, 'walking')})</span
855
+ >(${getFrameCount(ObjectLayerEngineViewer.Data.currentDirection, 'walking')})</span
886
856
  >`
887
857
  : ''}
888
858
  </button>
@@ -892,16 +862,17 @@ const ObjectLayerEngineViewer = {
892
862
  <div class="control-group">
893
863
  <h4><i class="fa-solid fa-file-image"></i> Atlas Sprite Sheet</h4>
894
864
  <div class="button-group" style="flex-direction: column; align-items: flex-start;">
895
- ${this.Data.atlasSpriteSheet
865
+ ${ObjectLayerEngineViewer.Data.atlasSpriteSheet
896
866
  ? html`
897
867
  <div class="atlas-preview-container">
898
868
  ${
899
- this.Data.atlasSpriteSheet.fileId
869
+ ObjectLayerEngineViewer.Data.atlasSpriteSheet.fileId
900
870
  ? html`
901
871
  <div class="atlas-img-wrapper">
902
872
  <img
903
- src="${getProxyPath()}api/file/blob/${this.Data.atlasSpriteSheet.fileId._id ||
904
- this.Data.atlasSpriteSheet.fileId}"
873
+ src="${getProxyPath()}api/file/blob/${ObjectLayerEngineViewer.Data
874
+ .atlasSpriteSheet.fileId._id ||
875
+ ObjectLayerEngineViewer.Data.atlasSpriteSheet.fileId}"
905
876
  class="in atlas-img-preview"
906
877
  />
907
878
  </div>
@@ -915,14 +886,14 @@ const ObjectLayerEngineViewer = {
915
886
  <div class="atlas-metadata-grid">
916
887
  <div>
917
888
  <p style="padding: 2px"><strong class="item-data-key-label">ID:</strong></p>
918
- <p style="padding: 2px" font-size: 12px;">${this.Data.atlasSpriteSheet._id}</p>
889
+ <p style="padding: 2px" font-size: 12px;">${ObjectLayerEngineViewer.Data.atlasSpriteSheet._id}</p>
919
890
  </div>
920
891
  ${
921
- this.Data.atlasSpriteSheet.cid
892
+ ObjectLayerEngineViewer.Data.atlasSpriteSheet.cid
922
893
  ? html`<div style="grid-column: 1 / -1;">
923
894
  <p style="padding: 2px"><strong class="item-data-key-label">IPFS CID:</strong></p>
924
895
  <p class="ipfs-cid-value" style="padding: 2px;">
925
- ${this.Data.atlasSpriteSheet.cid}
896
+ ${ObjectLayerEngineViewer.Data.atlasSpriteSheet.cid}
926
897
  </p>
927
898
  </div>`
928
899
  : ''
@@ -930,18 +901,16 @@ const ObjectLayerEngineViewer = {
930
901
  <div>
931
902
  <p style="padding: 2px"><strong class="item-data-key-label">Dimensions:</strong></p>
932
903
  <p style="padding: 2px">
933
- ${this.Data.atlasSpriteSheet.metadata.atlasWidth}x${
934
- this.Data.atlasSpriteSheet.metadata.atlasHeight
935
- }
904
+ ${ObjectLayerEngineViewer.Data.atlasSpriteSheet.metadata.atlasWidth}x${ObjectLayerEngineViewer.Data.atlasSpriteSheet.metadata.atlasHeight}
936
905
  </p>
937
906
  </div>
938
907
  <div>
939
908
  <p style="padding: 2px"><strong class="item-data-key-label">Cell Dim:</strong></p>
940
- <p style="padding: 2px">${this.Data.atlasSpriteSheet.metadata.cellPixelDim}px</p>
909
+ <p style="padding: 2px">${ObjectLayerEngineViewer.Data.atlasSpriteSheet.metadata.cellPixelDim}px</p>
941
910
  </div>
942
911
  <div>
943
912
  <p style="padding: 2px"><strong class="item-data-key-label">Item Key:</strong></p>
944
- <p style="padding: 2px">${this.Data.atlasSpriteSheet.metadata.itemKey}</p>
913
+ <p style="padding: 2px">${ObjectLayerEngineViewer.Data.atlasSpriteSheet.metadata.itemKey}</p>
945
914
  </div>
946
915
  </div>
947
916
  </div>
@@ -994,31 +963,24 @@ const ObjectLayerEngineViewer = {
994
963
  );
995
964
  ThemeEvents[id]();
996
965
  // Attach event listeners
997
- this.attachEventListeners({ appStore });
998
-
966
+ ObjectLayerEngineViewer.attachEventListeners({ appStore });
999
967
  // If we already have a webp loaded, display it without re-generating
1000
- if (this.Data.webp) {
1001
- this.displayWebp();
968
+ if (ObjectLayerEngineViewer.Data.webp) {
969
+ ObjectLayerEngineViewer.displayWebp();
1002
970
  }
1003
-
1004
971
  // Initialize metadata JSON editor
1005
- this.initMetadataJsonEditor();
1006
- },
1007
-
1008
- displayWebp: async function () {
1009
- const { webp, webpMetadata } = this.Data;
972
+ ObjectLayerEngineViewer.initMetadataJsonEditor();
973
+ }
974
+ static async displayWebp() {
975
+ const { webp, webpMetadata } = ObjectLayerEngineViewer.Data;
1010
976
  if (!webp || !webpMetadata) return;
1011
-
1012
977
  const { frameCount, frameDuration, currentDirection, currentMode, numericCode } = webpMetadata;
1013
-
1014
978
  const container = s('#webp-canvas-container');
1015
979
  if (!container) return;
1016
-
1017
980
  // Remove one-time placeholder without destroying the rest of the container
1018
981
  // (clearing innerHTML would also destroy #webp-loading-overlay, breaking showLoading)
1019
982
  const placeholder = container.querySelector('.webp-placeholder');
1020
983
  if (placeholder) placeholder.remove();
1021
-
1022
984
  // Reuse the existing <img> element or create one — never nuke the container
1023
985
  let img = container.querySelector('img');
1024
986
  if (!img) {
@@ -1029,7 +991,6 @@ const ObjectLayerEngineViewer = {
1029
991
  container.insertBefore(img, overlay || null);
1030
992
  }
1031
993
  img.src = webp;
1032
-
1033
994
  // Update info badge in-place or create it once
1034
995
  const displayArea = s('.webp-display-area');
1035
996
  if (displayArea) {
@@ -1052,12 +1013,10 @@ const ObjectLayerEngineViewer = {
1052
1013
  <span>${numericCode}</span>
1053
1014
  `;
1054
1015
  }
1055
- },
1056
-
1057
- initMetadataJsonEditor: async function () {
1016
+ }
1017
+ static async initMetadataJsonEditor() {
1058
1018
  const container = s('#metadata-json-editor-container');
1059
1019
  if (!container) return;
1060
-
1061
1020
  // Ensure vanilla-jsoneditor dark theme CSS is loaded
1062
1021
  if (!s('.jse-dark-theme-link')) {
1063
1022
  append(
@@ -1070,21 +1029,17 @@ const ObjectLayerEngineViewer = {
1070
1029
  />`,
1071
1030
  );
1072
1031
  }
1073
-
1074
1032
  // Destroy previous instance if any
1075
- if (this.Data.metadataJsonEditor) {
1076
- this.Data.metadataJsonEditor.destroy();
1077
- this.Data.metadataJsonEditor = null;
1033
+ if (ObjectLayerEngineViewer.Data.metadataJsonEditor) {
1034
+ ObjectLayerEngineViewer.Data.metadataJsonEditor.destroy();
1035
+ ObjectLayerEngineViewer.Data.metadataJsonEditor = null;
1078
1036
  }
1079
-
1080
- const objectLayerId = this.Data.objectLayer?._id;
1037
+ const objectLayerId = ObjectLayerEngineViewer.Data.objectLayer?._id;
1081
1038
  if (!objectLayerId) return;
1082
-
1083
1039
  try {
1084
1040
  const response = await ObjectLayerService.getMetadata({ id: objectLayerId });
1085
1041
  const metadataContent = response.status === 'success' && response.data ? response.data : response;
1086
-
1087
- this.Data.metadataJsonEditor = createJSONEditor({
1042
+ ObjectLayerEngineViewer.Data.metadataJsonEditor = createJSONEditor({
1088
1043
  target: container,
1089
1044
  props: {
1090
1045
  content: { json: metadataContent },
@@ -1095,13 +1050,11 @@ const ObjectLayerEngineViewer = {
1095
1050
  mode: 'tree',
1096
1051
  },
1097
1052
  });
1098
-
1099
1053
  // Apply dark theme class based on current theme
1100
- this._applyJsonEditorTheme();
1101
-
1054
+ ObjectLayerEngineViewer._applyJsonEditorTheme();
1102
1055
  // Register theme event to toggle dark/light on the JSON editor
1103
1056
  ThemeEvents['metadata-json-editor-theme'] = () => {
1104
- this._applyJsonEditorTheme();
1057
+ ObjectLayerEngineViewer._applyJsonEditorTheme();
1105
1058
  };
1106
1059
  } catch (err) {
1107
1060
  logger.warn('Failed to initialize metadata JSON editor:', err);
@@ -1109,9 +1062,8 @@ const ObjectLayerEngineViewer = {
1109
1062
  Failed to load metadata JSON
1110
1063
  </div>`;
1111
1064
  }
1112
- },
1113
-
1114
- _applyJsonEditorTheme: function () {
1065
+ }
1066
+ static _applyJsonEditorTheme() {
1115
1067
  const container = s('#metadata-json-editor-container');
1116
1068
  if (!container) return;
1117
1069
  if (darkTheme) {
@@ -1119,14 +1071,11 @@ const ObjectLayerEngineViewer = {
1119
1071
  } else {
1120
1072
  container.classList.remove('jse-theme-dark');
1121
1073
  }
1122
- },
1123
-
1124
- deleteObjectLayer: async function ({ appStore } = {}) {
1125
- const objectLayerId = this.Data.objectLayer?._id;
1074
+ }
1075
+ static async deleteObjectLayer({ appStore } = {}) {
1076
+ const objectLayerId = ObjectLayerEngineViewer.Data.objectLayer?._id;
1126
1077
  if (!objectLayerId) return;
1127
-
1128
- const itemId = this.Data.objectLayer?.data?.item?.id || objectLayerId;
1129
-
1078
+ const itemId = ObjectLayerEngineViewer.Data.objectLayer?.data?.item?.id || objectLayerId;
1130
1079
  const confirmResult = await Modal.RenderConfirm({
1131
1080
  id: 'delete-object-layer-confirm',
1132
1081
  html: async () => html`
@@ -1139,9 +1088,7 @@ const ObjectLayerEngineViewer = {
1139
1088
  </div>
1140
1089
  `,
1141
1090
  });
1142
-
1143
1091
  if (confirmResult.status !== 'confirm') return;
1144
-
1145
1092
  try {
1146
1093
  const result = await ObjectLayerService.delete({ id: objectLayerId });
1147
1094
  if (result.status === 'success') {
@@ -1149,20 +1096,18 @@ const ObjectLayerEngineViewer = {
1149
1096
  html: `Object layer "${itemId}" deleted successfully`,
1150
1097
  status: 'success',
1151
1098
  });
1152
-
1153
1099
  // Clean up JSON editor and its theme event
1154
- if (this.Data.metadataJsonEditor) {
1155
- this.Data.metadataJsonEditor.destroy();
1156
- this.Data.metadataJsonEditor = null;
1100
+ if (ObjectLayerEngineViewer.Data.metadataJsonEditor) {
1101
+ ObjectLayerEngineViewer.Data.metadataJsonEditor.destroy();
1102
+ ObjectLayerEngineViewer.Data.metadataJsonEditor = null;
1157
1103
  }
1158
1104
  delete ThemeEvents['metadata-json-editor-theme'];
1159
-
1160
1105
  // Navigate back to list
1161
- this.Data.currentObjectId = undefined;
1162
- this.Data.objectLayer = null;
1163
- this.Data.webp = null;
1164
- this.Data.webpMetadata = null;
1165
- this.Data.atlasSpriteSheet = null;
1106
+ ObjectLayerEngineViewer.Data.currentObjectId = undefined;
1107
+ ObjectLayerEngineViewer.Data.objectLayer = null;
1108
+ ObjectLayerEngineViewer.Data.webp = null;
1109
+ ObjectLayerEngineViewer.Data.webpMetadata = null;
1110
+ ObjectLayerEngineViewer.Data.atlasSpriteSheet = null;
1166
1111
  setQueryParams({ id: null }, { replace: false });
1167
1112
  } else {
1168
1113
  throw new Error(result.message || 'Failed to delete object layer');
@@ -1174,109 +1119,100 @@ const ObjectLayerEngineViewer = {
1174
1119
  status: 'error',
1175
1120
  });
1176
1121
  }
1177
- },
1178
-
1179
- attachEventListeners: function ({ appStore }) {
1122
+ }
1123
+ static attachEventListeners({ appStore }) {
1180
1124
  // Direction buttons
1181
1125
  const directionButtons = document.querySelectorAll('[data-direction]');
1182
1126
  directionButtons.forEach((btn) => {
1183
1127
  btn.addEventListener('click', async (e) => {
1184
1128
  if (e.currentTarget.disabled) return;
1185
1129
  const direction = e.currentTarget.getAttribute('data-direction');
1186
- if (direction !== this.Data.currentDirection) {
1187
- this.Data.currentDirection = direction;
1130
+ if (direction !== ObjectLayerEngineViewer.Data.currentDirection) {
1131
+ ObjectLayerEngineViewer.Data.currentDirection = direction;
1188
1132
  // Update button active states without re-rendering the full viewer (prevents flicker)
1189
- this._updateControlsState();
1190
- await this.generateWebp();
1133
+ ObjectLayerEngineViewer._updateControlsState();
1134
+ await ObjectLayerEngineViewer.generateWebp();
1191
1135
  }
1192
1136
  });
1193
1137
  });
1194
-
1195
1138
  // Mode buttons
1196
1139
  const modeButtons = document.querySelectorAll('[data-mode]');
1197
1140
  modeButtons.forEach((btn) => {
1198
1141
  btn.addEventListener('click', async (e) => {
1199
1142
  if (e.currentTarget.disabled) return;
1200
1143
  const mode = e.currentTarget.getAttribute('data-mode');
1201
- if (mode !== this.Data.currentMode) {
1202
- this.Data.currentMode = mode;
1144
+ if (mode !== ObjectLayerEngineViewer.Data.currentMode) {
1145
+ ObjectLayerEngineViewer.Data.currentMode = mode;
1203
1146
  // Update button active states without re-rendering the full viewer (prevents flicker)
1204
- this._updateControlsState();
1205
- await this.generateWebp();
1147
+ ObjectLayerEngineViewer._updateControlsState();
1148
+ await ObjectLayerEngineViewer.generateWebp();
1206
1149
  }
1207
1150
  });
1208
1151
  });
1209
-
1210
1152
  // Download button
1211
1153
  const downloadBtn = s('#download-webp-btn');
1212
1154
  if (downloadBtn) {
1213
1155
  downloadBtn.addEventListener('click', () => {
1214
- this.downloadWebp();
1156
+ ObjectLayerEngineViewer.downloadWebp();
1215
1157
  });
1216
1158
  }
1217
-
1218
1159
  // Return to list button
1219
1160
  const listBtn = s('#return-to-list-btn');
1220
1161
  if (listBtn) {
1221
1162
  listBtn.addEventListener('click', async () => {
1222
1163
  // Clear object data and reset state
1223
- this.Data.webp = null;
1224
- this.Data.webpMetadata = null;
1225
- this.Data.objectLayer = null;
1226
- this.Data.frameCounts = null;
1227
-
1164
+ ObjectLayerEngineViewer.Data.webp = null;
1165
+ ObjectLayerEngineViewer.Data.webpMetadata = null;
1166
+ ObjectLayerEngineViewer.Data.objectLayer = null;
1167
+ ObjectLayerEngineViewer.Data.frameCounts = null;
1228
1168
  // Set currentObjectId to null BEFORE setQueryParams so the
1229
1169
  // listenQueryParamsChange listener sees the id already matches
1230
1170
  // and skips calling Reload (avoids double-render race condition)
1231
- this.Data.currentObjectId = null;
1232
-
1171
+ ObjectLayerEngineViewer.Data.currentObjectId = null;
1233
1172
  // Update the URL to remove the id parameter
1234
1173
  setQueryParams({ id: null }, { replace: false });
1235
-
1236
1174
  // Directly render the list view instead of relying on the
1237
1175
  // listener → Reload → renderEmpty chain which can silently
1238
1176
  // fail when the URL was already clean or currentObjectId
1239
1177
  // was already null
1240
- await this.renderEmpty({ appStore });
1178
+ await ObjectLayerEngineViewer.renderEmpty({ appStore });
1241
1179
  });
1242
1180
  }
1243
-
1244
1181
  // Edit button
1245
1182
  const editBtn = s('#edit-object-layer-btn');
1246
1183
  if (editBtn) {
1247
1184
  editBtn.addEventListener('click', () => {
1248
- this.toEngine();
1185
+ ObjectLayerEngineViewer.toEngine();
1249
1186
  });
1250
1187
  }
1251
-
1252
1188
  // Delete button
1253
1189
  const deleteBtn = s('#delete-object-layer-btn');
1254
1190
  if (deleteBtn) {
1255
1191
  deleteBtn.addEventListener('click', async () => {
1256
- await this.deleteObjectLayer({ appStore });
1192
+ await ObjectLayerEngineViewer.deleteObjectLayer({ appStore });
1257
1193
  });
1258
1194
  }
1259
-
1260
1195
  // Atlas buttons
1261
1196
  if (s('#generate-atlas-btn')) {
1262
1197
  EventsUI.onClick('#generate-atlas-btn', async () => {
1263
- await this.generateAtlas({ appStore });
1198
+ await ObjectLayerEngineViewer.generateAtlas({ appStore });
1264
1199
  });
1265
1200
  }
1266
-
1267
1201
  const removeAtlasBtn = s('#remove-atlas-btn');
1268
1202
  if (removeAtlasBtn) {
1269
1203
  removeAtlasBtn.addEventListener('click', async () => {
1270
- await this.removeAtlas({ appStore });
1204
+ await ObjectLayerEngineViewer.removeAtlas({ appStore });
1271
1205
  });
1272
1206
  }
1273
-
1274
1207
  const downloadAtlasPngBtn = s('#download-atlas-png-btn');
1275
1208
  if (downloadAtlasPngBtn) {
1276
1209
  downloadAtlasPngBtn.addEventListener('click', () => {
1277
1210
  const fileId =
1278
- this.Data && this.Data.atlasSpriteSheet && this.Data.atlasSpriteSheet.fileId
1279
- ? this.Data.atlasSpriteSheet.fileId._id || this.Data.atlasSpriteSheet.fileId
1211
+ ObjectLayerEngineViewer.Data &&
1212
+ ObjectLayerEngineViewer.Data.atlasSpriteSheet &&
1213
+ ObjectLayerEngineViewer.Data.atlasSpriteSheet.fileId
1214
+ ? ObjectLayerEngineViewer.Data.atlasSpriteSheet.fileId._id ||
1215
+ ObjectLayerEngineViewer.Data.atlasSpriteSheet.fileId
1280
1216
  : null;
1281
1217
  if (!fileId) {
1282
1218
  NotificationManager.Push({
@@ -1288,47 +1224,43 @@ const ObjectLayerEngineViewer = {
1288
1224
  const url = `${getProxyPath()}api/file/blob/${fileId}`;
1289
1225
  const a = document.createElement('a');
1290
1226
  a.href = url;
1291
- a.download = `${this.Data.atlasSpriteSheet.metadata.itemKey}-atlas.png`;
1227
+ a.download = `${ObjectLayerEngineViewer.Data.atlasSpriteSheet.metadata.itemKey}-atlas.png`;
1292
1228
  document.body.appendChild(a);
1293
1229
  a.click();
1294
1230
  document.body.removeChild(a);
1295
1231
  });
1296
1232
  }
1297
-
1298
1233
  const downloadAtlasJsonBtn = s('#download-atlas-json-btn');
1299
1234
  if (downloadAtlasJsonBtn) {
1300
1235
  downloadAtlasJsonBtn.addEventListener('click', () => {
1301
- const blob = new Blob([JSON.stringify(this.Data.atlasSpriteSheet.metadata, null, 2)], {
1236
+ const blob = new Blob([JSON.stringify(ObjectLayerEngineViewer.Data.atlasSpriteSheet.metadata, null, 2)], {
1302
1237
  type: 'application/json',
1303
1238
  });
1304
1239
  const url = URL.createObjectURL(blob);
1305
1240
  const a = document.createElement('a');
1306
1241
  a.href = url;
1307
- a.download = `${this.Data.atlasSpriteSheet.metadata.itemKey}-atlas-metadata.json`;
1242
+ a.download = `${ObjectLayerEngineViewer.Data.atlasSpriteSheet.metadata.itemKey}-atlas-metadata.json`;
1308
1243
  document.body.appendChild(a);
1309
1244
  a.click();
1310
1245
  document.body.removeChild(a);
1311
1246
  URL.revokeObjectURL(url);
1312
1247
  });
1313
1248
  }
1314
- },
1315
-
1316
- generateAtlas: async function ({ appStore } = {}) {
1317
- const objectLayerId = this.Data.objectLayer._id;
1318
- this.Data.isGeneratingAtlas = true;
1319
- await this.renderViewer({ appStore });
1320
-
1249
+ }
1250
+ static async generateAtlas({ appStore } = {}) {
1251
+ const objectLayerId = ObjectLayerEngineViewer.Data.objectLayer._id;
1252
+ ObjectLayerEngineViewer.Data.isGeneratingAtlas = true;
1253
+ await ObjectLayerEngineViewer.renderViewer({ appStore });
1321
1254
  try {
1322
1255
  const { status, data, message } = await AtlasSpriteSheetService.generateAtlas({ id: objectLayerId });
1323
-
1324
1256
  if (status === 'success') {
1325
1257
  NotificationManager.Push({
1326
1258
  html: 'Atlas sprite sheet generated successfully',
1327
1259
  status: 'success',
1328
1260
  });
1329
1261
  // Reset generating flag before reload so renderViewer shows updated content
1330
- this.Data.isGeneratingAtlas = false;
1331
- await this.Reload({ appStore, force: true, skipWebp: true });
1262
+ ObjectLayerEngineViewer.Data.isGeneratingAtlas = false;
1263
+ await ObjectLayerEngineViewer.Reload({ appStore, force: true, skipWebp: true });
1332
1264
  return;
1333
1265
  } else {
1334
1266
  throw new Error(message || 'Failed to generate atlas');
@@ -1340,14 +1272,13 @@ const ObjectLayerEngineViewer = {
1340
1272
  status: 'error',
1341
1273
  });
1342
1274
  } finally {
1343
- if (this.Data.isGeneratingAtlas) {
1344
- this.Data.isGeneratingAtlas = false;
1345
- await this.renderViewer({ appStore });
1275
+ if (ObjectLayerEngineViewer.Data.isGeneratingAtlas) {
1276
+ ObjectLayerEngineViewer.Data.isGeneratingAtlas = false;
1277
+ await ObjectLayerEngineViewer.renderViewer({ appStore });
1346
1278
  }
1347
1279
  }
1348
- },
1349
-
1350
- removeAtlas: async function ({ appStore } = {}) {
1280
+ }
1281
+ static async removeAtlas({ appStore } = {}) {
1351
1282
  const confirmResult = await Modal.RenderConfirm({
1352
1283
  id: 'remove-atlas-confirm',
1353
1284
  html: async () => html`
@@ -1356,26 +1287,22 @@ const ObjectLayerEngineViewer = {
1356
1287
  </div>
1357
1288
  `,
1358
1289
  });
1359
-
1360
1290
  if (confirmResult.status !== 'confirm') {
1361
1291
  return;
1362
1292
  }
1363
-
1364
- const objectLayerId = this.Data.objectLayer._id;
1365
- this.Data.isGeneratingAtlas = true;
1366
- await this.renderViewer({ appStore });
1367
-
1293
+ const objectLayerId = ObjectLayerEngineViewer.Data.objectLayer._id;
1294
+ ObjectLayerEngineViewer.Data.isGeneratingAtlas = true;
1295
+ await ObjectLayerEngineViewer.renderViewer({ appStore });
1368
1296
  try {
1369
1297
  const { status, message } = await AtlasSpriteSheetService.deleteByObjectLayerId({ id: objectLayerId });
1370
-
1371
1298
  if (status === 'success') {
1372
1299
  NotificationManager.Push({
1373
1300
  html: 'Atlas sprite sheet removed successfully',
1374
1301
  status: 'success',
1375
1302
  });
1376
1303
  // Reset generating flag before reload so renderViewer shows updated content
1377
- this.Data.isGeneratingAtlas = false;
1378
- await this.Reload({ appStore, force: true, skipWebp: true });
1304
+ ObjectLayerEngineViewer.Data.isGeneratingAtlas = false;
1305
+ await ObjectLayerEngineViewer.Reload({ appStore, force: true, skipWebp: true });
1379
1306
  return;
1380
1307
  } else {
1381
1308
  throw new Error(message || 'Failed to remove atlas');
@@ -1387,21 +1314,18 @@ const ObjectLayerEngineViewer = {
1387
1314
  status: 'error',
1388
1315
  });
1389
1316
  } finally {
1390
- if (this.Data.isGeneratingAtlas) {
1391
- this.Data.isGeneratingAtlas = false;
1392
- await this.renderViewer({ appStore });
1317
+ if (ObjectLayerEngineViewer.Data.isGeneratingAtlas) {
1318
+ ObjectLayerEngineViewer.Data.isGeneratingAtlas = false;
1319
+ await ObjectLayerEngineViewer.renderViewer({ appStore });
1393
1320
  }
1394
1321
  }
1395
- },
1396
-
1397
- generateWebp: async function () {
1398
- if (this.Data.isGenerating) return;
1399
-
1400
- const { objectLayer, frameCounts, currentDirection, currentMode } = this.Data;
1322
+ }
1323
+ static async generateWebp() {
1324
+ if (ObjectLayerEngineViewer.Data.isGenerating) return;
1325
+ const { objectLayer, frameCounts, currentDirection, currentMode } = ObjectLayerEngineViewer.Data;
1401
1326
  if (!objectLayer || !frameCounts) return;
1402
-
1403
1327
  // Get numeric direction code
1404
- const numericCode = this.getDirectionCode(currentDirection, currentMode);
1328
+ const numericCode = ObjectLayerEngineViewer.getDirectionCode(currentDirection, currentMode);
1405
1329
  if (!numericCode) {
1406
1330
  NotificationManager.Push({
1407
1331
  html: `Invalid direction/mode combination: ${currentDirection} ${currentMode}`,
@@ -1409,9 +1333,7 @@ const ObjectLayerEngineViewer = {
1409
1333
  });
1410
1334
  return;
1411
1335
  }
1412
-
1413
1336
  const frameCount = frameCounts[numericCode];
1414
-
1415
1337
  if (!frameCount || frameCount === 0) {
1416
1338
  NotificationManager.Push({
1417
1339
  html: `No frames available for ${currentDirection} ${currentMode}`,
@@ -1419,13 +1341,11 @@ const ObjectLayerEngineViewer = {
1419
1341
  });
1420
1342
  return;
1421
1343
  }
1422
-
1423
1344
  const itemType = objectLayer.data.item.type;
1424
1345
  const itemId = objectLayer.data.item.id;
1425
1346
  const frameDuration = objectLayer.objectLayerRenderFramesId?.frame_duration || 100;
1426
-
1427
- this.Data.isGenerating = true;
1428
- this.showLoading(true, 'Generating WebP...');
1347
+ ObjectLayerEngineViewer.Data.isGenerating = true;
1348
+ ObjectLayerEngineViewer.showLoading(true, 'Generating WebP...');
1429
1349
  try {
1430
1350
  // Call the WebP generation API endpoint
1431
1351
  const { status, data } = await ObjectLayerService.generateWebp({
@@ -1433,21 +1353,18 @@ const ObjectLayerEngineViewer = {
1433
1353
  itemId,
1434
1354
  directionCode: numericCode,
1435
1355
  });
1436
-
1437
1356
  if (status === 'success' && data) {
1438
1357
  // Store the blob URL and metadata
1439
- this.Data.webp = data;
1440
- this.Data.webpMetadata = {
1358
+ ObjectLayerEngineViewer.Data.webp = data;
1359
+ ObjectLayerEngineViewer.Data.webpMetadata = {
1441
1360
  frameCount,
1442
1361
  frameDuration,
1443
1362
  currentDirection,
1444
1363
  currentMode,
1445
1364
  numericCode,
1446
1365
  };
1447
-
1448
1366
  // Display the WebP in the viewer
1449
- await this.displayWebp();
1450
-
1367
+ await ObjectLayerEngineViewer.displayWebp();
1451
1368
  // NotificationManager.Push({
1452
1369
  // html: `WebP generated successfully (${frameCount} frames, ${frameDuration}ms duration)`,
1453
1370
  // status: 'success',
@@ -1455,36 +1372,33 @@ const ObjectLayerEngineViewer = {
1455
1372
  } else {
1456
1373
  throw new Error('Failed to generate WebP');
1457
1374
  }
1458
-
1459
- this.Data.isGenerating = false;
1460
- this.showLoading(false);
1375
+ ObjectLayerEngineViewer.Data.isGenerating = false;
1376
+ ObjectLayerEngineViewer.showLoading(false);
1461
1377
  } catch (error) {
1462
1378
  logger.error('Error generating WebP:', error);
1463
1379
  NotificationManager.Push({
1464
1380
  html: `Failed to generate WebP: ${error.message}`,
1465
1381
  status: 'error',
1466
1382
  });
1467
- this.Data.isGenerating = false;
1468
- this.showLoading(false);
1383
+ ObjectLayerEngineViewer.Data.isGenerating = false;
1384
+ ObjectLayerEngineViewer.showLoading(false);
1469
1385
  }
1470
- },
1471
-
1386
+ }
1472
1387
  /**
1473
1388
  * Updates direction/mode button active states and disabled flags in-place,
1474
1389
  * without re-rendering the viewer. Prevents layout flicker when switching
1475
1390
  * direction or mode while the WebP canvas and surrounding structure stay intact.
1476
1391
  */
1477
- _updateControlsState: function () {
1478
- const { currentDirection, currentMode, frameCounts } = this.Data;
1392
+ static _updateControlsState() {
1393
+ const { currentDirection, currentMode, frameCounts } = ObjectLayerEngineViewer.Data;
1479
1394
  const hasFrames = (direction, mode) => {
1480
- const code = this.getDirectionCode(direction, mode);
1395
+ const code = ObjectLayerEngineViewer.getDirectionCode(direction, mode);
1481
1396
  return !!(code && frameCounts && frameCounts[code] && frameCounts[code] > 0);
1482
1397
  };
1483
1398
  const getFrameCount = (direction, mode) => {
1484
- const code = this.getDirectionCode(direction, mode);
1399
+ const code = ObjectLayerEngineViewer.getDirectionCode(direction, mode);
1485
1400
  return code ? (frameCounts && frameCounts[code]) || 0 : 0;
1486
1401
  };
1487
-
1488
1402
  document.querySelectorAll('[data-direction]').forEach((btn) => {
1489
1403
  const d = btn.getAttribute('data-direction');
1490
1404
  btn.classList.toggle('active', d === currentDirection);
@@ -1493,7 +1407,6 @@ const ObjectLayerEngineViewer = {
1493
1407
  const countEl = btn.querySelector('.frame-count');
1494
1408
  if (countEl) countEl.textContent = hasFr ? `(${getFrameCount(d, currentMode)})` : '';
1495
1409
  });
1496
-
1497
1410
  document.querySelectorAll('[data-mode]').forEach((btn) => {
1498
1411
  const m = btn.getAttribute('data-mode');
1499
1412
  btn.classList.toggle('active', m === currentMode);
@@ -1502,9 +1415,8 @@ const ObjectLayerEngineViewer = {
1502
1415
  const countEl = btn.querySelector('.frame-count');
1503
1416
  if (countEl) countEl.textContent = hasFr ? `(${getFrameCount(currentDirection, m)})` : '';
1504
1417
  });
1505
- },
1506
-
1507
- showLoading: function (show, message = 'Generating WebP...') {
1418
+ }
1419
+ static showLoading(show, message = 'Generating WebP...') {
1508
1420
  const overlay = s('#webp-loading-overlay');
1509
1421
  if (overlay) {
1510
1422
  overlay.style.display = show ? 'flex' : 'none';
@@ -1513,90 +1425,76 @@ const ObjectLayerEngineViewer = {
1513
1425
  loadingText.textContent = message;
1514
1426
  }
1515
1427
  }
1516
-
1517
1428
  const downloadBtn = s('#download-webp-btn');
1518
1429
  if (downloadBtn) {
1519
1430
  downloadBtn.disabled = show;
1520
1431
  }
1521
-
1522
1432
  // Keep existing info badge visible during loading (removes the layout-shift flicker)
1523
- },
1524
-
1525
- downloadWebp: function () {
1526
- if (!this.Data.webp) {
1433
+ }
1434
+ static downloadWebp() {
1435
+ if (!ObjectLayerEngineViewer.Data.webp) {
1527
1436
  NotificationManager.Push({
1528
1437
  html: 'No WebP available to download',
1529
1438
  status: 'warning',
1530
1439
  });
1531
1440
  return;
1532
1441
  }
1533
-
1534
- const { objectLayer, currentDirection, currentMode } = this.Data;
1535
- const numericCode = this.getDirectionCode(currentDirection, currentMode);
1442
+ const { objectLayer, currentDirection, currentMode } = ObjectLayerEngineViewer.Data;
1443
+ const numericCode = ObjectLayerEngineViewer.getDirectionCode(currentDirection, currentMode);
1536
1444
  const filename = `${objectLayer.data.item.id}_${currentDirection}_${currentMode}_${numericCode}.webp`;
1537
-
1538
1445
  // Create a temporary anchor element to trigger download
1539
1446
  const a = document.createElement('a');
1540
- a.href = this.Data.webp;
1447
+ a.href = ObjectLayerEngineViewer.Data.webp;
1541
1448
  a.download = filename;
1542
1449
  document.body.appendChild(a);
1543
1450
  a.click();
1544
1451
  document.body.removeChild(a);
1545
-
1546
1452
  NotificationManager.Push({
1547
1453
  html: `WebP downloaded: ${filename}`,
1548
1454
  status: 'success',
1549
1455
  });
1550
- },
1551
-
1552
- toEngine: function () {
1553
- const { objectLayer } = this.Data;
1456
+ }
1457
+ static toEngine() {
1458
+ const { objectLayer } = ObjectLayerEngineViewer.Data;
1554
1459
  if (!objectLayer || !objectLayer._id) return;
1555
-
1556
1460
  // Navigate to editor route first
1557
1461
  setPath(`${getProxyPath()}object-layer-engine`);
1558
1462
  // Then add query param without replacing history
1559
1463
  setQueryParams({ id: objectLayer._id }, { replace: true });
1560
-
1561
1464
  if (s(`.modal-object-layer-engine`)) {
1562
1465
  ObjectLayerEngineModal.Reload();
1563
1466
  } else {
1564
1467
  s(`.main-btn-object-layer-engine`)?.click();
1565
1468
  }
1566
- },
1567
-
1568
- Reload: async function (options = {}) {
1469
+ }
1470
+ static async Reload(options = {}) {
1569
1471
  const { appStore, force = false, skipWebp = false } = options;
1570
1472
  const queryParams = getQueryParams();
1571
1473
  const objectId = queryParams.id || null;
1572
-
1573
1474
  // Only reload if object id actually changed (same logic as listener) or forced
1574
- if (objectId !== this.Data.currentObjectId || force) {
1575
- if (objectId !== this.Data.currentObjectId && !skipWebp) {
1576
- this.Data.webp = null;
1577
- this.Data.webpMetadata = null;
1475
+ if (objectId !== ObjectLayerEngineViewer.Data.currentObjectId || force) {
1476
+ if (objectId !== ObjectLayerEngineViewer.Data.currentObjectId && !skipWebp) {
1477
+ ObjectLayerEngineViewer.Data.webp = null;
1478
+ ObjectLayerEngineViewer.Data.webpMetadata = null;
1578
1479
  }
1579
- this.Data.currentObjectId = objectId;
1580
-
1480
+ ObjectLayerEngineViewer.Data.currentObjectId = objectId;
1581
1481
  if (objectId) {
1582
- await this.loadObjectLayer(objectId, appStore, { skipWebp });
1482
+ await ObjectLayerEngineViewer.loadObjectLayer(objectId, appStore, { skipWebp });
1583
1483
  } else {
1584
- await this.renderEmpty({ appStore });
1484
+ await ObjectLayerEngineViewer.renderEmpty({ appStore });
1585
1485
  }
1586
- } else if (!objectId && (this.Data.currentObjectId === null || force)) {
1486
+ } else if (!objectId && (ObjectLayerEngineViewer.Data.currentObjectId === null || force)) {
1587
1487
  // Special case: if we're already in empty state but DOM might have been reset
1588
1488
  // (e.g., modal reopened), force render the table if DOM is missing
1589
1489
  const id = 'object-layer-engine-viewer';
1590
1490
  const idModal = 'modal-object-layer-engine-viewer';
1591
1491
  const gridId = `object-layer-engine-management-grid-${idModal}`;
1592
1492
  const gridDomExists = s(`.${gridId}`);
1593
-
1594
1493
  if (!gridDomExists) {
1595
1494
  // DOM was reset (e.g., modal HTML reloaded), re-render the table
1596
- await this.renderEmpty({ appStore });
1495
+ await ObjectLayerEngineViewer.renderEmpty({ appStore });
1597
1496
  }
1598
1497
  }
1599
- },
1600
- };
1601
-
1498
+ }
1499
+ }
1602
1500
  export { ObjectLayerEngineViewer };