move.gl 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (463) hide show
  1. package/README.md +185 -11
  2. package/dist/LICENSE +21 -0
  3. package/dist/README.md +212 -0
  4. package/dist/css/move.gl.css +43859 -0
  5. package/dist/css/move.gl.min.css +19 -0
  6. package/dist/js/index.cjs +1171 -0
  7. package/dist/js/index.cjs.map +1 -0
  8. package/dist/js/index.d.cts +184 -0
  9. package/dist/js/index.d.ts +184 -0
  10. package/dist/js/index.mjs +1135 -0
  11. package/dist/js/index.mjs.map +1 -0
  12. package/dist/package.json +68 -0
  13. package/{scss → dist/scss}/classes/_animations.scss +33 -14
  14. package/dist/scss/classes/_controls.scss +314 -0
  15. package/dist/scss/classes/_effects.scss +283 -0
  16. package/dist/scss/classes/_index.scss +28 -0
  17. package/dist/scss/classes/_loaders.scss +779 -0
  18. package/dist/scss/classes/_transforms.scss +138 -0
  19. package/dist/scss/classes/_transitions.scss +264 -0
  20. package/{scss → dist/scss}/dev/_deprecation.scss +6 -3
  21. package/{scss → dist/scss}/dev/_modules.scss +5 -6
  22. package/dist/scss/docs.scss +2344 -0
  23. package/dist/scss/docs.scss.bak +3133 -0
  24. package/dist/scss/functions/_index.scss +22 -0
  25. package/dist/scss/functions/scenes/_bubble.scss +32 -0
  26. package/dist/scss/functions/scenes/_index.scss +21 -0
  27. package/dist/scss/index.scss +17 -0
  28. package/dist/scss/maps/_controls.scss +85 -0
  29. package/dist/scss/maps/_index.scss +22 -0
  30. package/{scss → dist/scss}/mixins/_accessibility.scss +24 -3
  31. package/{scss → dist/scss}/mixins/_boot.scss +4 -4
  32. package/dist/scss/mixins/_index.scss +41 -0
  33. package/dist/scss/mixins/_screensaver.scss +228 -0
  34. package/dist/scss/mixins/_shape.scss +315 -0
  35. package/dist/scss/mixins/animations/_base.scss +403 -0
  36. package/dist/scss/mixins/animations/_beat.scss +137 -0
  37. package/{scss → dist/scss}/mixins/animations/_blink.scss +60 -52
  38. package/dist/scss/mixins/animations/_bounce.scss +306 -0
  39. package/{scss → dist/scss}/mixins/animations/_elastic.scss +26 -22
  40. package/dist/scss/mixins/animations/_fade.scss +393 -0
  41. package/{scss → dist/scss}/mixins/animations/_flash.scss +53 -61
  42. package/dist/scss/mixins/animations/_flip.scss +251 -0
  43. package/{scss → dist/scss}/mixins/animations/_float.scss +47 -32
  44. package/{scss → dist/scss}/mixins/animations/_glow.scss +69 -58
  45. package/dist/scss/mixins/animations/_heartbeat.scss +195 -0
  46. package/dist/scss/mixins/animations/_hinge.scss +118 -0
  47. package/dist/scss/mixins/animations/_index.scss +97 -0
  48. package/dist/scss/mixins/animations/_jello.scss +123 -0
  49. package/dist/scss/mixins/animations/_jiggle.scss +162 -0
  50. package/dist/scss/mixins/animations/_lightspeed.scss +135 -0
  51. package/{scss → dist/scss}/mixins/animations/_nod.scss +57 -65
  52. package/dist/scss/mixins/animations/_pop.scss +153 -0
  53. package/dist/scss/mixins/animations/_pulse.scss +275 -0
  54. package/{scss → dist/scss}/mixins/animations/_ripple.scss +47 -55
  55. package/dist/scss/mixins/animations/_roll.scss +217 -0
  56. package/dist/scss/mixins/animations/_rotate.scss +728 -0
  57. package/dist/scss/mixins/animations/_rubber.scss +115 -0
  58. package/dist/scss/mixins/animations/_scale.scss +382 -0
  59. package/dist/scss/mixins/animations/_shake.scss +233 -0
  60. package/dist/scss/mixins/animations/_slide.scss +501 -0
  61. package/dist/scss/mixins/animations/_spin.scss +322 -0
  62. package/{scss → dist/scss}/mixins/animations/_sway.scss +32 -49
  63. package/{scss → dist/scss}/mixins/animations/_swing.scss +47 -49
  64. package/{scss → dist/scss}/mixins/animations/_tada.scss +44 -42
  65. package/{scss → dist/scss}/mixins/animations/_twist.scss +40 -55
  66. package/{scss → dist/scss}/mixins/animations/_wave.scss +36 -53
  67. package/dist/scss/mixins/animations/_wobble.scss +283 -0
  68. package/dist/scss/mixins/animations/_zoom.scss +394 -0
  69. package/{scss/mixins/mouse → dist/scss/mixins/controls}/_cursor.scss +60 -39
  70. package/dist/scss/mixins/controls/_hover.scss +625 -0
  71. package/dist/scss/mixins/controls/_index.scss +30 -0
  72. package/dist/scss/mixins/controls/_keyboard.scss +300 -0
  73. package/{scss/mixins/mouse → dist/scss/mixins/controls}/_pointer.scss +81 -72
  74. package/dist/scss/mixins/controls/_scroll.scss +460 -0
  75. package/{scss/mixins/scroll → dist/scss/mixins/controls}/_scrollbar.scss +50 -16
  76. package/dist/scss/mixins/controls/_selection.scss +208 -0
  77. package/dist/scss/mixins/controls/_touch.scss +401 -0
  78. package/dist/scss/mixins/effects/_blend.scss +128 -0
  79. package/dist/scss/mixins/effects/_filter.scss +470 -0
  80. package/dist/scss/mixins/effects/_focus.scss +83 -0
  81. package/dist/scss/mixins/effects/_gradient.scss +130 -0
  82. package/dist/scss/mixins/effects/_index.scss +28 -0
  83. package/dist/scss/mixins/effects/_mask.scss +76 -0
  84. package/dist/scss/mixins/effects/_opacity.scss +376 -0
  85. package/dist/scss/mixins/effects/_shadow.scss +429 -0
  86. package/dist/scss/mixins/keyframes/_base.scss +199 -0
  87. package/dist/scss/mixins/keyframes/_index.scss +24 -0
  88. package/dist/scss/mixins/keyframes/animations/_beat.scss +280 -0
  89. package/dist/scss/mixins/keyframes/animations/_blink.scss +82 -0
  90. package/dist/scss/mixins/keyframes/animations/_bounce.scss +292 -0
  91. package/dist/scss/mixins/keyframes/animations/_fade.scss +311 -0
  92. package/dist/scss/mixins/keyframes/animations/_flash.scss +165 -0
  93. package/dist/scss/mixins/keyframes/animations/_flip.scss +266 -0
  94. package/{scss/mixins → dist/scss/mixins/keyframes}/animations/_index.scss +19 -10
  95. package/dist/scss/mixins/keyframes/animations/_jiggle.scss +85 -0
  96. package/dist/scss/mixins/keyframes/animations/_lightspeed.scss +73 -0
  97. package/dist/scss/mixins/keyframes/animations/_nod.scss +79 -0
  98. package/dist/scss/mixins/keyframes/animations/_pop.scss +78 -0
  99. package/dist/scss/mixins/keyframes/animations/_pulse.scss +225 -0
  100. package/dist/scss/mixins/keyframes/animations/_ripple.scss +94 -0
  101. package/dist/scss/mixins/keyframes/animations/_roll.scss +124 -0
  102. package/dist/scss/mixins/keyframes/animations/_rotate.scss +360 -0
  103. package/dist/scss/mixins/keyframes/animations/_rubber.scss +81 -0
  104. package/dist/scss/mixins/keyframes/animations/_scale.scss +308 -0
  105. package/dist/scss/mixins/keyframes/animations/_shake.scss +270 -0
  106. package/dist/scss/mixins/keyframes/animations/_slide.scss +345 -0
  107. package/dist/scss/mixins/keyframes/animations/_spin.scss +270 -0
  108. package/dist/scss/mixins/keyframes/animations/_sway.scss +83 -0
  109. package/dist/scss/mixins/keyframes/animations/_twist.scss +89 -0
  110. package/dist/scss/mixins/keyframes/animations/_wave.scss +90 -0
  111. package/dist/scss/mixins/keyframes/animations/_wobble.scss +293 -0
  112. package/dist/scss/mixins/keyframes/animations/_zoom.scss +345 -0
  113. package/dist/scss/mixins/loaders/_bars.scss +128 -0
  114. package/dist/scss/mixins/loaders/_base.scss +39 -0
  115. package/dist/scss/mixins/loaders/_bubble.scss +395 -0
  116. package/dist/scss/mixins/loaders/_circle.scss +456 -0
  117. package/dist/scss/mixins/loaders/_dots.scss +248 -0
  118. package/dist/scss/mixins/loaders/_graph.scss +542 -0
  119. package/dist/scss/mixins/loaders/_index.scss +77 -0
  120. package/dist/scss/mixins/loaders/_line.scss +471 -0
  121. package/dist/scss/mixins/loaders/_objects.scss +563 -0
  122. package/dist/scss/mixins/loaders/_progress.scss +477 -0
  123. package/dist/scss/mixins/loaders/_rect.scss +480 -0
  124. package/dist/scss/mixins/loaders/_rings.scss +377 -0
  125. package/dist/scss/mixins/loaders/_skeleton.scss +461 -0
  126. package/dist/scss/mixins/loaders/_special.scss +611 -0
  127. package/dist/scss/mixins/loaders/_spinner.scss +175 -0
  128. package/dist/scss/mixins/loaders/_text.scss +446 -0
  129. package/{scss → dist/scss}/mixins/transforms/_flip.scss +16 -18
  130. package/dist/scss/mixins/transforms/_index.scss +28 -0
  131. package/dist/scss/mixins/transforms/_matrix.scss +18 -0
  132. package/{scss → dist/scss}/mixins/transforms/_perspective.scss +18 -1
  133. package/{scss → dist/scss}/mixins/transforms/_rotate.scss +9 -14
  134. package/{scss → dist/scss}/mixins/transforms/_scale.scss +16 -1
  135. package/{scss → dist/scss}/mixins/transforms/_skew.scss +16 -2
  136. package/{scss → dist/scss}/mixins/transforms/_translate.scss +16 -2
  137. package/dist/scss/mixins/transitions/_index.scss +22 -0
  138. package/dist/scss/mixins/transitions/_transition.scss +43 -0
  139. package/dist/scss/variables/_animations.scss +300 -0
  140. package/dist/scss/variables/_controls.scss +178 -0
  141. package/dist/scss/variables/_effects.scss +87 -0
  142. package/dist/scss/variables/_index.scss +27 -0
  143. package/dist/scss/variables/_keyframes.scss +28 -0
  144. package/dist/scss/variables/_loaders.scss +75 -0
  145. package/dist/scss/variables/_transforms.scss +85 -0
  146. package/dist/scss/variables/_transitions.scss +80 -0
  147. package/dist/ts/Draggable.ts +143 -0
  148. package/dist/ts/Gesture.ts +226 -0
  149. package/dist/ts/Keyboard.ts +195 -0
  150. package/dist/ts/LoaderManager.ts +662 -0
  151. package/dist/ts/Screensaver.ts +192 -0
  152. package/dist/ts/VideoOverlay.ts +205 -0
  153. package/dist/ts/demo.ts +1108 -0
  154. package/dist/ts/index.ts +58 -0
  155. package/package.json +90 -53
  156. package/src/html/_base.html +138 -0
  157. package/src/html/base.html +147 -0
  158. package/src/html/core-concepts.html +282 -0
  159. package/src/html/demo_base.html +171 -0
  160. package/src/html/demo_draggable.html +250 -0
  161. package/src/html/demo_gesture.html +264 -0
  162. package/src/html/demo_keyboard.html +224 -0
  163. package/src/html/demo_screensaver.html +258 -0
  164. package/src/html/demo_video_overlay.html +291 -0
  165. package/src/html/getting-started.html +242 -0
  166. package/src/html/index.html +400 -0
  167. package/src/html/keyboard.html +14 -0
  168. package/src/html/partials/_demo_links.html +21 -0
  169. package/src/html/partials/_footer.html +18 -0
  170. package/src/html/partials/_head.html +21 -0
  171. package/src/html/partials/_nav.html +84 -0
  172. package/src/html/partials/_theme_toggle.html +11 -0
  173. package/src/html/screensaver.html +20 -0
  174. package/src/html/test_animations.html +813 -0
  175. package/src/html/test_attention.html +281 -0
  176. package/src/html/test_bounce.html +201 -0
  177. package/src/html/test_effects.html +1348 -0
  178. package/src/html/test_fade.html +213 -0
  179. package/src/html/test_flip.html +208 -0
  180. package/src/html/test_keyframes.html +415 -0
  181. package/src/html/test_loaders.html +1489 -0
  182. package/src/html/test_mouse.html +516 -0
  183. package/src/html/test_overview.html +1444 -0
  184. package/src/html/test_pulse.html +212 -0
  185. package/src/html/test_scale.html +204 -0
  186. package/src/html/test_shake.html +232 -0
  187. package/src/html/test_slide.html +212 -0
  188. package/src/html/test_special.html +257 -0
  189. package/src/html/test_spin.html +216 -0
  190. package/src/html/test_transforms.html +332 -0
  191. package/src/html/test_transitions.html +245 -0
  192. package/src/html/test_zoom.html +188 -0
  193. package/src/html/video_overlay.html +27 -0
  194. package/src/jinja/_base.html.jinja +50 -0
  195. package/src/jinja/base.html.jinja +48 -0
  196. package/src/jinja/core-concepts.html.jinja +148 -0
  197. package/src/jinja/demo_draggable.html.jinja +114 -0
  198. package/src/jinja/demo_gesture.html.jinja +128 -0
  199. package/src/jinja/demo_keyboard.html.jinja +88 -0
  200. package/src/jinja/demo_screensaver.html.jinja +122 -0
  201. package/src/jinja/demo_video_overlay.html.jinja +155 -0
  202. package/src/jinja/getting-started.html.jinja +108 -0
  203. package/src/jinja/index.html.jinja +268 -0
  204. package/src/jinja/index.json +5 -0
  205. package/src/jinja/move.gl.css +7741 -0
  206. package/src/jinja/partials/_code_block.html.jinja +17 -0
  207. package/src/jinja/partials/_demo_links.html.jinja +41 -0
  208. package/src/jinja/partials/_feature_card.html.jinja +20 -0
  209. package/src/jinja/partials/_footer.html.jinja +22 -0
  210. package/src/jinja/partials/_head.html.jinja +27 -0
  211. package/src/jinja/partials/_nav.html.jinja +79 -0
  212. package/src/jinja/partials/_theme_toggle.html.jinja +15 -0
  213. package/src/jinja/test_animations.html.jinja +679 -0
  214. package/src/jinja/test_attention.html.jinja +147 -0
  215. package/src/jinja/test_bounce.html.jinja +67 -0
  216. package/src/jinja/test_effects.html.jinja +1218 -0
  217. package/src/jinja/test_fade.html.jinja +79 -0
  218. package/src/jinja/test_flip.html.jinja +74 -0
  219. package/src/jinja/test_keyframes.html.jinja +281 -0
  220. package/src/jinja/test_loaders.html.jinja +1358 -0
  221. package/src/jinja/test_mouse.html.jinja +382 -0
  222. package/src/jinja/test_overview.html.jinja +1313 -0
  223. package/src/jinja/test_pulse.html.jinja +78 -0
  224. package/src/jinja/test_scale.html.jinja +70 -0
  225. package/src/jinja/test_shake.html.jinja +98 -0
  226. package/src/jinja/test_slide.html.jinja +78 -0
  227. package/src/jinja/test_special.html.jinja +123 -0
  228. package/src/jinja/test_spin.html.jinja +82 -0
  229. package/src/jinja/test_transforms.html.jinja +198 -0
  230. package/src/jinja/test_transitions.html.jinja +111 -0
  231. package/src/jinja/test_zoom.html.jinja +54 -0
  232. package/src/scss/classes/_animations.scss +595 -0
  233. package/src/scss/classes/_controls.scss +314 -0
  234. package/src/scss/classes/_effects.scss +283 -0
  235. package/src/scss/classes/_index.scss +28 -0
  236. package/src/scss/classes/_loaders.scss +779 -0
  237. package/src/scss/classes/_transforms.scss +138 -0
  238. package/src/scss/classes/_transitions.scss +264 -0
  239. package/src/scss/dev/_banner.scss +36 -0
  240. package/src/scss/dev/_debug.scss +18 -0
  241. package/src/scss/dev/_deprecation.scss +13 -0
  242. package/src/scss/dev/_index.scss +8 -0
  243. package/src/scss/dev/_modules.scss +23 -0
  244. package/src/scss/docs.scss +2344 -0
  245. package/src/scss/docs.scss.bak +3133 -0
  246. package/src/scss/functions/_index.scss +22 -0
  247. package/src/scss/functions/scenes/_bubble.scss +32 -0
  248. package/src/scss/functions/scenes/_index.scss +21 -0
  249. package/src/scss/index.scss +17 -0
  250. package/src/scss/maps/_controls.scss +85 -0
  251. package/src/scss/maps/_index.scss +22 -0
  252. package/src/scss/mixins/_accessibility.scss +91 -0
  253. package/src/scss/mixins/_boot.scss +51 -0
  254. package/src/scss/mixins/_index.scss +41 -0
  255. package/src/scss/mixins/_screensaver.scss +228 -0
  256. package/src/scss/mixins/_shape.scss +315 -0
  257. package/src/scss/mixins/animations/_base.scss +403 -0
  258. package/src/scss/mixins/animations/_beat.scss +137 -0
  259. package/src/scss/mixins/animations/_blink.scss +159 -0
  260. package/src/scss/mixins/animations/_bounce.scss +306 -0
  261. package/src/scss/mixins/animations/_elastic.scss +69 -0
  262. package/src/scss/mixins/animations/_fade.scss +393 -0
  263. package/src/scss/mixins/animations/_flash.scss +169 -0
  264. package/src/scss/mixins/animations/_flip.scss +251 -0
  265. package/src/scss/mixins/animations/_float.scss +141 -0
  266. package/src/scss/mixins/animations/_glow.scss +190 -0
  267. package/src/scss/mixins/animations/_heartbeat.scss +195 -0
  268. package/src/scss/mixins/animations/_hinge.scss +118 -0
  269. package/src/scss/mixins/animations/_index.scss +97 -0
  270. package/src/scss/mixins/animations/_jello.scss +123 -0
  271. package/src/scss/mixins/animations/_jiggle.scss +162 -0
  272. package/src/scss/mixins/animations/_lightspeed.scss +135 -0
  273. package/src/scss/mixins/animations/_nod.scss +153 -0
  274. package/src/scss/mixins/animations/_pop.scss +153 -0
  275. package/src/scss/mixins/animations/_pulse.scss +275 -0
  276. package/src/scss/mixins/animations/_ripple.scss +161 -0
  277. package/src/scss/mixins/animations/_roll.scss +217 -0
  278. package/src/scss/mixins/animations/_rotate.scss +728 -0
  279. package/src/scss/mixins/animations/_rubber.scss +115 -0
  280. package/src/scss/mixins/animations/_scale.scss +382 -0
  281. package/src/scss/mixins/animations/_shake.scss +233 -0
  282. package/src/scss/mixins/animations/_slide.scss +501 -0
  283. package/src/scss/mixins/animations/_spin.scss +322 -0
  284. package/src/scss/mixins/animations/_sway.scss +150 -0
  285. package/src/scss/mixins/animations/_swing.scss +245 -0
  286. package/src/scss/mixins/animations/_tada.scss +235 -0
  287. package/src/scss/mixins/animations/_twist.scss +162 -0
  288. package/src/scss/mixins/animations/_wave.scss +149 -0
  289. package/src/scss/mixins/animations/_wobble.scss +283 -0
  290. package/src/scss/mixins/animations/_zoom.scss +394 -0
  291. package/src/scss/mixins/controls/_cursor.scss +203 -0
  292. package/src/scss/mixins/controls/_hover.scss +625 -0
  293. package/src/scss/mixins/controls/_index.scss +30 -0
  294. package/src/scss/mixins/controls/_keyboard.scss +300 -0
  295. package/src/scss/mixins/controls/_pointer.scss +267 -0
  296. package/src/scss/mixins/controls/_scroll.scss +460 -0
  297. package/src/scss/mixins/controls/_scrollbar.scss +283 -0
  298. package/src/scss/mixins/controls/_selection.scss +208 -0
  299. package/src/scss/mixins/controls/_touch.scss +401 -0
  300. package/src/scss/mixins/effects/_blend.scss +128 -0
  301. package/src/scss/mixins/effects/_filter.scss +470 -0
  302. package/src/scss/mixins/effects/_focus.scss +83 -0
  303. package/src/scss/mixins/effects/_gradient.scss +130 -0
  304. package/src/scss/mixins/effects/_index.scss +28 -0
  305. package/src/scss/mixins/effects/_mask.scss +76 -0
  306. package/src/scss/mixins/effects/_opacity.scss +376 -0
  307. package/src/scss/mixins/effects/_shadow.scss +429 -0
  308. package/src/scss/mixins/keyframes/_base.scss +199 -0
  309. package/src/scss/mixins/keyframes/_index.scss +24 -0
  310. package/src/scss/mixins/keyframes/animations/_beat.scss +280 -0
  311. package/src/scss/mixins/keyframes/animations/_blink.scss +82 -0
  312. package/src/scss/mixins/keyframes/animations/_bounce.scss +292 -0
  313. package/src/scss/mixins/keyframes/animations/_fade.scss +311 -0
  314. package/src/scss/mixins/keyframes/animations/_flash.scss +165 -0
  315. package/src/scss/mixins/keyframes/animations/_flip.scss +266 -0
  316. package/src/scss/mixins/keyframes/animations/_index.scss +46 -0
  317. package/src/scss/mixins/keyframes/animations/_jiggle.scss +85 -0
  318. package/src/scss/mixins/keyframes/animations/_lightspeed.scss +73 -0
  319. package/src/scss/mixins/keyframes/animations/_nod.scss +79 -0
  320. package/src/scss/mixins/keyframes/animations/_pop.scss +78 -0
  321. package/src/scss/mixins/keyframes/animations/_pulse.scss +225 -0
  322. package/src/scss/mixins/keyframes/animations/_ripple.scss +94 -0
  323. package/src/scss/mixins/keyframes/animations/_roll.scss +124 -0
  324. package/src/scss/mixins/keyframes/animations/_rotate.scss +360 -0
  325. package/src/scss/mixins/keyframes/animations/_rubber.scss +81 -0
  326. package/src/scss/mixins/keyframes/animations/_scale.scss +308 -0
  327. package/src/scss/mixins/keyframes/animations/_shake.scss +270 -0
  328. package/src/scss/mixins/keyframes/animations/_slide.scss +345 -0
  329. package/src/scss/mixins/keyframes/animations/_spin.scss +270 -0
  330. package/src/scss/mixins/keyframes/animations/_sway.scss +83 -0
  331. package/src/scss/mixins/keyframes/animations/_twist.scss +89 -0
  332. package/src/scss/mixins/keyframes/animations/_wave.scss +90 -0
  333. package/src/scss/mixins/keyframes/animations/_wobble.scss +293 -0
  334. package/src/scss/mixins/keyframes/animations/_zoom.scss +345 -0
  335. package/src/scss/mixins/loaders/_bars.scss +128 -0
  336. package/src/scss/mixins/loaders/_base.scss +39 -0
  337. package/src/scss/mixins/loaders/_bubble.scss +395 -0
  338. package/src/scss/mixins/loaders/_circle.scss +456 -0
  339. package/src/scss/mixins/loaders/_dots.scss +248 -0
  340. package/src/scss/mixins/loaders/_graph.scss +542 -0
  341. package/src/scss/mixins/loaders/_index.scss +77 -0
  342. package/src/scss/mixins/loaders/_line.scss +471 -0
  343. package/src/scss/mixins/loaders/_objects.scss +563 -0
  344. package/src/scss/mixins/loaders/_progress.scss +477 -0
  345. package/src/scss/mixins/loaders/_rect.scss +480 -0
  346. package/src/scss/mixins/loaders/_rings.scss +377 -0
  347. package/src/scss/mixins/loaders/_skeleton.scss +461 -0
  348. package/src/scss/mixins/loaders/_special.scss +611 -0
  349. package/src/scss/mixins/loaders/_spinner.scss +175 -0
  350. package/src/scss/mixins/loaders/_text.scss +446 -0
  351. package/src/scss/mixins/transforms/_flip.scss +74 -0
  352. package/src/scss/mixins/transforms/_index.scss +28 -0
  353. package/src/scss/mixins/transforms/_matrix.scss +18 -0
  354. package/src/scss/mixins/transforms/_perspective.scss +28 -0
  355. package/src/scss/mixins/transforms/_rotate.scss +96 -0
  356. package/src/scss/mixins/transforms/_scale.scss +26 -0
  357. package/src/scss/mixins/transforms/_skew.scss +27 -0
  358. package/src/scss/mixins/transforms/_translate.scss +27 -0
  359. package/src/scss/mixins/transitions/_index.scss +22 -0
  360. package/src/scss/mixins/transitions/_transition.scss +43 -0
  361. package/src/scss/variables/_animations.scss +300 -0
  362. package/src/scss/variables/_controls.scss +178 -0
  363. package/src/scss/variables/_effects.scss +87 -0
  364. package/src/scss/variables/_index.scss +27 -0
  365. package/src/scss/variables/_keyframes.scss +28 -0
  366. package/src/scss/variables/_loaders.scss +75 -0
  367. package/src/scss/variables/_transforms.scss +85 -0
  368. package/src/scss/variables/_transitions.scss +80 -0
  369. package/src/ts/Draggable.ts +143 -0
  370. package/src/ts/Gesture.ts +226 -0
  371. package/src/ts/Keyboard.ts +195 -0
  372. package/src/ts/LoaderManager.ts +662 -0
  373. package/src/ts/Screensaver.ts +192 -0
  374. package/src/ts/VideoOverlay.ts +205 -0
  375. package/src/ts/demo.ts +1108 -0
  376. package/src/ts/index.ts +58 -0
  377. package/css/move.gl.css +0 -2
  378. package/css/move.gl.min.css +0 -2
  379. package/scss/classes/_transforms.scss +0 -124
  380. package/scss/classes/keyboard.scss +0 -18
  381. package/scss/classes/screensaver.scss +0 -15
  382. package/scss/effects/_filter.scss +0 -176
  383. package/scss/effects/_index.scss +0 -23
  384. package/scss/effects/_opacity.scss +0 -62
  385. package/scss/effects/_shadow.scss +0 -175
  386. package/scss/functions/scenes/_bubble.scss +0 -19
  387. package/scss/functions/scenes/_index.scss +0 -20
  388. package/scss/index.scss +0 -0
  389. package/scss/keyframes/_beat.scss +0 -26
  390. package/scss/keyframes/_index.scss +0 -0
  391. package/scss/maps/_index.scss +0 -0
  392. package/scss/maps/_mouse.scss +0 -96
  393. package/scss/mixins/_hover.scss +0 -51
  394. package/scss/mixins/_index.scss +0 -0
  395. package/scss/mixins/_selection.scss +0 -321
  396. package/scss/mixins/_shape.scss +0 -44
  397. package/scss/mixins/_touch.scss +0 -95
  398. package/scss/mixins/animations/--hover.scss +0 -107
  399. package/scss/mixins/animations/_base.scss +0 -337
  400. package/scss/mixins/animations/_beat.scss +0 -119
  401. package/scss/mixins/animations/_bounce.scss +0 -192
  402. package/scss/mixins/animations/_fade.scss +0 -154
  403. package/scss/mixins/animations/_flip.scss +0 -72
  404. package/scss/mixins/animations/_heartbeat.scss +0 -175
  405. package/scss/mixins/animations/_hinge.scss +0 -119
  406. package/scss/mixins/animations/_jello.scss +0 -129
  407. package/scss/mixins/animations/_jiggle.scss +0 -163
  408. package/scss/mixins/animations/_lightspeed.scss +0 -130
  409. package/scss/mixins/animations/_pop.scss +0 -150
  410. package/scss/mixins/animations/_pulse.scss +0 -213
  411. package/scss/mixins/animations/_roll.scss +0 -261
  412. package/scss/mixins/animations/_rotate.scss +0 -428
  413. package/scss/mixins/animations/_rubber.scss +0 -116
  414. package/scss/mixins/animations/_scale.scss +0 -113
  415. package/scss/mixins/animations/_shake.scss +0 -182
  416. package/scss/mixins/animations/_slide.scss +0 -294
  417. package/scss/mixins/animations/_spin.scss +0 -219
  418. package/scss/mixins/animations/_wobble.scss +0 -254
  419. package/scss/mixins/animations/_zoom.scss +0 -166
  420. package/scss/mixins/effects/_filter.scss +0 -148
  421. package/scss/mixins/effects/_index.scss +0 -0
  422. package/scss/mixins/effects/_shadow.scss +0 -21
  423. package/scss/mixins/loaders/_index.scss +0 -0
  424. package/scss/mixins/loaders/_progress.scss +0 -174
  425. package/scss/mixins/loaders/_spinner.scss +0 -101
  426. package/scss/mixins/loaders/circle_01.scss +0 -22
  427. package/scss/mixins/loaders/circle_02.scss +0 -19
  428. package/scss/mixins/loaders/circle_03.scss +0 -29
  429. package/scss/mixins/loaders/circle_inner_01.scss +0 -33
  430. package/scss/mixins/loaders/circle_inner_02.scss +0 -33
  431. package/scss/mixins/loaders/circle_inner_03.scss +0 -34
  432. package/scss/mixins/mouse/_index.scss +0 -0
  433. package/scss/mixins/scroll/_index.scss +0 -0
  434. package/scss/mixins/scroll/_scroll.scss +0 -104
  435. package/scss/mixins/transforms/_index.scss +0 -23
  436. package/scss/mixins/transforms/_matrix.scss +0 -1
  437. package/scss/mixins/transitions/_index.scss +0 -0
  438. package/scss/mixins/transitions/_transition.scss +0 -13
  439. package/scss/variables/_animation.scss +0 -91
  440. package/scss/variables/_index.scss +0 -0
  441. package/ts/ARContent.ts +0 -27
  442. package/ts/ARInteraction.ts +0 -34
  443. package/ts/AdaptiveUI.ts +0 -25
  444. package/ts/ContentStreaming.ts +0 -20
  445. package/ts/Draggable.ts +0 -71
  446. package/ts/DynamicEnvironment.ts +0 -60
  447. package/ts/Gesture.ts +0 -168
  448. package/ts/ImmersiveAudio.ts +0 -40
  449. package/ts/InteractiveCanvas.ts +0 -177
  450. package/ts/InteractiveVideo.ts +0 -29
  451. package/ts/Keyboard.ts +0 -162
  452. package/ts/RealTimeCollaboration.ts +0 -25
  453. package/ts/Screensaver.ts +0 -140
  454. package/ts/SpatialNavigation.ts +0 -38
  455. package/ts/UserProfile.ts +0 -27
  456. package/ts/VRExperience.ts +0 -58
  457. package/ts/VideoOverlay.ts +0 -116
  458. package/ts/index.ts +0 -0
  459. /package/{scss → dist/scss}/dev/_banner.scss +0 -0
  460. /package/{scss → dist/scss}/dev/_debug.scss +0 -0
  461. /package/{scss → dist/scss}/dev/_index.scss +0 -0
  462. /package/{scss/classes/_index.scss → src/html/partials/_code_block.html} +0 -0
  463. /package/{scss/functions/_index.scss → src/html/partials/_feature_card.html} +0 -0
package/src/ts/demo.ts ADDED
@@ -0,0 +1,1108 @@
1
+ // =============================================================================
2
+ // move.gl Demo Scripts
3
+ // =============================================================================
4
+ // Demo-specific JavaScript for interactive component demonstrations.
5
+ // These scripts are separate from the main library.
6
+ //
7
+ // This file contains:
8
+ // - Theme toggle functionality
9
+ // - Navigation dropdown functionality
10
+ // - Utility functions for demos
11
+ // - Demo page components (Draggable, Keyboard, Gesture, Screensaver, VideoOverlay)
12
+
13
+
14
+ // -----------------------------------------------------------------------------
15
+ // Type Definitions
16
+ // -----------------------------------------------------------------------------
17
+
18
+ type SwipeDirection = 'left' | 'right' | 'up' | 'down';
19
+ type DragEventType = 'start' | 'drag' | 'end';
20
+ type DragCallback = (type: DragEventType, elementId: string, x: number, y: number) => void;
21
+
22
+ interface KeyboardLayout {
23
+ default: string[][];
24
+ shift: string[][];
25
+ special: string[][];
26
+ }
27
+
28
+ interface GestureStats {
29
+ taps: number;
30
+ swipes: number;
31
+ pinches: number;
32
+ }
33
+
34
+ interface ScreensaverOptions {
35
+ timeout?: number;
36
+ fadeDuration?: number;
37
+ }
38
+
39
+ interface VideoOverlayOptions {
40
+ opacity?: number;
41
+ fadeDuration?: number;
42
+ effect?: string;
43
+ }
44
+
45
+
46
+ // -----------------------------------------------------------------------------
47
+ // Theme Toggle
48
+ // -----------------------------------------------------------------------------
49
+
50
+ /**
51
+ * Initialize theme toggle functionality.
52
+ * Handles light/dark mode switching with localStorage persistence.
53
+ */
54
+ function initThemeToggle(): void {
55
+ const themeToggle = document.querySelector<HTMLButtonElement>('[data-toggle="theme"]');
56
+ const html = document.documentElement;
57
+
58
+ // Load saved theme or use system preference
59
+ const savedTheme = localStorage.getItem('theme');
60
+ const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
61
+
62
+ if (savedTheme) {
63
+ html.setAttribute('data-theme', savedTheme);
64
+ } else if (systemPrefersDark) {
65
+ html.setAttribute('data-theme', 'dark');
66
+ }
67
+
68
+ // Handle theme toggle click
69
+ themeToggle?.addEventListener('click', () => {
70
+ const currentTheme = html.getAttribute('data-theme');
71
+ const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
72
+ html.setAttribute('data-theme', newTheme);
73
+ localStorage.setItem('theme', newTheme);
74
+ });
75
+
76
+ // Listen for system theme changes
77
+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
78
+ if (!localStorage.getItem('theme')) {
79
+ html.setAttribute('data-theme', e.matches ? 'dark' : 'light');
80
+ }
81
+ });
82
+ }
83
+
84
+
85
+ // -----------------------------------------------------------------------------
86
+ // Navigation Dropdown
87
+ // -----------------------------------------------------------------------------
88
+
89
+ /**
90
+ * Initialize navigation dropdown functionality.
91
+ * Handles opening, closing, and keyboard navigation.
92
+ */
93
+ function initNavDropdown(): void {
94
+ const dropdown = document.getElementById('nav-dropdown');
95
+ const toggle = dropdown?.querySelector<HTMLButtonElement>('.nav__dropdown-toggle');
96
+
97
+ if (!dropdown || !toggle) return;
98
+
99
+ // Toggle dropdown on click
100
+ toggle.addEventListener('click', (e) => {
101
+ e.stopPropagation();
102
+ const isOpen = dropdown.classList.toggle('open');
103
+ toggle.setAttribute('aria-expanded', String(isOpen));
104
+ });
105
+
106
+ // Close dropdown when clicking outside
107
+ document.addEventListener('click', (e) => {
108
+ if (!dropdown.contains(e.target as Node)) {
109
+ dropdown.classList.remove('open');
110
+ toggle.setAttribute('aria-expanded', 'false');
111
+ }
112
+ });
113
+
114
+ // Close dropdown on Escape key
115
+ document.addEventListener('keydown', (e) => {
116
+ if (e.key === 'Escape' && dropdown.classList.contains('open')) {
117
+ dropdown.classList.remove('open');
118
+ toggle.setAttribute('aria-expanded', 'false');
119
+ toggle.focus();
120
+ }
121
+ });
122
+ }
123
+
124
+
125
+ // -----------------------------------------------------------------------------
126
+ // Tab Navigation
127
+ // -----------------------------------------------------------------------------
128
+
129
+ /**
130
+ * Initialize tab navigation functionality.
131
+ * Handles tab switching and content visibility.
132
+ */
133
+ function initTabs(): void {
134
+ const tabContainers = document.querySelectorAll<HTMLElement>('[data-tabs]');
135
+
136
+ tabContainers.forEach((container) => {
137
+ const tabs = container.querySelectorAll<HTMLButtonElement>('.tab');
138
+ const contents = container.querySelectorAll<HTMLElement>('.tab-content');
139
+
140
+ tabs.forEach((tab) => {
141
+ tab.addEventListener('click', () => {
142
+ const targetId = tab.dataset.target;
143
+
144
+ // Update active tab
145
+ tabs.forEach((t) => t.classList.remove('active'));
146
+ tab.classList.add('active');
147
+
148
+ // Update visible content
149
+ contents.forEach((content) => {
150
+ content.classList.toggle('active', content.id === targetId);
151
+ });
152
+ });
153
+ });
154
+ });
155
+ }
156
+
157
+
158
+ // -----------------------------------------------------------------------------
159
+ // Log Output
160
+ // -----------------------------------------------------------------------------
161
+
162
+ /**
163
+ * Log output manager for demo panels.
164
+ */
165
+ class LogOutput {
166
+ private container: HTMLElement;
167
+ private maxEntries: number;
168
+
169
+ constructor(selector: string, maxEntries = 50) {
170
+ const element = document.querySelector<HTMLElement>(selector);
171
+ if (!element) {
172
+ throw new Error(`Log output container not found: ${selector}`);
173
+ }
174
+ this.container = element;
175
+ this.maxEntries = maxEntries;
176
+ }
177
+
178
+ /**
179
+ * Add a log entry with timestamp.
180
+ */
181
+ log(message: string, type: 'info' | 'success' | 'warning' | 'error' = 'info'): void {
182
+ const entry = document.createElement('div');
183
+ entry.className = `log-entry log-entry--${type}`;
184
+
185
+ const timestamp = document.createElement('span');
186
+ timestamp.className = 'timestamp';
187
+ timestamp.textContent = new Date().toLocaleTimeString();
188
+
189
+ const text = document.createElement('span');
190
+ text.textContent = message;
191
+
192
+ entry.appendChild(timestamp);
193
+ entry.appendChild(text);
194
+
195
+ this.container.appendChild(entry);
196
+
197
+ // Remove old entries if exceeding max
198
+ while (this.container.children.length > this.maxEntries) {
199
+ this.container.removeChild(this.container.firstChild!);
200
+ }
201
+
202
+ // Scroll to bottom
203
+ this.container.scrollTop = this.container.scrollHeight;
204
+ }
205
+
206
+ /**
207
+ * Clear all log entries.
208
+ */
209
+ clear(): void {
210
+ this.container.innerHTML = '';
211
+ }
212
+ }
213
+
214
+
215
+ // -----------------------------------------------------------------------------
216
+ // Utility Functions
217
+ // -----------------------------------------------------------------------------
218
+
219
+ /**
220
+ * Format a number with units (e.g., "1.5s", "100px").
221
+ */
222
+ function formatValue(value: number, unit: string): string {
223
+ return `${value}${unit}`;
224
+ }
225
+
226
+ /**
227
+ * Debounce function for rate-limiting.
228
+ */
229
+ function debounce<T extends (...args: unknown[]) => void>(
230
+ func: T,
231
+ wait: number
232
+ ): (...args: Parameters<T>) => void {
233
+ let timeout: ReturnType<typeof setTimeout> | null = null;
234
+
235
+ return (...args: Parameters<T>) => {
236
+ if (timeout) clearTimeout(timeout);
237
+ timeout = setTimeout(() => func(...args), wait);
238
+ };
239
+ }
240
+
241
+ /**
242
+ * Throttle function for rate-limiting.
243
+ */
244
+ function throttle<T extends (...args: unknown[]) => void>(
245
+ func: T,
246
+ limit: number
247
+ ): (...args: Parameters<T>) => void {
248
+ let inThrottle = false;
249
+
250
+ return (...args: Parameters<T>) => {
251
+ if (!inThrottle) {
252
+ func(...args);
253
+ inThrottle = true;
254
+ setTimeout(() => (inThrottle = false), limit);
255
+ }
256
+ };
257
+ }
258
+
259
+
260
+ // -----------------------------------------------------------------------------
261
+ // Initialize on DOM Ready
262
+ // -----------------------------------------------------------------------------
263
+
264
+ function initDemo(): void {
265
+ initThemeToggle();
266
+ initNavDropdown();
267
+ initTabs();
268
+ }
269
+
270
+ // Auto-initialize when DOM is ready
271
+ if (document.readyState === 'loading') {
272
+ document.addEventListener('DOMContentLoaded', initDemo);
273
+ } else {
274
+ initDemo();
275
+ }
276
+
277
+
278
+ // -----------------------------------------------------------------------------
279
+ // Exports
280
+ // -----------------------------------------------------------------------------
281
+
282
+ export {
283
+ debounce, formatValue, initNavDropdown,
284
+ initTabs, initThemeToggle, LogOutput, throttle
285
+ };
286
+
287
+
288
+ // -----------------------------------------------------------------------------
289
+ // Demo: Draggable
290
+ // -----------------------------------------------------------------------------
291
+
292
+ /**
293
+ * Demo implementation of draggable functionality.
294
+ * For production use, import Draggable from the main library.
295
+ */
296
+ class DemoDraggable {
297
+ private element: HTMLElement | null;
298
+ private isDragging = false;
299
+ private startX = 0;
300
+ private startY = 0;
301
+ private onDrag: DragCallback | undefined;
302
+ private boundRect: DOMRect | undefined;
303
+
304
+ constructor(elementId: string, onDrag?: DragCallback) {
305
+ this.element = document.getElementById(elementId);
306
+ this.onDrag = onDrag;
307
+
308
+ if (this.element?.parentElement) {
309
+ this.boundRect = this.element.parentElement.getBoundingClientRect();
310
+ this.attachEventListeners();
311
+ }
312
+ }
313
+
314
+ private attachEventListeners(): void {
315
+ if (!this.element) return;
316
+
317
+ this.element.addEventListener('mousedown', this.startDrag.bind(this));
318
+ this.element.addEventListener('touchstart', this.startDrag.bind(this), { passive: false });
319
+ document.addEventListener('mouseup', this.stopDrag.bind(this));
320
+ document.addEventListener('touchend', this.stopDrag.bind(this));
321
+ document.addEventListener('mousemove', this.drag.bind(this));
322
+ document.addEventListener('touchmove', this.drag.bind(this), { passive: false });
323
+ }
324
+
325
+ private getCoords(event: MouseEvent | TouchEvent): { clientX: number; clientY: number } {
326
+ if ('touches' in event && event.touches.length > 0) {
327
+ return { clientX: event.touches[0].clientX, clientY: event.touches[0].clientY };
328
+ }
329
+ return { clientX: (event as MouseEvent).clientX, clientY: (event as MouseEvent).clientY };
330
+ }
331
+
332
+ private startDrag(event: MouseEvent | TouchEvent): void {
333
+ if (!this.element) return;
334
+ event.preventDefault();
335
+ const coords = this.getCoords(event);
336
+ this.isDragging = true;
337
+ this.startX = coords.clientX - this.element.offsetLeft;
338
+ this.startY = coords.clientY - this.element.offsetTop;
339
+ this.onDrag?.('start', this.element.id, coords.clientX, coords.clientY);
340
+ }
341
+
342
+ private stopDrag(event: MouseEvent | TouchEvent): void {
343
+ if (this.isDragging && this.element) {
344
+ this.isDragging = false;
345
+ const coords = this.getCoords(event);
346
+ this.onDrag?.('end', this.element.id, coords.clientX || 0, coords.clientY || 0);
347
+ }
348
+ }
349
+
350
+ private drag(event: MouseEvent | TouchEvent): void {
351
+ if (!this.isDragging || !this.element?.parentElement) return;
352
+ event.preventDefault();
353
+
354
+ const coords = this.getCoords(event);
355
+ const container = this.element.parentElement.getBoundingClientRect();
356
+
357
+ let newX = coords.clientX - this.startX;
358
+ let newY = coords.clientY - this.startY;
359
+
360
+ newX = Math.max(0, Math.min(newX, container.width - this.element.offsetWidth));
361
+ newY = Math.max(0, Math.min(newY, container.height - this.element.offsetHeight));
362
+
363
+ this.element.style.left = `${newX}px`;
364
+ this.element.style.top = `${newY}px`;
365
+ this.element.style.right = 'auto';
366
+ this.element.style.bottom = 'auto';
367
+ this.element.style.transform = 'none';
368
+
369
+ this.onDrag?.('drag', this.element.id, Math.round(newX), Math.round(newY));
370
+ }
371
+ }
372
+
373
+
374
+ // -----------------------------------------------------------------------------
375
+ // Demo: Virtual Keyboard
376
+ // -----------------------------------------------------------------------------
377
+
378
+ /**
379
+ * Demo virtual keyboard with customizable layouts.
380
+ */
381
+ class DemoKeyboard {
382
+ private layouts: KeyboardLayout = {
383
+ default: [
384
+ ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'],
385
+ ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'],
386
+ ['⇧', 'z', 'x', 'c', 'v', 'b', 'n', 'm', '⌫'],
387
+ ['123', ' ', '.', '↵']
388
+ ],
389
+ shift: [
390
+ ['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'],
391
+ ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L'],
392
+ ['⇧', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '⌫'],
393
+ ['123', ' ', '.', '↵']
394
+ ],
395
+ special: [
396
+ ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],
397
+ ['@', '#', '$', '%', '&', '*', '-', '+', '='],
398
+ ['!', '"', "'", ':', ';', '/', '?', '⌫'],
399
+ ['ABC', ' ', '.', '↵']
400
+ ]
401
+ };
402
+
403
+ private currentMode: keyof KeyboardLayout = 'default';
404
+ private stats = { chars: 0, words: 0, keys: 0 };
405
+ private input: HTMLInputElement | null;
406
+ private container: HTMLElement | null;
407
+
408
+ constructor(inputId: string, containerId: string) {
409
+ this.input = document.getElementById(inputId) as HTMLInputElement;
410
+ this.container = document.getElementById(containerId);
411
+ this.render();
412
+ }
413
+
414
+ private render(): void {
415
+ if (!this.container) return;
416
+
417
+ const layout = this.layouts[this.currentMode];
418
+ this.container.innerHTML = layout.map(row =>
419
+ `<div class="keyboard-row">${row.map(key => {
420
+ let cls = 'key';
421
+ if (key === ' ') cls += ' key--space';
422
+ if (key === '⇧') cls += ' key--shift';
423
+ if (key === '⌫') cls += ' key--backspace';
424
+ if (key === '↵') cls += ' key--enter';
425
+ if (key === '123' || key === 'ABC') cls += ' key--mode';
426
+ return `<button class="${cls}" data-key="${key}">${key === ' ' ? 'space' : key}</button>`;
427
+ }).join('')}</div>`
428
+ ).join('');
429
+
430
+ this.container.querySelectorAll<HTMLButtonElement>('.key').forEach(btn => {
431
+ btn.addEventListener('click', () => this.handleKey(btn.dataset.key ?? ''));
432
+ });
433
+ }
434
+
435
+ private handleKey(key: string): void {
436
+ if (!this.input) return;
437
+
438
+ this.stats.keys++;
439
+
440
+ if (key === '⌫') {
441
+ this.input.value = this.input.value.slice(0, -1);
442
+ } else if (key === '↵') {
443
+ this.input.value += '\n';
444
+ } else if (key === '⇧') {
445
+ this.switchMode(this.currentMode === 'shift' ? 'default' : 'shift');
446
+ return;
447
+ } else if (key === '123') {
448
+ this.switchMode('special');
449
+ return;
450
+ } else if (key === 'ABC') {
451
+ this.switchMode('default');
452
+ return;
453
+ } else {
454
+ this.input.value += key;
455
+ this.stats.chars++;
456
+ }
457
+
458
+ this.stats.words = this.input.value.trim().split(/\s+/).filter(w => w).length;
459
+ this.updateStats();
460
+ }
461
+
462
+ switchMode(mode: keyof KeyboardLayout): void {
463
+ this.currentMode = mode;
464
+ this.render();
465
+ document.querySelectorAll<HTMLButtonElement>('.mode-btn').forEach(btn => {
466
+ btn.classList.toggle('active',
467
+ (mode === 'default' && btn.textContent === 'ABC') ||
468
+ (mode === 'shift' && btn.textContent?.includes('SHIFT')) ||
469
+ (mode === 'special' && btn.textContent === '123')
470
+ );
471
+ });
472
+ }
473
+
474
+ private updateStats(): void {
475
+ const charEl = document.getElementById('charCount');
476
+ const wordEl = document.getElementById('wordCount');
477
+ const keyEl = document.getElementById('keypressCount');
478
+ if (charEl) charEl.textContent = String(this.stats.chars);
479
+ if (wordEl) wordEl.textContent = String(this.stats.words);
480
+ if (keyEl) keyEl.textContent = String(this.stats.keys);
481
+ }
482
+
483
+ getStats(): typeof this.stats {
484
+ return { ...this.stats };
485
+ }
486
+ }
487
+
488
+
489
+ // -----------------------------------------------------------------------------
490
+ // Demo: Gesture Handler
491
+ // -----------------------------------------------------------------------------
492
+
493
+ /**
494
+ * Demo gesture handler for touch and mouse interactions.
495
+ */
496
+ class DemoGesture {
497
+ private element: HTMLElement | null;
498
+ private stats: GestureStats = { taps: 0, swipes: 0, pinches: 0 };
499
+ private startX = 0;
500
+ private startY = 0;
501
+ private startTime = 0;
502
+ private isDragging = false;
503
+
504
+ constructor(elementId: string) {
505
+ this.element = document.getElementById(elementId);
506
+ if (this.element) {
507
+ this.attachEventListeners();
508
+ }
509
+ }
510
+
511
+ private attachEventListeners(): void {
512
+ if (!this.element) return;
513
+
514
+ // Mouse events
515
+ this.element.addEventListener('mousedown', (e) => this.handleStart(e.clientX, e.clientY));
516
+ document.addEventListener('mouseup', (e) => this.handleEnd(e.clientX, e.clientY));
517
+
518
+ // Touch events
519
+ this.element.addEventListener('touchstart', (e) => {
520
+ e.preventDefault();
521
+ if (e.touches.length === 1) {
522
+ this.handleStart(e.touches[0].clientX, e.touches[0].clientY);
523
+ } else if (e.touches.length === 2) {
524
+ this.handlePinch();
525
+ }
526
+ });
527
+
528
+ this.element.addEventListener('touchend', (e) => {
529
+ if (e.changedTouches.length === 1) {
530
+ this.handleEnd(e.changedTouches[0].clientX, e.changedTouches[0].clientY);
531
+ }
532
+ });
533
+ }
534
+
535
+ private handleStart(x: number, y: number): void {
536
+ this.startX = x;
537
+ this.startY = y;
538
+ this.startTime = Date.now();
539
+ this.isDragging = true;
540
+ }
541
+
542
+ private handleEnd(x: number, y: number): void {
543
+ if (!this.isDragging) return;
544
+ this.isDragging = false;
545
+
546
+ const dx = x - this.startX;
547
+ const dy = y - this.startY;
548
+ const dist = Math.sqrt(dx * dx + dy * dy);
549
+ const duration = Date.now() - this.startTime;
550
+
551
+ if (dist < 10 && duration < 300) {
552
+ this.handleTap();
553
+ } else if (dist > 50) {
554
+ const direction = this.getSwipeDirection(dx, dy);
555
+ this.handleSwipe(direction, dx, dy);
556
+ }
557
+ }
558
+
559
+ private getSwipeDirection(dx: number, dy: number): SwipeDirection {
560
+ if (Math.abs(dx) > Math.abs(dy)) {
561
+ return dx > 0 ? 'right' : 'left';
562
+ }
563
+ return dy > 0 ? 'down' : 'up';
564
+ }
565
+
566
+ private handleTap(): void {
567
+ this.stats.taps++;
568
+ this.updateUI('tap');
569
+ }
570
+
571
+ private handleSwipe(direction: SwipeDirection, _dx: number, _dy: number): void {
572
+ this.stats.swipes++;
573
+ this.updateUI('swipe', direction);
574
+ }
575
+
576
+ private handlePinch(): void {
577
+ this.stats.pinches++;
578
+ this.updateUI('pinch');
579
+ }
580
+
581
+ private updateUI(type: string, direction?: SwipeDirection): void {
582
+ const tapCount = document.getElementById('tapCount');
583
+ const swipeCount = document.getElementById('swipeCount');
584
+ const pinchCount = document.getElementById('pinchCount');
585
+ const lastDirection = document.getElementById('lastDirection');
586
+
587
+ if (tapCount) tapCount.textContent = String(this.stats.taps);
588
+ if (swipeCount) swipeCount.textContent = String(this.stats.swipes);
589
+ if (pinchCount) pinchCount.textContent = String(this.stats.pinches);
590
+ if (direction && lastDirection) lastDirection.textContent = direction;
591
+
592
+ // Show feedback
593
+ const feedback = document.getElementById('gestureFeedback');
594
+ if (feedback) {
595
+ feedback.textContent = type === 'swipe' ? `Swiped ${direction}!` : `${type.charAt(0).toUpperCase() + type.slice(1)} detected!`;
596
+ feedback.classList.add('visible');
597
+ setTimeout(() => feedback.classList.remove('visible'), 1500);
598
+ }
599
+
600
+ // Show direction indicator
601
+ if (direction) {
602
+ this.showDirectionIndicator(direction);
603
+ }
604
+ }
605
+
606
+ private showDirectionIndicator(direction: SwipeDirection): void {
607
+ document.querySelectorAll('.direction-indicator').forEach(el => el.classList.remove('active'));
608
+ const indicator = document.getElementById(`dir${direction.charAt(0).toUpperCase() + direction.slice(1)}`);
609
+ if (indicator) {
610
+ indicator.classList.add('active');
611
+ setTimeout(() => indicator.classList.remove('active'), 300);
612
+ }
613
+ }
614
+
615
+ resetStats(): void {
616
+ this.stats = { taps: 0, swipes: 0, pinches: 0 };
617
+ this.updateUI('reset');
618
+ const lastDirection = document.getElementById('lastDirection');
619
+ if (lastDirection) lastDirection.textContent = '—';
620
+ }
621
+ }
622
+
623
+
624
+ // -----------------------------------------------------------------------------
625
+ // Demo: Screensaver
626
+ // -----------------------------------------------------------------------------
627
+
628
+ /**
629
+ * Demo screensaver with inactivity detection.
630
+ */
631
+ class DemoScreensaver {
632
+ private timeout: number;
633
+ private fadeDuration: number;
634
+ private isActive = false;
635
+ private timeoutId: ReturnType<typeof setTimeout> | null = null;
636
+ private lastActivity: number;
637
+ private eventCount = 0;
638
+
639
+ private screensaverContent: HTMLElement | null;
640
+ private placeholder: HTMLElement | null;
641
+ private statusDot: HTMLElement | null;
642
+ private statusText: HTMLElement | null;
643
+ private countdown: HTMLElement | null;
644
+ private activityLog: HTMLElement | null;
645
+
646
+ constructor(options: ScreensaverOptions = {}) {
647
+ this.timeout = options.timeout ?? 10000;
648
+ this.fadeDuration = options.fadeDuration ?? 500;
649
+ this.lastActivity = Date.now();
650
+
651
+ this.screensaverContent = document.getElementById('screensaverContent');
652
+ this.placeholder = document.getElementById('placeholder');
653
+ this.statusDot = document.getElementById('statusDot');
654
+ this.statusText = document.getElementById('statusText');
655
+ this.countdown = document.getElementById('countdown');
656
+ this.activityLog = document.getElementById('activityLog');
657
+
658
+ this.setupEventListeners();
659
+ this.startTimeout();
660
+ this.updateCountdown();
661
+ }
662
+
663
+ private setupEventListeners(): void {
664
+ ['mousemove', 'mousedown', 'keydown', 'touchstart', 'scroll'].forEach(event => {
665
+ document.addEventListener(event, () => this.resetTimeout(), { passive: true });
666
+ });
667
+ }
668
+
669
+ log(message: string): void {
670
+ if (!this.activityLog) return;
671
+ const time = new Date().toLocaleTimeString();
672
+ const entry = document.createElement('div');
673
+ entry.className = 'entry';
674
+ entry.textContent = `[${time}] ${message}`;
675
+ this.activityLog.appendChild(entry);
676
+ this.activityLog.scrollTop = this.activityLog.scrollHeight;
677
+ }
678
+
679
+ resetTimeout(): void {
680
+ if (this.isActive) this.deactivate();
681
+ this.lastActivity = Date.now();
682
+ this.eventCount++;
683
+ const eventCountEl = document.getElementById('eventCount');
684
+ if (eventCountEl) eventCountEl.textContent = String(this.eventCount);
685
+ if (this.timeoutId) clearTimeout(this.timeoutId);
686
+ this.startTimeout();
687
+ }
688
+
689
+ private startTimeout(): void {
690
+ this.timeoutId = setTimeout(() => this.activate(), this.timeout);
691
+ }
692
+
693
+ private updateCountdown(): void {
694
+ setInterval(() => {
695
+ if (!this.isActive && this.countdown) {
696
+ const elapsed = Date.now() - this.lastActivity;
697
+ const remaining = Math.max(0, Math.ceil((this.timeout - elapsed) / 1000));
698
+ this.countdown.textContent = `${remaining}s`;
699
+ }
700
+ }, 100);
701
+ }
702
+
703
+ activate(): void {
704
+ this.isActive = true;
705
+ this.screensaverContent?.classList.add('active');
706
+ if (this.placeholder) this.placeholder.style.opacity = '0';
707
+ this.statusDot?.classList.add('screensaver-active');
708
+ if (this.statusText) this.statusText.textContent = 'Screensaver active';
709
+ if (this.countdown) this.countdown.textContent = '💤';
710
+ this.log('Screensaver activated');
711
+ }
712
+
713
+ deactivate(): void {
714
+ this.isActive = false;
715
+ this.screensaverContent?.classList.remove('active');
716
+ if (this.placeholder) this.placeholder.style.opacity = '1';
717
+ this.statusDot?.classList.remove('screensaver-active');
718
+ if (this.statusText) this.statusText.textContent = 'Monitoring activity';
719
+ this.log('Screensaver deactivated');
720
+ }
721
+
722
+ setTimeout(timeout: number): void {
723
+ this.timeout = timeout;
724
+ this.resetTimeout();
725
+ }
726
+
727
+ setFadeDuration(duration: number): void {
728
+ this.fadeDuration = duration;
729
+ if (this.screensaverContent) {
730
+ this.screensaverContent.style.transition = `opacity ${duration}ms ease`;
731
+ }
732
+ }
733
+
734
+ getEventCount(): number {
735
+ return this.eventCount;
736
+ }
737
+
738
+ resetEventCount(): void {
739
+ this.eventCount = 0;
740
+ const eventCountEl = document.getElementById('eventCount');
741
+ if (eventCountEl) eventCountEl.textContent = '0';
742
+ }
743
+ }
744
+
745
+
746
+ // -----------------------------------------------------------------------------
747
+ // Demo: Video Overlay
748
+ // -----------------------------------------------------------------------------
749
+
750
+ /**
751
+ * Demo video overlay with visual effects.
752
+ */
753
+ class DemoVideoOverlay {
754
+ private overlay: HTMLElement | null;
755
+ private particles: HTMLElement | null;
756
+ private isVisible = false;
757
+ private currentEffect = 'vignette';
758
+ private opacity = 1;
759
+ private fadeDuration = 300;
760
+ private blurAmount = 0;
761
+
762
+ constructor() {
763
+ this.overlay = document.getElementById('videoOverlay');
764
+ this.particles = document.getElementById('particles');
765
+
766
+ this.checkHevcSupport();
767
+ this.setupControls();
768
+ this.createParticles();
769
+ }
770
+
771
+ private checkHevcSupport(): void {
772
+ const indicator = document.getElementById('alphaIndicator');
773
+ if (!indicator) return;
774
+
775
+ const video = document.createElement('video');
776
+ const canPlayHevc = video.canPlayType('video/mp4; codecs="hvc1"') !== '';
777
+
778
+ if (canPlayHevc) {
779
+ indicator.className = 'alpha-indicator supported';
780
+ indicator.textContent = '✓ HEVC Supported';
781
+ } else {
782
+ indicator.className = 'alpha-indicator unsupported';
783
+ indicator.textContent = '✗ HEVC Not Supported';
784
+ }
785
+ }
786
+
787
+ private setupControls(): void {
788
+ document.getElementById('opacitySlider')?.addEventListener('input', (e) => {
789
+ const target = e.target as HTMLInputElement;
790
+ this.opacity = parseInt(target.value) / 100;
791
+ const valueEl = document.getElementById('opacityValue');
792
+ if (valueEl) valueEl.textContent = `${target.value}%`;
793
+ if (this.isVisible && this.overlay) this.overlay.style.opacity = String(this.opacity);
794
+ });
795
+
796
+ document.getElementById('fadeSlider')?.addEventListener('input', (e) => {
797
+ const target = e.target as HTMLInputElement;
798
+ this.fadeDuration = parseInt(target.value);
799
+ const valueEl = document.getElementById('fadeValue');
800
+ if (valueEl) valueEl.textContent = target.value;
801
+ if (this.overlay) this.overlay.style.transition = `opacity ${this.fadeDuration}ms ease`;
802
+ });
803
+
804
+ document.getElementById('blurSlider')?.addEventListener('input', (e) => {
805
+ const target = e.target as HTMLInputElement;
806
+ this.blurAmount = parseInt(target.value);
807
+ const valueEl = document.getElementById('blurValue');
808
+ if (valueEl) valueEl.textContent = target.value;
809
+ if (this.overlay) {
810
+ this.overlay.style.backdropFilter = this.blurAmount > 0 ? `blur(${this.blurAmount}px)` : 'none';
811
+ }
812
+ });
813
+
814
+ document.querySelectorAll<HTMLButtonElement>('.effect-btn').forEach(btn => {
815
+ btn.addEventListener('click', () => {
816
+ document.querySelectorAll('.effect-btn').forEach(b => b.classList.remove('active'));
817
+ btn.classList.add('active');
818
+ this.setEffect(btn.dataset.effect ?? 'none');
819
+ });
820
+ });
821
+
822
+ document.getElementById('toggleOverlay')?.addEventListener('click', () => this.toggle());
823
+ document.getElementById('fadeInOut')?.addEventListener('click', () => this.fadeInOut());
824
+ document.getElementById('resetDemo')?.addEventListener('click', () => this.reset());
825
+ }
826
+
827
+ private createParticles(): void {
828
+ if (!this.particles) return;
829
+
830
+ for (let i = 0; i < 30; i++) {
831
+ const particle = document.createElement('div');
832
+ particle.className = 'particle';
833
+ particle.style.left = `${Math.random() * 100}%`;
834
+ particle.style.top = `${Math.random() * 100}%`;
835
+ particle.style.animationDelay = `${Math.random() * 3}s`;
836
+ particle.style.animationDuration = `${2 + Math.random() * 2}s`;
837
+ this.particles.appendChild(particle);
838
+ }
839
+ }
840
+
841
+ setEffect(effect: string): void {
842
+ this.currentEffect = effect;
843
+ const overlayEffect = this.overlay?.querySelector<HTMLElement>('.overlay-effect');
844
+ if (!overlayEffect || !this.particles) return;
845
+
846
+ switch (effect) {
847
+ case 'none':
848
+ overlayEffect.style.background = 'transparent';
849
+ this.particles.style.display = 'none';
850
+ break;
851
+ case 'vignette':
852
+ overlayEffect.style.background = 'radial-gradient(circle at center, transparent 30%, rgba(0, 0, 0, 0.8) 100%)';
853
+ this.particles.style.display = 'none';
854
+ break;
855
+ case 'particles':
856
+ overlayEffect.style.background = 'transparent';
857
+ this.particles.style.display = 'block';
858
+ break;
859
+ case 'gradient':
860
+ overlayEffect.style.background = 'linear-gradient(to bottom, rgba(102, 126, 234, 0.3), rgba(118, 75, 162, 0.3))';
861
+ this.particles.style.display = 'none';
862
+ break;
863
+ case 'scanlines':
864
+ overlayEffect.style.background = 'repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.1) 1px, transparent 1px, transparent 2px)';
865
+ this.particles.style.display = 'none';
866
+ break;
867
+ }
868
+ }
869
+
870
+ toggle(): void {
871
+ this.isVisible = !this.isVisible;
872
+ this.overlay?.classList.toggle('visible', this.isVisible);
873
+ if (this.isVisible && this.overlay) this.overlay.style.opacity = String(this.opacity);
874
+ const toggleBtn = document.getElementById('toggleOverlay');
875
+ if (toggleBtn) toggleBtn.textContent = this.isVisible ? 'Hide Overlay' : 'Show Overlay';
876
+ }
877
+
878
+ fadeInOut(): void {
879
+ if (!this.isVisible) {
880
+ this.toggle();
881
+ setTimeout(() => this.toggle(), this.fadeDuration * 3);
882
+ }
883
+ }
884
+
885
+ reset(): void {
886
+ this.isVisible = false;
887
+ this.overlay?.classList.remove('visible');
888
+ const toggleBtn = document.getElementById('toggleOverlay');
889
+ if (toggleBtn) toggleBtn.textContent = 'Show Overlay';
890
+
891
+ const opacitySlider = document.getElementById('opacitySlider') as HTMLInputElement;
892
+ const opacityValue = document.getElementById('opacityValue');
893
+ const fadeSlider = document.getElementById('fadeSlider') as HTMLInputElement;
894
+ const fadeValue = document.getElementById('fadeValue');
895
+ const blurSlider = document.getElementById('blurSlider') as HTMLInputElement;
896
+ const blurValue = document.getElementById('blurValue');
897
+
898
+ if (opacitySlider) opacitySlider.value = '100';
899
+ if (opacityValue) opacityValue.textContent = '100%';
900
+ if (fadeSlider) fadeSlider.value = '300';
901
+ if (fadeValue) fadeValue.textContent = '300';
902
+ if (blurSlider) blurSlider.value = '0';
903
+ if (blurValue) blurValue.textContent = '0';
904
+
905
+ this.opacity = 1;
906
+ this.fadeDuration = 300;
907
+ this.blurAmount = 0;
908
+
909
+ if (this.overlay) {
910
+ this.overlay.style.transition = 'opacity 300ms ease';
911
+ this.overlay.style.backdropFilter = 'none';
912
+ }
913
+ }
914
+ }
915
+
916
+
917
+ // -----------------------------------------------------------------------------
918
+ // Demo Page Initializers
919
+ // -----------------------------------------------------------------------------
920
+
921
+ /**
922
+ * Initialize the draggable demo page.
923
+ */
924
+ function initDraggableDemo(): void {
925
+ const logOutput = document.getElementById('logOutput');
926
+
927
+ function log(message: string): void {
928
+ if (!logOutput) return;
929
+ const time = new Date().toLocaleTimeString();
930
+ const entry = document.createElement('div');
931
+ entry.className = 'log-entry';
932
+ entry.innerHTML = `<span class="timestamp">[${time}]</span> ${message}`;
933
+ logOutput.appendChild(entry);
934
+ logOutput.scrollTop = logOutput.scrollHeight;
935
+ }
936
+
937
+ function handleDrag(type: DragEventType, id: string, x: number, y: number): void {
938
+ if (type === 'start') {
939
+ log(`<strong>${id}</strong>: Drag started`);
940
+ } else if (type === 'end') {
941
+ log(`<strong>${id}</strong>: Drag ended`);
942
+ } else {
943
+ log(`<strong>${id}</strong>: Position (${x}, ${y})`);
944
+ }
945
+ }
946
+
947
+ // Initialize draggable boxes
948
+ new DemoDraggable('box1', handleDrag);
949
+ new DemoDraggable('box2', handleDrag);
950
+ new DemoDraggable('box3', handleDrag);
951
+
952
+ // Global functions for buttons
953
+ (window as unknown as Record<string, () => void>).resetPositions = () => {
954
+ const box1 = document.getElementById('box1');
955
+ const box2 = document.getElementById('box2');
956
+ const box3 = document.getElementById('box3');
957
+ if (box1) box1.style.cssText = 'top: 50px; left: 50px;';
958
+ if (box2) box2.style.cssText = 'top: 50px; right: 50px;';
959
+ if (box3) box3.style.cssText = 'bottom: 50px; left: 50%; transform: translateX(-50%);';
960
+ log('Positions reset');
961
+ };
962
+
963
+ (window as unknown as Record<string, () => void>).clearLog = () => {
964
+ if (logOutput) {
965
+ logOutput.innerHTML = '<div class="log-entry"><span class="timestamp">[--:--:--]</span> Log cleared</div>';
966
+ }
967
+ };
968
+
969
+ log('Draggable demo initialized. Try dragging the boxes!');
970
+ }
971
+
972
+ /**
973
+ * Initialize the keyboard demo page.
974
+ */
975
+ function initKeyboardDemo(): void {
976
+ const keyboard = new DemoKeyboard('keyboardInput', 'keyboard');
977
+
978
+ (window as unknown as Record<string, (mode: string) => void>).switchMode = (mode: string) => {
979
+ keyboard.switchMode(mode as keyof KeyboardLayout);
980
+ };
981
+ }
982
+
983
+ /**
984
+ * Initialize the gesture demo page.
985
+ */
986
+ function initGestureDemo(): void {
987
+ const gesture = new DemoGesture('gestureArea');
988
+
989
+ function log(type: string, details: string): void {
990
+ const gestureLog = document.getElementById('gestureLog');
991
+ if (!gestureLog) return;
992
+ const time = new Date().toLocaleTimeString();
993
+ const entry = document.createElement('div');
994
+ entry.className = 'entry';
995
+ entry.innerHTML = `<span class="timestamp">${time}</span><span class="type">${type}</span><span class="details">${details}</span>`;
996
+ gestureLog.appendChild(entry);
997
+ gestureLog.scrollTop = gestureLog.scrollHeight;
998
+ }
999
+
1000
+ (window as unknown as Record<string, () => void>).resetStats = () => {
1001
+ gesture.resetStats();
1002
+ log('RESET', 'Stats cleared');
1003
+ };
1004
+
1005
+ (window as unknown as Record<string, () => void>).clearLog = () => {
1006
+ const gestureLog = document.getElementById('gestureLog');
1007
+ if (gestureLog) {
1008
+ gestureLog.innerHTML = '<div class="entry"><span class="timestamp">--:--:--</span><span class="type">INIT</span><span class="details">Log cleared</span></div>';
1009
+ }
1010
+ };
1011
+
1012
+ log('READY', 'Gesture handler initialized');
1013
+ }
1014
+
1015
+ /**
1016
+ * Initialize the screensaver demo page.
1017
+ */
1018
+ function initScreensaverDemo(): void {
1019
+ const screensaver = new DemoScreensaver({ timeout: 10000, fadeDuration: 500 });
1020
+
1021
+ document.getElementById('timeoutSlider')?.addEventListener('input', (e) => {
1022
+ const target = e.target as HTMLInputElement;
1023
+ const value = parseInt(target.value);
1024
+ const valueEl = document.getElementById('timeoutValue');
1025
+ if (valueEl) valueEl.textContent = String(value);
1026
+ screensaver.setTimeout(value * 1000);
1027
+ screensaver.log(`Timeout set to ${value}s`);
1028
+ });
1029
+
1030
+ document.getElementById('fadeSlider')?.addEventListener('input', (e) => {
1031
+ const target = e.target as HTMLInputElement;
1032
+ const value = parseInt(target.value);
1033
+ const valueEl = document.getElementById('fadeValue');
1034
+ if (valueEl) valueEl.textContent = String(value);
1035
+ screensaver.setFadeDuration(value);
1036
+ screensaver.log(`Fade duration set to ${value}ms`);
1037
+ });
1038
+
1039
+ (window as unknown as Record<string, () => void>).forceActivate = () => screensaver.activate();
1040
+ (window as unknown as Record<string, () => void>).forceDeactivate = () => {
1041
+ screensaver.deactivate();
1042
+ screensaver.resetTimeout();
1043
+ };
1044
+ (window as unknown as Record<string, () => void>).resetDemo = () => {
1045
+ screensaver.resetEventCount();
1046
+ const activityLog = document.getElementById('activityLog');
1047
+ if (activityLog) activityLog.innerHTML = '<div class="entry">[--:--:--] Demo reset</div>';
1048
+ screensaver.deactivate();
1049
+ screensaver.resetTimeout();
1050
+ };
1051
+ }
1052
+
1053
+ /**
1054
+ * Initialize the video overlay demo page.
1055
+ */
1056
+ function initVideoOverlayDemo(): void {
1057
+ new DemoVideoOverlay();
1058
+ }
1059
+
1060
+
1061
+ // -----------------------------------------------------------------------------
1062
+ // Auto-Detection and Initialization
1063
+ // -----------------------------------------------------------------------------
1064
+
1065
+ /**
1066
+ * Detect which demo page is loaded and initialize accordingly.
1067
+ */
1068
+ function initDemoPage(): void {
1069
+ const path = window.location.pathname;
1070
+
1071
+ if (path.includes('demo_draggable')) {
1072
+ initDraggableDemo();
1073
+ } else if (path.includes('demo_keyboard')) {
1074
+ initKeyboardDemo();
1075
+ } else if (path.includes('demo_gesture')) {
1076
+ initGestureDemo();
1077
+ } else if (path.includes('demo_screensaver')) {
1078
+ initScreensaverDemo();
1079
+ } else if (path.includes('demo_video_overlay')) {
1080
+ initVideoOverlayDemo();
1081
+ }
1082
+ }
1083
+
1084
+ // Auto-initialize demo pages
1085
+ if (document.readyState === 'loading') {
1086
+ document.addEventListener('DOMContentLoaded', initDemoPage);
1087
+ } else {
1088
+ initDemoPage();
1089
+ }
1090
+
1091
+
1092
+ // -----------------------------------------------------------------------------
1093
+ // Demo Class Exports
1094
+ // -----------------------------------------------------------------------------
1095
+
1096
+ export {
1097
+ DemoDraggable,
1098
+ DemoGesture,
1099
+ DemoKeyboard,
1100
+ DemoScreensaver,
1101
+ DemoVideoOverlay,
1102
+ initDemoPage,
1103
+ initDraggableDemo,
1104
+ initGestureDemo,
1105
+ initKeyboardDemo,
1106
+ initScreensaverDemo,
1107
+ initVideoOverlayDemo
1108
+ };