@blokkli/editor 2.0.0-alpha.13 → 2.0.0-alpha.14

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 (272) hide show
  1. package/dist/module.d.mts +1 -1
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +4003 -1162
  4. package/dist/modules/drupal/graphql/base/fragment.ParagraphsBlokkliConfigInput.graphql +31 -0
  5. package/dist/modules/drupal/graphql/base/fragment.blokkliProps.graphql +1 -0
  6. package/dist/modules/drupal/graphql/base/fragment.paragraphsBlokkliEditState.graphql +1 -0
  7. package/dist/modules/drupal/graphql/base/query.pbEntityConfig.graphql +5 -0
  8. package/dist/modules/drupal/graphql/features/transform.graphql +9 -1
  9. package/dist/modules/drupal/graphql/features/transform_host.graphql +38 -0
  10. package/dist/modules/drupal/graphql/mutations/update_host_options.graphql +15 -0
  11. package/dist/modules/drupal/index.d.mts +1 -1
  12. package/dist/modules/drupal/index.mjs +20 -7
  13. package/dist/modules/drupal/runtime/adapter/index.js +109 -4
  14. package/dist/runtime/adapter/index.d.ts +54 -1
  15. package/dist/runtime/blokkliPlugins/AddAction/index.vue +27 -3
  16. package/dist/runtime/blokkliPlugins/BlockIndicator/index.vue +65 -0
  17. package/dist/runtime/blokkliPlugins/BlockIndicator/index.vue.d.ts +26 -0
  18. package/dist/runtime/blokkliPlugins/ContextMenu/Menu/index.vue +3 -0
  19. package/dist/runtime/blokkliPlugins/ContextMenu/index.vue +3 -2
  20. package/dist/runtime/blokkliPlugins/DroppableEdit/index.vue +3 -3
  21. package/dist/runtime/blokkliPlugins/ItemDropdown/index.vue +49 -11
  22. package/dist/runtime/blokkliPlugins/ItemDropdown/index.vue.d.ts +29 -15
  23. package/dist/runtime/blokkliPlugins/Sidebar/Detached/index.vue +6 -7
  24. package/dist/runtime/blokkliPlugins/Sidebar/index.vue +2 -9
  25. package/dist/runtime/blokkliPlugins/Sidebar/index.vue.d.ts +1 -1
  26. package/dist/runtime/blokkliPlugins/ViewOption/index.vue +6 -3
  27. package/dist/runtime/blokkliPlugins/index.d.ts +8 -7
  28. package/dist/runtime/blokkliPlugins/index.js +15 -13
  29. package/dist/runtime/components/Blocks/Fragment/icon.svg +1 -1
  30. package/dist/runtime/components/BlokkliProvider.vue +1 -0
  31. package/dist/runtime/components/BlokkliProvider.vue.d.ts +1 -0
  32. package/dist/runtime/components/Edit/Actions/index.vue +39 -67
  33. package/dist/runtime/components/Edit/AddListItem/index.vue +2 -5
  34. package/dist/runtime/components/Edit/AddListItem/index.vue.d.ts +1 -1
  35. package/dist/runtime/components/Edit/AddListItemIcon/index.vue +19 -0
  36. package/dist/runtime/components/Edit/AddListItemIcon/index.vue.d.ts +15 -0
  37. package/dist/runtime/components/Edit/AppMenu/index.vue +5 -5
  38. package/dist/runtime/components/Edit/Dialog/index.vue +5 -1
  39. package/dist/runtime/components/Edit/Dialog/index.vue.d.ts +1 -1
  40. package/dist/runtime/components/Edit/DiffViewer/State.vue +276 -0
  41. package/dist/runtime/components/Edit/DiffViewer/State.vue.d.ts +16 -0
  42. package/dist/runtime/components/Edit/DragInteractions/index.vue +35 -6
  43. package/dist/runtime/components/Edit/EditProvider.vue +46 -35
  44. package/dist/runtime/components/Edit/Features/AddList/index.vue +15 -25
  45. package/dist/runtime/components/Edit/Features/Analyze/Overlay/fragment.glsl +58 -0
  46. package/dist/runtime/components/Edit/Features/Analyze/Overlay/index.vue +168 -0
  47. package/dist/runtime/components/Edit/Features/Analyze/Overlay/index.vue.d.ts +9 -0
  48. package/dist/runtime/components/Edit/Features/Analyze/Overlay/vertex.glsl +72 -0
  49. package/dist/runtime/components/Edit/Features/Analyze/Renderer.vue +159 -0
  50. package/dist/runtime/components/Edit/Features/Analyze/Renderer.vue.d.ts +7 -0
  51. package/dist/runtime/components/Edit/Features/Analyze/Results/Results.vue +100 -0
  52. package/dist/runtime/components/Edit/Features/Analyze/Results/Results.vue.d.ts +6 -0
  53. package/dist/runtime/components/Edit/Features/Analyze/Results/ResultsItem.vue +56 -0
  54. package/dist/runtime/components/Edit/Features/Analyze/Results/ResultsItem.vue.d.ts +3 -0
  55. package/dist/runtime/components/Edit/Features/Analyze/Results/ResultsItemNodes.vue +87 -0
  56. package/dist/runtime/components/Edit/Features/Analyze/Results/ResultsItemNodes.vue.d.ts +7 -0
  57. package/dist/runtime/components/Edit/Features/Analyze/Results/ResultsItemNodesTarget.vue +101 -0
  58. package/dist/runtime/components/Edit/Features/Analyze/Results/ResultsItemNodesTarget.vue.d.ts +8 -0
  59. package/dist/runtime/components/Edit/Features/Analyze/Results/Status.vue +18 -0
  60. package/dist/runtime/components/Edit/Features/Analyze/Results/Status.vue.d.ts +8 -0
  61. package/dist/runtime/components/Edit/Features/Analyze/Summary/Chart.vue +92 -0
  62. package/dist/runtime/components/Edit/Features/Analyze/Summary/Chart.vue.d.ts +17 -0
  63. package/dist/runtime/components/Edit/Features/Analyze/Summary/index.vue +77 -0
  64. package/dist/runtime/components/Edit/Features/Analyze/Summary/index.vue.d.ts +6 -0
  65. package/dist/runtime/components/Edit/Features/Analyze/analyzers/axe.d.ts +12 -0
  66. package/dist/runtime/components/Edit/Features/Analyze/analyzers/axe.js +75 -0
  67. package/dist/runtime/components/Edit/Features/Analyze/analyzers/defineAnalyzer.d.ts +4 -0
  68. package/dist/runtime/components/Edit/Features/Analyze/analyzers/defineAnalyzer.js +5 -0
  69. package/dist/runtime/components/Edit/Features/Analyze/analyzers/helpers/Context.d.ts +32 -0
  70. package/dist/runtime/components/Edit/Features/Analyze/analyzers/helpers/Context.js +45 -0
  71. package/dist/runtime/components/Edit/Features/Analyze/analyzers/helpers/collectTextElements.d.ts +5 -0
  72. package/dist/runtime/components/Edit/Features/Analyze/analyzers/helpers/collectTextElements.js +95 -0
  73. package/dist/runtime/components/Edit/Features/Analyze/analyzers/helpers/normalizeArray.d.ts +3 -0
  74. package/dist/runtime/components/Edit/Features/Analyze/analyzers/helpers/normalizeArray.js +13 -0
  75. package/dist/runtime/components/Edit/Features/Analyze/analyzers/index.d.ts +2 -0
  76. package/dist/runtime/components/Edit/Features/Analyze/analyzers/index.js +2 -0
  77. package/dist/runtime/components/Edit/Features/Analyze/analyzers/readability.d.ts +2 -0
  78. package/dist/runtime/components/Edit/Features/Analyze/analyzers/readability.js +165 -0
  79. package/dist/runtime/components/Edit/Features/Analyze/analyzers/types.d.ts +44 -0
  80. package/dist/runtime/components/Edit/Features/Analyze/analyzers/types.js +0 -0
  81. package/dist/runtime/components/Edit/Features/Analyze/helper.d.ts +5 -0
  82. package/dist/runtime/components/Edit/Features/Analyze/helper.js +28 -0
  83. package/dist/runtime/components/Edit/Features/Analyze/index.vue +44 -0
  84. package/dist/runtime/components/Edit/Features/Anchors/Renderer.vue +136 -0
  85. package/dist/runtime/components/Edit/Features/Anchors/index.vue +32 -0
  86. package/dist/runtime/components/Edit/Features/Anchors/index.vue.d.ts +2 -0
  87. package/dist/runtime/components/Edit/Features/Artboard/Overview/index.vue +25 -13
  88. package/dist/runtime/components/Edit/Features/Artboard/Renderer.vue +296 -0
  89. package/dist/runtime/components/Edit/Features/Artboard/Renderer.vue.d.ts +7 -0
  90. package/dist/runtime/components/Edit/Features/Artboard/index.vue +10 -245
  91. package/dist/runtime/components/Edit/Features/Assistant/index.vue +3 -2
  92. package/dist/runtime/components/Edit/Features/BlockAddList/index.vue +4 -4
  93. package/dist/runtime/components/Edit/Features/Clipboard/index.vue +161 -28
  94. package/dist/runtime/components/Edit/Features/CommandPalette/Palette/Group/index.vue +16 -4
  95. package/dist/runtime/components/Edit/Features/CommandPalette/Palette/Group/index.vue.d.ts +0 -1
  96. package/dist/runtime/components/Edit/Features/CommandPalette/Palette/index.vue +4 -53
  97. package/dist/runtime/components/Edit/Features/CommandPalette/index.vue +3 -2
  98. package/dist/runtime/components/Edit/Features/Conversions/index.vue +12 -14
  99. package/dist/runtime/components/Edit/Features/Debug/Viewport/index.vue +14 -0
  100. package/dist/runtime/components/Edit/Features/Debug/index.vue +27 -24
  101. package/dist/runtime/components/Edit/Features/Diff/DiffView/index.vue +13 -190
  102. package/dist/runtime/components/Edit/Features/Diff/index.vue +2 -2
  103. package/dist/runtime/components/Edit/Features/DraggingOverlay/DragItems/index.vue +4 -4
  104. package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/fragment.glsl +1 -1
  105. package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/index.vue +35 -71
  106. package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/vertex.glsl +1 -1
  107. package/dist/runtime/components/Edit/Features/DraggingOverlay/index.vue +62 -48
  108. package/dist/runtime/components/Edit/Features/EditForm/Frame/index.vue +3 -3
  109. package/dist/runtime/components/Edit/Features/EditForm/index.vue +3 -3
  110. package/dist/runtime/components/Edit/Features/EditableField/index.vue +6 -2
  111. package/dist/runtime/components/Edit/Features/EditableMask/index.vue +3 -20
  112. package/dist/runtime/components/Edit/Features/Fragments/index.vue +3 -2
  113. package/dist/runtime/components/Edit/Features/History/index.vue +35 -12
  114. package/dist/runtime/components/Edit/Features/ImportExisting/Dialog/index.vue +6 -2
  115. package/dist/runtime/components/Edit/Features/ImportExisting/index.vue +3 -2
  116. package/dist/runtime/components/Edit/Features/Library/index.vue +11 -9
  117. package/dist/runtime/components/Edit/Features/MediaLibrary/Library/index.vue +5 -8
  118. package/dist/runtime/components/Edit/Features/MultiSelect/Overlay/fragment.glsl +1 -1
  119. package/dist/runtime/components/Edit/Features/MultiSelect/Overlay/index.vue +9 -4
  120. package/dist/runtime/components/Edit/Features/MultiSelect/Overlay/vertex.glsl +1 -1
  121. package/dist/runtime/components/Edit/Features/MultiSelect/index.vue +8 -14
  122. package/dist/runtime/components/Edit/Features/Options/Form/Checkbox/index.vue +3 -2
  123. package/dist/runtime/components/Edit/Features/Options/Form/Checkbox/index.vue.d.ts +2 -0
  124. package/dist/runtime/components/Edit/Features/Options/Form/Item.vue +9 -3
  125. package/dist/runtime/components/Edit/Features/Options/Form/Item.vue.d.ts +0 -1
  126. package/dist/runtime/components/Edit/Features/Options/Form/Radios/index.vue +37 -19
  127. package/dist/runtime/components/Edit/Features/Options/Form/Radios/index.vue.d.ts +8 -2
  128. package/dist/runtime/components/Edit/Features/Options/Form/index.vue +81 -37
  129. package/dist/runtime/components/Edit/Features/Options/Form/index.vue.d.ts +5 -5
  130. package/dist/runtime/components/Edit/Features/Options/index.vue +30 -6
  131. package/dist/runtime/components/Edit/Features/PreviewGrant/index.vue +3 -3
  132. package/dist/runtime/components/Edit/Features/Publish/Dialog/index.vue +1 -0
  133. package/dist/runtime/components/Edit/Features/Publish/index.vue +3 -2
  134. package/dist/runtime/components/Edit/Features/Revert/index.vue +3 -3
  135. package/dist/runtime/components/Edit/Features/Search/index.vue +3 -2
  136. package/dist/runtime/components/Edit/Features/Selection/AddButtons/AddButtonsField.vue +54 -0
  137. package/dist/runtime/components/Edit/Features/Selection/AddButtons/AddButtonsField.vue.d.ts +14 -0
  138. package/dist/runtime/components/Edit/Features/Selection/AddButtons/Overlay/index.vue +120 -0
  139. package/dist/runtime/components/Edit/Features/Selection/AddButtons/Overlay/index.vue.d.ts +15 -0
  140. package/dist/runtime/components/Edit/Features/Selection/AddButtons/index.vue +459 -0
  141. package/dist/runtime/components/Edit/Features/Selection/AddButtons/index.vue.d.ts +6 -0
  142. package/dist/runtime/components/Edit/Features/Selection/Overlay/fragment.glsl +14 -9
  143. package/dist/runtime/components/Edit/Features/Selection/Overlay/index.vue +32 -11
  144. package/dist/runtime/components/Edit/Features/Selection/Overlay/vertex.glsl +1 -1
  145. package/dist/runtime/components/Edit/Features/Selection/index.vue +76 -7
  146. package/dist/runtime/components/Edit/Features/Settings/Dialog/FeatureSetting/index.vue +12 -17
  147. package/dist/runtime/components/Edit/Features/Settings/index.vue +11 -25
  148. package/dist/runtime/components/Edit/Features/Theme/Color/index.vue +5 -1
  149. package/dist/runtime/components/Edit/Features/Theme/index.vue +2 -1
  150. package/dist/runtime/components/Edit/Features/TouchActionBar/index.vue +3 -2
  151. package/dist/runtime/components/Edit/Features/Transform/Dialog/index.vue +198 -0
  152. package/dist/runtime/components/Edit/Features/Transform/Dialog/index.vue.d.ts +13 -0
  153. package/dist/runtime/components/Edit/Features/Transform/index.vue +155 -44
  154. package/dist/runtime/components/Edit/Form/Radio/index.vue +33 -0
  155. package/dist/runtime/components/Edit/Form/Radio/index.vue.d.ts +20 -0
  156. package/dist/runtime/components/Edit/Form/RadioTabs/index.vue +37 -0
  157. package/dist/runtime/components/Edit/Form/RadioTabs/index.vue.d.ts +22 -0
  158. package/dist/runtime/components/Edit/Form/Select/index.vue +29 -0
  159. package/dist/runtime/components/Edit/Form/Select/index.vue.d.ts +20 -0
  160. package/dist/runtime/components/Edit/Form/Text/index.vue +33 -0
  161. package/dist/runtime/components/Edit/Form/Text/index.vue.d.ts +19 -0
  162. package/dist/runtime/components/Edit/Form/Textarea/index.vue +13 -6
  163. package/dist/runtime/components/Edit/Form/Textarea/index.vue.d.ts +4 -0
  164. package/dist/runtime/components/Edit/FormOverlay/index.vue +1 -1
  165. package/dist/runtime/components/Edit/Indicators/index.vue +123 -0
  166. package/dist/runtime/components/Edit/Indicators/index.vue.d.ts +2 -0
  167. package/dist/runtime/components/Edit/ItemIcon/index.vue +2 -1
  168. package/dist/runtime/components/Edit/Konami/Game/PixelGrid.vue +66 -0
  169. package/dist/runtime/components/Edit/Konami/Game/PixelGrid.vue.d.ts +7 -0
  170. package/dist/runtime/components/Edit/Konami/Game/blokkli.png +0 -0
  171. package/dist/runtime/components/Edit/Konami/Game/charmap.d.ts +2 -0
  172. package/dist/runtime/components/Edit/Konami/Game/charmap.js +168 -0
  173. package/dist/runtime/components/Edit/Konami/Game/index.vue +745 -0
  174. package/dist/runtime/components/Edit/Konami/Game/index.vue.d.ts +6 -0
  175. package/dist/runtime/components/Edit/Konami/Game/textRendering.d.ts +8 -0
  176. package/dist/runtime/components/Edit/Konami/Game/textRendering.js +138 -0
  177. package/dist/runtime/components/Edit/Konami/Game/useIconRendering.d.ts +9 -0
  178. package/dist/runtime/components/Edit/Konami/Game/useIconRendering.js +130 -0
  179. package/dist/runtime/components/Edit/Konami/index.vue +44 -0
  180. package/dist/runtime/components/Edit/Konami/index.vue.d.ts +2 -0
  181. package/dist/runtime/components/Edit/Loading/index.vue +6 -2
  182. package/dist/runtime/components/Edit/Loading/index.vue.d.ts +2 -0
  183. package/dist/runtime/components/Edit/Messages/index.vue +8 -3
  184. package/dist/runtime/components/Edit/PluginConfigForm/Checkbox/index.vue +17 -0
  185. package/dist/runtime/components/Edit/PluginConfigForm/Checkbox/index.vue.d.ts +11 -0
  186. package/dist/runtime/components/Edit/PluginConfigForm/Options/index.vue +37 -0
  187. package/dist/runtime/components/Edit/PluginConfigForm/Options/index.vue.d.ts +11 -0
  188. package/dist/runtime/components/Edit/PluginConfigForm/Text/index.vue +43 -0
  189. package/dist/runtime/components/Edit/PluginConfigForm/Text/index.vue.d.ts +11 -0
  190. package/dist/runtime/components/Edit/PluginConfigForm/index.vue +57 -0
  191. package/dist/runtime/components/Edit/PluginConfigForm/index.vue.d.ts +16 -0
  192. package/dist/runtime/components/Edit/PreviewProvider.vue +3 -4
  193. package/dist/runtime/components/Edit/RelativeTime/index.vue +3 -2
  194. package/dist/runtime/components/Edit/ShortcutIndicator/index.vue +8 -3
  195. package/dist/runtime/components/Edit/SystemRequirements/index.vue +3 -3
  196. package/dist/runtime/components/Edit/Toolbar/index.vue +3 -2
  197. package/dist/runtime/components/Edit/Transition/index.vue +41 -0
  198. package/dist/runtime/components/Edit/Transition/index.vue.d.ts +19 -0
  199. package/dist/runtime/components/Edit/index.d.ts +23 -15
  200. package/dist/runtime/components/Edit/index.js +44 -28
  201. package/dist/runtime/composables/defineBlokkli.js +7 -3
  202. package/dist/runtime/composables/defineBlokkliFeature.d.ts +4 -7
  203. package/dist/runtime/composables/defineBlokkliProvider.d.ts +11 -0
  204. package/dist/runtime/composables/defineBlokkliProvider.js +46 -0
  205. package/dist/runtime/composables/useBlokkliHelper.js +1 -1
  206. package/dist/runtime/constants/index.d.ts +3 -0
  207. package/dist/runtime/constants/index.js +3 -0
  208. package/dist/runtime/css/output.css +1 -1
  209. package/dist/runtime/helpers/addElementClasses.d.ts +2 -0
  210. package/dist/runtime/helpers/addElementClasses.js +24 -0
  211. package/dist/runtime/helpers/animationProvider.d.ts +4 -2
  212. package/dist/runtime/helpers/animationProvider.js +7 -2
  213. package/dist/runtime/helpers/bundles/index.d.ts +1 -0
  214. package/dist/runtime/helpers/bundles/index.js +4 -0
  215. package/dist/runtime/helpers/composables/useStickyToolbar.d.ts +20 -0
  216. package/dist/runtime/helpers/composables/useStickyToolbar.js +215 -0
  217. package/dist/runtime/helpers/definitionProvider.d.ts +2 -1
  218. package/dist/runtime/helpers/definitionProvider.js +17 -0
  219. package/dist/runtime/helpers/domProvider.d.ts +2 -1
  220. package/dist/runtime/helpers/domProvider.js +89 -43
  221. package/dist/runtime/helpers/dropTargets/index.d.ts +6 -0
  222. package/dist/runtime/helpers/dropTargets/index.js +49 -0
  223. package/dist/runtime/helpers/eventBus.d.ts +1 -1
  224. package/dist/runtime/helpers/eventBus.js +2 -2
  225. package/dist/runtime/helpers/index.d.ts +10 -1
  226. package/dist/runtime/helpers/index.js +57 -0
  227. package/dist/runtime/helpers/indicatorsProvider.d.ts +10 -0
  228. package/dist/runtime/helpers/indicatorsProvider.js +23 -0
  229. package/dist/runtime/helpers/keyboardProvider.d.ts +2 -0
  230. package/dist/runtime/helpers/keyboardProvider.js +17 -1
  231. package/dist/runtime/helpers/pluginProvider.d.ts +10 -0
  232. package/dist/runtime/helpers/pluginProvider.js +33 -0
  233. package/dist/runtime/helpers/renderCycle.d.ts +1 -0
  234. package/dist/runtime/helpers/renderCycle.js +10 -0
  235. package/dist/runtime/helpers/runtimeHelpers/index.js +14 -11
  236. package/dist/runtime/helpers/selectionProvider.d.ts +16 -0
  237. package/dist/runtime/helpers/selectionProvider.js +47 -35
  238. package/dist/runtime/helpers/stateProvider.d.ts +6 -2
  239. package/dist/runtime/helpers/stateProvider.js +58 -14
  240. package/dist/runtime/helpers/storageProvider.d.ts +4 -3
  241. package/dist/runtime/helpers/storageProvider.js +56 -3
  242. package/dist/runtime/helpers/symbols.d.ts +1 -0
  243. package/dist/runtime/helpers/symbols.js +1 -0
  244. package/dist/runtime/helpers/textProvider.js +6 -0
  245. package/dist/runtime/helpers/themeProvider.d.ts +2 -0
  246. package/dist/runtime/helpers/themeProvider.js +4 -1
  247. package/dist/runtime/helpers/transform.js +1 -3
  248. package/dist/runtime/helpers/uiProvider.d.ts +7 -2
  249. package/dist/runtime/helpers/uiProvider.js +49 -47
  250. package/dist/runtime/helpers/useTransitionedValue.d.ts +18 -0
  251. package/dist/runtime/helpers/useTransitionedValue.js +57 -0
  252. package/dist/runtime/icons/anchor.svg +1 -0
  253. package/dist/runtime/icons/arrow-left.svg +1 -1
  254. package/dist/runtime/icons/arrow-right.svg +1 -1
  255. package/dist/runtime/icons/arrow-top-right.svg +1 -0
  256. package/dist/runtime/icons/chart.svg +1 -0
  257. package/dist/runtime/icons/copy.svg +1 -0
  258. package/dist/runtime/icons/cursor-move.svg +1 -1
  259. package/dist/runtime/icons/diff.svg +1 -1
  260. package/dist/runtime/icons/eye.svg +1 -1
  261. package/dist/runtime/icons/info.svg +1 -1
  262. package/dist/runtime/icons/link.svg +1 -0
  263. package/dist/runtime/icons/speedometer.svg +1 -0
  264. package/dist/runtime/types/blokkOptions.d.ts +8 -0
  265. package/dist/runtime/types/index.d.ts +163 -5
  266. package/dist/runtime/types/theme.d.ts +2 -1
  267. package/dist/shared/{editor.gz_ac6uT.d.mts → editor.CKsrTpc1.d.mts} +1 -1
  268. package/package.json +20 -5
  269. package/dist/runtime/components/Edit/Features/FieldAreas/Overlay/index.vue +0 -22
  270. package/dist/runtime/components/Edit/Features/FieldAreas/index.vue +0 -41
  271. /package/dist/runtime/components/Edit/Features/{FieldAreas/Overlay → Analyze}/index.vue.d.ts +0 -0
  272. /package/dist/runtime/components/Edit/Features/{FieldAreas/index.vue.d.ts → Anchors/Renderer.vue.d.ts} +0 -0
@@ -0,0 +1,745 @@
1
+ <template>
2
+ <div
3
+ class="bk bk-konami"
4
+ :style="{
5
+ '--bk-bg': background
6
+ }"
7
+ >
8
+ <div class="bk-dialog-background" />
9
+ <div class="bk-konami-game bk-slide-up-inner">
10
+ <div class="bk-konami-game-canvas">
11
+ <canvas
12
+ ref="canvasDisplay"
13
+ :style="canvasStyle"
14
+ :width="canvasWidth"
15
+ :height="canvasHeight"
16
+ class="bk-is-display"
17
+ />
18
+ <Pixelgrid
19
+ :canvas-scale
20
+ :canvas-height
21
+ :canvas-width
22
+ :style="canvasStyle"
23
+ />
24
+ </div>
25
+ </div>
26
+ <div v-if="DEBUG_ICONS" class="bk-konami-debug-canvas">
27
+ <canvas
28
+ ref="debugCanvas"
29
+ :width="debugCanvasWidth"
30
+ :height="debugCanvasHeight"
31
+ :style="{
32
+ width: debugCanvasWidth * 6 + 'px',
33
+ height: debugCanvasHeight * 6 + 'px'
34
+ }"
35
+ />
36
+ </div>
37
+ </div>
38
+ </template>
39
+
40
+ <script setup>
41
+ import onBlokkliEvent from "#blokkli/helpers/composables/onBlokkliEvent";
42
+ import {
43
+ computed,
44
+ useTemplateRef,
45
+ useBlokkli,
46
+ ref,
47
+ onMounted,
48
+ onUnmounted
49
+ } from "#imports";
50
+ import Pixelgrid from "./PixelGrid.vue";
51
+ import { useTextRendering } from "./textRendering";
52
+ import { useIconRendering } from "./useIconRendering";
53
+ import logoUrl from "./blokkli.png";
54
+ const emit = defineEmits(["close"]);
55
+ const DEBUG_ICONS = false;
56
+ const DEBUG_GAME = false;
57
+ const largeIconSize = 32;
58
+ const blackColor = "black";
59
+ const worldWidth = 7 * 3;
60
+ const worldHeight = 4 * 3 - 1;
61
+ const scoreAreaHeight = 1;
62
+ const cellSize = 12;
63
+ const gameWorldBorder = 1;
64
+ const gameWorldPadding = 1;
65
+ let isLoaded = false;
66
+ const { keyboard, ui } = useBlokkli();
67
+ const { drawTextPixels, getTextWidth, drawText } = useTextRendering();
68
+ const { initIcons, getIconCount, drawIcon } = useIconRendering(
69
+ cellSize,
70
+ largeIconSize
71
+ );
72
+ const iconCount = getIconCount();
73
+ const canvasWidth = computed(() => {
74
+ return worldWidth * cellSize + (gameWorldBorder + gameWorldPadding) * 2;
75
+ });
76
+ const canvasHeight = computed(() => {
77
+ return scoreAreaHeight * cellSize + (gameWorldBorder + gameWorldPadding) * 2 + worldHeight * cellSize;
78
+ });
79
+ const canvasScale = computed(() => {
80
+ const availableWidth = ui.viewport.value.width * 0.8;
81
+ const availableHeight = ui.viewport.value.height * 0.8;
82
+ const maxScaleWidth = Math.floor(availableWidth / canvasWidth.value);
83
+ const maxScaleHeight = Math.floor(availableHeight / canvasHeight.value);
84
+ return Math.max(1, Math.min(maxScaleWidth, maxScaleHeight));
85
+ });
86
+ const canvasStyle = computed(() => {
87
+ return {
88
+ width: canvasWidth.value * canvasScale.value + "px",
89
+ height: canvasHeight.value * canvasScale.value + "px"
90
+ };
91
+ });
92
+ const snake = ref([
93
+ { x: Math.floor(worldWidth / 2), y: Math.floor(worldHeight / 2) }
94
+ ]);
95
+ const direction = ref("right");
96
+ const nextDirection = ref("right");
97
+ const food = ref({ x: 10, y: 10 });
98
+ const gameOver = ref(false);
99
+ const gameStarted = ref(false);
100
+ const score = ref(0);
101
+ const blocksEaten = ref(0);
102
+ const removedTail = ref(null);
103
+ let lastCellUpdate = 0;
104
+ let gameOverTime = 0;
105
+ const currentBlockIndex = ref(0);
106
+ let movesSinceFoodSpawn = 0;
107
+ let optimalPathLength = 0;
108
+ const canvasDisplay = useTemplateRef("canvasDisplay");
109
+ const debugCanvas = useTemplateRef("debugCanvas");
110
+ const debugCanvasWidth = computed(() => {
111
+ if (!DEBUG_ICONS) return 0;
112
+ const iconsPerRow = 7;
113
+ return Math.min(iconCount, iconsPerRow) * (largeIconSize + 10);
114
+ });
115
+ const debugCanvasHeight = computed(() => {
116
+ if (!DEBUG_ICONS) return 0;
117
+ const iconsPerRow = 7;
118
+ const smallRows = Math.ceil(iconCount / iconsPerRow);
119
+ const largeRows = Math.ceil(iconCount / iconsPerRow);
120
+ return smallRows * (cellSize + 10) + largeRows * (largeIconSize + 10) + 20;
121
+ });
122
+ let scoreCanvas = null;
123
+ let snakeCanvas = null;
124
+ let logoCanvas = null;
125
+ let lastScore = -1;
126
+ let lastBlocksEaten = -1;
127
+ const cellMoveDuration = 200;
128
+ function generateFood() {
129
+ let newFood;
130
+ do {
131
+ newFood = {
132
+ x: Math.floor(Math.random() * worldWidth),
133
+ y: Math.floor(Math.random() * worldHeight)
134
+ };
135
+ } while (snake.value.some(
136
+ (segment) => segment.x === newFood.x && segment.y === newFood.y
137
+ ));
138
+ food.value = newFood;
139
+ currentBlockIndex.value = (currentBlockIndex.value + 1) % iconCount;
140
+ movesSinceFoodSpawn = 0;
141
+ const head = snake.value[0];
142
+ optimalPathLength = Math.abs(head.x - newFood.x) + Math.abs(head.y - newFood.y);
143
+ }
144
+ function getAIDirection() {
145
+ const head = snake.value[0];
146
+ const target = food.value;
147
+ const isSafe = (pos) => {
148
+ if (pos.x < 0 || pos.x >= worldWidth || pos.y < 0 || pos.y >= worldHeight) {
149
+ return false;
150
+ }
151
+ for (let i = 0; i < snake.value.length - 1; i++) {
152
+ const segment = snake.value[i];
153
+ if (segment.x === pos.x && segment.y === pos.y) {
154
+ return false;
155
+ }
156
+ }
157
+ return true;
158
+ };
159
+ const moves = [];
160
+ const directions = ["up", "down", "left", "right"];
161
+ for (const dir of directions) {
162
+ if (dir === "up" && direction.value === "down" || dir === "down" && direction.value === "up" || dir === "left" && direction.value === "right" || dir === "right" && direction.value === "left") {
163
+ continue;
164
+ }
165
+ const newPos = { ...head };
166
+ switch (dir) {
167
+ case "up":
168
+ newPos.y -= 1;
169
+ break;
170
+ case "down":
171
+ newPos.y += 1;
172
+ break;
173
+ case "left":
174
+ newPos.x -= 1;
175
+ break;
176
+ case "right":
177
+ newPos.x += 1;
178
+ break;
179
+ }
180
+ if (isSafe(newPos)) {
181
+ const distance = Math.abs(newPos.x - target.x) + Math.abs(newPos.y - target.y);
182
+ moves.push({ dir, pos: newPos, priority: -distance });
183
+ }
184
+ }
185
+ moves.sort((a, b) => b.priority - a.priority);
186
+ return moves.length > 0 ? moves[0].dir : direction.value;
187
+ }
188
+ function resetGame() {
189
+ const startPos = {
190
+ x: Math.floor(worldWidth / 2),
191
+ y: Math.floor(worldHeight / 2)
192
+ };
193
+ snake.value = [startPos];
194
+ direction.value = "right";
195
+ nextDirection.value = "right";
196
+ gameOver.value = false;
197
+ gameStarted.value = false;
198
+ score.value = 0;
199
+ blocksEaten.value = 0;
200
+ removedTail.value = null;
201
+ lastCellUpdate = 0;
202
+ gameOverTime = 0;
203
+ movesSinceFoodSpawn = 0;
204
+ optimalPathLength = 0;
205
+ if (DEBUG_GAME) {
206
+ for (let i = 0; i < 10; i++) {
207
+ const head = snake.value[0];
208
+ snake.value.push({ x: head.x - i - 1, y: head.y });
209
+ }
210
+ blocksEaten.value = 10;
211
+ score.value = 10 * 100;
212
+ gameStarted.value = true;
213
+ }
214
+ generateFood();
215
+ }
216
+ function update(currentTime) {
217
+ if (gameOver.value || !gameStarted.value) return;
218
+ if (lastCellUpdate === 0) {
219
+ lastCellUpdate = currentTime;
220
+ return;
221
+ }
222
+ const timeSinceLastUpdate = currentTime - lastCellUpdate;
223
+ if (timeSinceLastUpdate >= cellMoveDuration) {
224
+ if (DEBUG_GAME) {
225
+ nextDirection.value = getAIDirection();
226
+ }
227
+ direction.value = nextDirection.value;
228
+ const head = snake.value[0];
229
+ const newHead = { ...head };
230
+ switch (direction.value) {
231
+ case "up":
232
+ newHead.y -= 1;
233
+ break;
234
+ case "down":
235
+ newHead.y += 1;
236
+ break;
237
+ case "left":
238
+ newHead.x -= 1;
239
+ break;
240
+ case "right":
241
+ newHead.x += 1;
242
+ break;
243
+ }
244
+ if (newHead.x < 0 || newHead.x >= worldWidth || newHead.y < 0 || newHead.y >= worldHeight) {
245
+ gameOver.value = true;
246
+ gameOverTime = lastCellUpdate + cellMoveDuration;
247
+ return;
248
+ }
249
+ if (snake.value.some(
250
+ (segment) => segment.x === newHead.x && segment.y === newHead.y
251
+ )) {
252
+ gameOver.value = true;
253
+ gameOverTime = lastCellUpdate + cellMoveDuration;
254
+ return;
255
+ }
256
+ lastCellUpdate = currentTime;
257
+ snake.value.unshift(newHead);
258
+ movesSinceFoodSpawn++;
259
+ if (newHead.x === food.value.x && newHead.y === food.value.y) {
260
+ const pathDifference = movesSinceFoodSpawn - optimalPathLength;
261
+ const cappedDifference = Math.min(pathDifference, 9);
262
+ const points = 100 - cappedDifference * 10;
263
+ score.value += points;
264
+ blocksEaten.value += 1;
265
+ generateFood();
266
+ removedTail.value = null;
267
+ } else {
268
+ const tail = snake.value.pop();
269
+ removedTail.value = tail ? { ...tail } : null;
270
+ }
271
+ }
272
+ }
273
+ const background = computed(() => {
274
+ return "rgba(133, 144, 24, 1)";
275
+ });
276
+ function initOffscreenCanvases() {
277
+ scoreCanvas = document.createElement("canvas");
278
+ scoreCanvas.width = canvasWidth.value;
279
+ scoreCanvas.height = cellSize;
280
+ const gameAreaWidth = worldWidth * cellSize + (gameWorldBorder + gameWorldPadding) * 2;
281
+ const gameAreaHeight = scoreAreaHeight * cellSize + (gameWorldBorder + gameWorldPadding) * 2 + worldHeight * cellSize;
282
+ snakeCanvas = new OffscreenCanvas(gameAreaWidth, gameAreaHeight);
283
+ }
284
+ async function initLogo() {
285
+ return new Promise((resolve) => {
286
+ const img = new Image();
287
+ img.onload = () => {
288
+ logoCanvas = new OffscreenCanvas(img.width, img.height);
289
+ const ctx = logoCanvas.getContext("2d", { willReadFrequently: true });
290
+ if (!ctx) {
291
+ resolve();
292
+ return;
293
+ }
294
+ ctx.drawImage(img, 0, 0);
295
+ const imageData = ctx.getImageData(0, 0, img.width, img.height);
296
+ const data = imageData.data;
297
+ const bgColor = background.value;
298
+ const match = bgColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
299
+ const bgR = match ? Number.parseInt(match[1]) : 0;
300
+ const bgG = match ? Number.parseInt(match[2]) : 0;
301
+ const bgB = match ? Number.parseInt(match[3]) : 0;
302
+ for (let i = 0; i < data.length; i += 4) {
303
+ const r = data[i];
304
+ const g = data[i + 1];
305
+ const b = data[i + 2];
306
+ const a = data[i + 3];
307
+ const brightness = (r + g + b) / 3;
308
+ if (a > 0 && brightness > 200) {
309
+ data[i] = bgR;
310
+ data[i + 1] = bgG;
311
+ data[i + 2] = bgB;
312
+ data[i + 3] = 255;
313
+ }
314
+ }
315
+ ctx.putImageData(imageData, 0, 0);
316
+ resolve();
317
+ };
318
+ img.src = logoUrl;
319
+ });
320
+ }
321
+ function drawScoreArea() {
322
+ if (!scoreCanvas) return;
323
+ const ctx = scoreCanvas.getContext("2d");
324
+ if (!ctx) return;
325
+ ctx.fillStyle = background.value;
326
+ ctx.fillRect(0, 0, scoreCanvas.width, scoreCanvas.height);
327
+ const scoreText = "Score: " + score.value.toString();
328
+ drawTextPixels(ctx, scoreText, 0, 2, blackColor, "left");
329
+ const blocksText = blocksEaten.value.toString();
330
+ const rightAlignX = worldWidth * cellSize + 4;
331
+ drawTextPixels(ctx, blocksText, rightAlignX, 2, blackColor, "right");
332
+ lastScore = score.value;
333
+ lastBlocksEaten = blocksEaten.value;
334
+ }
335
+ function drawStartScreen(ctx, currentTime) {
336
+ ctx.imageSmoothingEnabled = false;
337
+ const offset = gameWorldBorder + gameWorldPadding;
338
+ const totalWidth = worldWidth * cellSize;
339
+ const largeIconSize2 = 32;
340
+ const gameAreaY = scoreAreaHeight * cellSize + offset;
341
+ const numColumns = 6;
342
+ const columnWidth = totalWidth / numColumns;
343
+ const rowHeight = largeIconSize2 + 24;
344
+ const numRows = 8;
345
+ const speed = 25;
346
+ const wrapHeight = numRows * rowHeight;
347
+ let positionIndex = 0;
348
+ for (let row = 0; row < numRows; row++) {
349
+ for (let col = 0; col < numColumns; col++) {
350
+ if ((row + col) % 2 === 0) {
351
+ const iconIndex = positionIndex % iconCount;
352
+ const xBase = offset + col * columnWidth + (columnWidth - largeIconSize2) / 2;
353
+ const sineFrequency = 1e-3;
354
+ const sinePhase = positionIndex * 0.6;
355
+ const xOffset = Math.cos(currentTime * sineFrequency + sinePhase) * 24;
356
+ const x = xBase + xOffset;
357
+ const baseY = row * rowHeight;
358
+ const yProgress = currentTime / 1e3 * speed;
359
+ const wrappedY = (baseY + yProgress) % wrapHeight;
360
+ const y = wrappedY + gameAreaY - largeIconSize2 * 2;
361
+ drawIcon(ctx, iconIndex, x, y, true);
362
+ positionIndex++;
363
+ }
364
+ }
365
+ }
366
+ if (logoCanvas) {
367
+ ctx.drawImage(logoCanvas, 0, 0);
368
+ }
369
+ const line1 = "Use arrow keys to move";
370
+ const line1Width = getTextWidth(line1);
371
+ const line1X = Math.floor((totalWidth - line1Width) / 2) + offset;
372
+ const line2 = "Press ESC to exit";
373
+ const line2Width = getTextWidth(line2);
374
+ const line2X = Math.floor((totalWidth - line2Width) / 2) + offset;
375
+ ctx.beginPath();
376
+ ctx.rect((canvasWidth.value - (line1Width + 10)) / 2, 88, line1Width + 10, 21);
377
+ ctx.fill();
378
+ ctx.lineWidth = 2;
379
+ ctx.stroke();
380
+ drawText(ctx, line1, line1X, 90, blackColor);
381
+ drawText(ctx, line2, line2X, 100, blackColor);
382
+ const blinkOn = currentTime % 1e3 < 500;
383
+ if (blinkOn) {
384
+ const spaceText = "Press SPACE to start";
385
+ const spaceTextWidth = Math.round(getTextWidth(spaceText));
386
+ const spaceTextX = Math.round((canvasWidth.value - spaceTextWidth) / 2);
387
+ ctx.fillStyle = background.value;
388
+ ctx.strokeStyle = blackColor;
389
+ ctx.lineWidth = 2;
390
+ ctx.beginPath();
391
+ ctx.rect(spaceTextX - 3, 117, spaceTextWidth + 6, 13);
392
+ ctx.fill();
393
+ ctx.stroke();
394
+ drawTextPixels(
395
+ ctx,
396
+ spaceText,
397
+ canvasWidth.value / 2,
398
+ 120,
399
+ blackColor,
400
+ "center"
401
+ );
402
+ }
403
+ }
404
+ function draw(currentTime) {
405
+ const ctx = canvasDisplay.value?.getContext("2d");
406
+ if (!ctx) return;
407
+ if (!gameStarted.value) {
408
+ ctx.fillStyle = background.value;
409
+ ctx.fillRect(0, 0, canvasWidth.value, canvasHeight.value);
410
+ drawStartScreen(ctx, currentTime);
411
+ return;
412
+ }
413
+ let movementProgress = 0;
414
+ if (lastCellUpdate > 0) {
415
+ const timeToUse = gameOver.value && gameOverTime > 0 ? gameOverTime : currentTime;
416
+ const timeSinceLastUpdate = timeToUse - lastCellUpdate;
417
+ movementProgress = Math.min(timeSinceLastUpdate / cellMoveDuration, 1);
418
+ }
419
+ if (score.value !== lastScore || blocksEaten.value !== lastBlocksEaten) {
420
+ drawScoreArea();
421
+ }
422
+ const offset = gameWorldBorder + gameWorldPadding;
423
+ const gameAreaY = scoreAreaHeight * cellSize;
424
+ const gameAreaHeight = canvasHeight.value - gameAreaY;
425
+ ctx.fillStyle = background.value;
426
+ ctx.fillRect(0, gameAreaY, canvasWidth.value, gameAreaHeight);
427
+ if (gameWorldBorder > 0) {
428
+ ctx.fillStyle = blackColor;
429
+ const borderX = 0;
430
+ const borderY = scoreAreaHeight * cellSize;
431
+ const borderWidth = worldWidth * cellSize + (gameWorldBorder + gameWorldPadding) * 2;
432
+ const borderHeight = worldHeight * cellSize + (gameWorldBorder + gameWorldPadding) * 2;
433
+ ctx.fillRect(borderX, borderY, borderWidth, gameWorldBorder);
434
+ ctx.fillRect(
435
+ borderX,
436
+ borderY + borderHeight - gameWorldBorder,
437
+ borderWidth,
438
+ gameWorldBorder
439
+ );
440
+ ctx.fillRect(borderX, borderY, gameWorldBorder, borderHeight);
441
+ ctx.fillRect(
442
+ borderX + borderWidth - gameWorldBorder,
443
+ borderY,
444
+ gameWorldBorder,
445
+ borderHeight
446
+ );
447
+ }
448
+ const renderPositions = [];
449
+ if (removedTail.value) {
450
+ const currentTail = snake.value[snake.value.length - 1];
451
+ if (currentTail) {
452
+ const dx = currentTail.x - removedTail.value.x;
453
+ const dy = currentTail.y - removedTail.value.y;
454
+ const renderX = removedTail.value.x + dx * movementProgress;
455
+ const renderY = removedTail.value.y + dy * movementProgress;
456
+ renderPositions.push({ x: renderX, y: renderY });
457
+ }
458
+ }
459
+ for (let i = snake.value.length - 1; i >= 0; i--) {
460
+ const segment = snake.value[i];
461
+ let renderX = segment.x;
462
+ let renderY = segment.y;
463
+ if (i === 0) {
464
+ const dx = direction.value === "left" ? 1 : direction.value === "right" ? -1 : 0;
465
+ const dy = direction.value === "up" ? 1 : direction.value === "down" ? -1 : 0;
466
+ renderX = segment.x + dx * (1 - movementProgress);
467
+ renderY = segment.y + dy * (1 - movementProgress);
468
+ }
469
+ renderPositions.push({ x: renderX, y: renderY });
470
+ }
471
+ const SNAKE_DEBUG = false;
472
+ if (snakeCanvas) {
473
+ const snakeCtx = SNAKE_DEBUG ? ctx : snakeCanvas.getContext("2d", {
474
+ willReadFrequently: true
475
+ });
476
+ if (snakeCtx) {
477
+ snakeCtx.clearRect(0, 0, snakeCanvas.width, snakeCanvas.height);
478
+ snakeCtx.strokeStyle = blackColor;
479
+ snakeCtx.lineCap = "round";
480
+ snakeCtx.lineJoin = "round";
481
+ snakeCtx.beginPath();
482
+ if (renderPositions.length > 0) {
483
+ const offset2 = gameWorldBorder + gameWorldPadding;
484
+ const firstPos = renderPositions[0];
485
+ const startX = Math.round(firstPos.x * cellSize + cellSize / 2 + offset2);
486
+ const startY = Math.round(
487
+ (firstPos.y + scoreAreaHeight) * cellSize + cellSize / 2 + offset2
488
+ );
489
+ snakeCtx.moveTo(startX, startY);
490
+ for (let i = 1; i < renderPositions.length; i++) {
491
+ const pos = renderPositions[i];
492
+ const x = Math.round(pos.x * cellSize + cellSize / 2 + offset2);
493
+ const y = Math.round(
494
+ (pos.y + scoreAreaHeight) * cellSize + cellSize / 2 + offset2
495
+ );
496
+ snakeCtx.lineTo(x, y);
497
+ }
498
+ snakeCtx.lineCap = "round";
499
+ snakeCtx.lineJoin = "round";
500
+ snakeCtx.lineDashOffset = 0;
501
+ snakeCtx.lineWidth = 12;
502
+ snakeCtx.setLineDash([4e5]);
503
+ snakeCtx.stroke();
504
+ snakeCtx.strokeStyle = "white";
505
+ snakeCtx.lineDashOffset = 0;
506
+ snakeCtx.lineWidth = 10;
507
+ snakeCtx.stroke();
508
+ snakeCtx.lineWidth = 6;
509
+ snakeCtx.strokeStyle = "black";
510
+ snakeCtx.lineDashOffset = -0;
511
+ snakeCtx.setLineDash([4, 8]);
512
+ snakeCtx.stroke();
513
+ snakeCtx.lineWidth = 2;
514
+ snakeCtx.strokeStyle = "black";
515
+ snakeCtx.lineDashOffset = -0;
516
+ snakeCtx.setLineDash([]);
517
+ snakeCtx.stroke();
518
+ const headPos = renderPositions[renderPositions.length - 1];
519
+ const headX = Math.round(headPos.x * cellSize + cellSize / 2 + offset2);
520
+ const headY = Math.round(
521
+ (headPos.y + scoreAreaHeight) * cellSize + cellSize / 2 + offset2
522
+ );
523
+ const headRadius = cellSize / 2;
524
+ snakeCtx.setLineDash([]);
525
+ snakeCtx.fillStyle = blackColor;
526
+ const mouthCycle = currentTime % 600 / 600;
527
+ const mouthOpen = Math.sin(mouthCycle * Math.PI * 2) * 0.5 + 0.5;
528
+ const maxMouthAngle = Math.PI / 3;
529
+ const mouthAngle = mouthOpen * maxMouthAngle;
530
+ snakeCtx.fillStyle = "white";
531
+ snakeCtx.beginPath();
532
+ snakeCtx.arc(headX, headY, cellSize / 2 - 2, 0, Math.PI * 2);
533
+ snakeCtx.fill();
534
+ let rotation = 0;
535
+ switch (direction.value) {
536
+ case "right":
537
+ rotation = 0;
538
+ break;
539
+ case "down":
540
+ rotation = Math.PI / 2;
541
+ break;
542
+ case "left":
543
+ rotation = Math.PI;
544
+ break;
545
+ case "up":
546
+ rotation = -Math.PI / 2;
547
+ break;
548
+ }
549
+ const jawLength = headRadius + 2;
550
+ const mouthOffset = -1;
551
+ const mouthCenterX = headX + Math.cos(rotation) * mouthOffset;
552
+ const mouthCenterY = headY + Math.sin(rotation) * mouthOffset;
553
+ const upperJawX = mouthCenterX + Math.cos(rotation - mouthAngle / 2) * jawLength;
554
+ const upperJawY = mouthCenterY + Math.sin(rotation - mouthAngle / 2) * jawLength;
555
+ const lowerJawX = mouthCenterX + Math.cos(rotation + mouthAngle / 2) * jawLength;
556
+ const lowerJawY = mouthCenterY + Math.sin(rotation + mouthAngle / 2) * jawLength;
557
+ snakeCtx.fillStyle = "white";
558
+ snakeCtx.beginPath();
559
+ snakeCtx.moveTo(mouthCenterX, mouthCenterY);
560
+ snakeCtx.lineTo(upperJawX, upperJawY);
561
+ snakeCtx.lineTo(lowerJawX, lowerJawY);
562
+ snakeCtx.closePath();
563
+ snakeCtx.fill();
564
+ snakeCtx.strokeStyle = blackColor;
565
+ snakeCtx.lineWidth = 1;
566
+ snakeCtx.lineCap = "round";
567
+ snakeCtx.beginPath();
568
+ snakeCtx.moveTo(mouthCenterX, mouthCenterY);
569
+ snakeCtx.lineTo(upperJawX, upperJawY);
570
+ snakeCtx.stroke();
571
+ snakeCtx.beginPath();
572
+ snakeCtx.moveTo(mouthCenterX, mouthCenterY);
573
+ snakeCtx.lineTo(lowerJawX, lowerJawY);
574
+ snakeCtx.stroke();
575
+ }
576
+ if (!SNAKE_DEBUG) {
577
+ const imageData = snakeCtx.getImageData(
578
+ 0,
579
+ 0,
580
+ snakeCanvas.width,
581
+ snakeCanvas.height
582
+ );
583
+ const data = imageData.data;
584
+ const THRESHOLD = 100;
585
+ for (let i = 0; i < data.length; i += 4) {
586
+ const r = data[i];
587
+ const g = data[i + 1];
588
+ const b = data[i + 2];
589
+ const a = data[i + 3];
590
+ const brightness = (r + g + b) / 3;
591
+ if (a > THRESHOLD && brightness < THRESHOLD) {
592
+ data[i] = 0;
593
+ data[i + 1] = 0;
594
+ data[i + 2] = 0;
595
+ data[i + 3] = 255;
596
+ } else {
597
+ data[i] = 0;
598
+ data[i + 1] = 0;
599
+ data[i + 2] = 0;
600
+ data[i + 3] = 0;
601
+ }
602
+ }
603
+ snakeCtx.putImageData(imageData, 0, 0);
604
+ ctx.drawImage(
605
+ snakeCanvas,
606
+ 0,
607
+ 0,
608
+ // source x, y
609
+ snakeCanvas.width,
610
+ snakeCanvas.height,
611
+ // source width, height
612
+ 0,
613
+ 0,
614
+ // destination x, y
615
+ snakeCanvas.width,
616
+ snakeCanvas.height
617
+ // destination width, height
618
+ );
619
+ }
620
+ }
621
+ }
622
+ const foodX = food.value.x * cellSize + offset;
623
+ const foodY = (food.value.y + scoreAreaHeight) * cellSize + offset;
624
+ drawIcon(ctx, currentBlockIndex.value, foodX, foodY);
625
+ if (scoreCanvas) {
626
+ ctx.drawImage(scoreCanvas, 0, 0);
627
+ }
628
+ if (gameOver.value) {
629
+ const totalWidth = worldWidth * cellSize;
630
+ const gameOverText = "GAME OVER";
631
+ const gameOverWidth = getTextWidth(gameOverText) * 3;
632
+ const gameOverX = Math.floor((totalWidth - gameOverWidth) / 2) + offset;
633
+ drawText(
634
+ ctx,
635
+ gameOverText,
636
+ gameOverX,
637
+ 3 * cellSize,
638
+ blackColor,
639
+ background.value,
640
+ 1,
641
+ 2,
642
+ 3
643
+ );
644
+ const retryText = "Press SPACE to try again";
645
+ const retryWidth = getTextWidth(retryText);
646
+ const retryX = Math.floor((totalWidth - retryWidth) / 2) + offset;
647
+ drawText(
648
+ ctx,
649
+ retryText,
650
+ retryX,
651
+ 8 * cellSize,
652
+ blackColor,
653
+ background.value,
654
+ 1,
655
+ 2
656
+ );
657
+ }
658
+ }
659
+ function handleKeyPress(e) {
660
+ e.stopPropagation();
661
+ const key = e.key;
662
+ if ((key === "r" || key === "R") && (e.metaKey || e.ctrlKey)) {
663
+ return;
664
+ }
665
+ if (key === "Escape") {
666
+ e.preventDefault();
667
+ emit("close");
668
+ return;
669
+ }
670
+ if (key === " " && gameOver.value) {
671
+ e.preventDefault();
672
+ resetGame();
673
+ gameStarted.value = true;
674
+ return;
675
+ }
676
+ if (!gameStarted.value && (key === " " || key === "ArrowUp" || key === "ArrowDown" || key === "ArrowLeft" || key === "ArrowRight")) {
677
+ e.preventDefault();
678
+ gameStarted.value = true;
679
+ return;
680
+ }
681
+ if (key === "ArrowUp" && direction.value !== "down") {
682
+ e.preventDefault();
683
+ nextDirection.value = "up";
684
+ } else if (key === "ArrowDown" && direction.value !== "up") {
685
+ e.preventDefault();
686
+ nextDirection.value = "down";
687
+ } else if (key === "ArrowLeft" && direction.value !== "right") {
688
+ e.preventDefault();
689
+ nextDirection.value = "left";
690
+ } else if (key === "ArrowRight" && direction.value !== "left") {
691
+ e.preventDefault();
692
+ nextDirection.value = "right";
693
+ }
694
+ }
695
+ onMounted(async () => {
696
+ keyboard.lockKeyboardEvents("konami");
697
+ document.addEventListener("keydown", handleKeyPress, { capture: true });
698
+ console.log(
699
+ "Virtual screen resolution:",
700
+ canvasWidth.value,
701
+ "x",
702
+ canvasHeight.value
703
+ );
704
+ await initIcons();
705
+ await initLogo();
706
+ initOffscreenCanvases();
707
+ resetGame();
708
+ drawScoreArea();
709
+ if (DEBUG_ICONS && debugCanvas.value) {
710
+ const ctx = debugCanvas.value.getContext("2d");
711
+ if (ctx) {
712
+ ctx.fillStyle = "white";
713
+ ctx.fillRect(0, 0, debugCanvas.value.width, debugCanvas.value.height);
714
+ const iconsPerRow = 7;
715
+ for (let i = 0; i < iconCount; i++) {
716
+ const row = Math.floor(i / iconsPerRow);
717
+ const col = i % iconsPerRow;
718
+ const x = col * (largeIconSize + 10) + 5;
719
+ const y = row * (cellSize + 10) + 5;
720
+ drawIcon(ctx, i, x, y, false);
721
+ }
722
+ const smallRows = Math.ceil(iconCount / iconsPerRow);
723
+ const largeIconsStartY = smallRows * (cellSize + 10) + 10;
724
+ for (let i = 0; i < iconCount; i++) {
725
+ const row = Math.floor(i / iconsPerRow);
726
+ const col = i % iconsPerRow;
727
+ const x = col * (largeIconSize + 10) + 5;
728
+ const y = largeIconsStartY + row * (largeIconSize + 10);
729
+ drawIcon(ctx, i, x, y, true);
730
+ }
731
+ }
732
+ }
733
+ isLoaded = true;
734
+ });
735
+ onUnmounted(() => {
736
+ keyboard.unlockKeyboardEvents("konami");
737
+ document.removeEventListener("keydown", handleKeyPress, { capture: true });
738
+ });
739
+ onBlokkliEvent("canvas:draw", (e) => {
740
+ if (!isLoaded) return;
741
+ const time = e.time;
742
+ update(time);
743
+ draw(time);
744
+ });
745
+ </script>