scratch-blocks 2.0.2 → 2.0.3

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 (274) hide show
  1. package/commitlint.config.js +2 -2
  2. package/dist/main.mjs +1 -2
  3. package/dist/types/msg/scratch_msgs.d.ts.map +1 -1
  4. package/dist/types/src/block_reporting.d.ts.map +1 -1
  5. package/dist/types/src/blocks/colour.d.ts +0 -19
  6. package/dist/types/src/blocks/colour.d.ts.map +1 -1
  7. package/dist/types/src/blocks/control.d.ts +0 -19
  8. package/dist/types/src/blocks/control.d.ts.map +1 -1
  9. package/dist/types/src/blocks/data.d.ts +0 -19
  10. package/dist/types/src/blocks/data.d.ts.map +1 -1
  11. package/dist/types/src/blocks/event.d.ts +0 -19
  12. package/dist/types/src/blocks/event.d.ts.map +1 -1
  13. package/dist/types/src/blocks/looks.d.ts +0 -19
  14. package/dist/types/src/blocks/looks.d.ts.map +1 -1
  15. package/dist/types/src/blocks/math.d.ts +0 -19
  16. package/dist/types/src/blocks/math.d.ts.map +1 -1
  17. package/dist/types/src/blocks/matrix.d.ts +0 -19
  18. package/dist/types/src/blocks/matrix.d.ts.map +1 -1
  19. package/dist/types/src/blocks/motion.d.ts +0 -19
  20. package/dist/types/src/blocks/motion.d.ts.map +1 -1
  21. package/dist/types/src/blocks/note.d.ts +0 -19
  22. package/dist/types/src/blocks/note.d.ts.map +1 -1
  23. package/dist/types/src/blocks/operators.d.ts +0 -19
  24. package/dist/types/src/blocks/operators.d.ts.map +1 -1
  25. package/dist/types/src/blocks/procedures.d.ts +6 -9
  26. package/dist/types/src/blocks/procedures.d.ts.map +1 -1
  27. package/dist/types/src/blocks/sensing.d.ts +0 -19
  28. package/dist/types/src/blocks/sensing.d.ts.map +1 -1
  29. package/dist/types/src/blocks/sound.d.ts +0 -19
  30. package/dist/types/src/blocks/sound.d.ts.map +1 -1
  31. package/dist/types/src/blocks/text.d.ts +0 -19
  32. package/dist/types/src/blocks/text.d.ts.map +1 -1
  33. package/dist/types/src/blocks/vertical_extensions.d.ts +0 -19
  34. package/dist/types/src/blocks/vertical_extensions.d.ts.map +1 -1
  35. package/dist/types/src/checkable_continuous_flyout.d.ts +2 -7
  36. package/dist/types/src/checkable_continuous_flyout.d.ts.map +1 -1
  37. package/dist/types/src/checkbox_bubble.d.ts +13 -12
  38. package/dist/types/src/checkbox_bubble.d.ts.map +1 -1
  39. package/dist/types/src/colours.d.ts.map +1 -1
  40. package/dist/types/src/constants.d.ts +0 -7
  41. package/dist/types/src/constants.d.ts.map +1 -1
  42. package/dist/types/src/context_menu_items.d.ts +0 -5
  43. package/dist/types/src/context_menu_items.d.ts.map +1 -1
  44. package/dist/types/src/data_category.d.ts +2 -4
  45. package/dist/types/src/data_category.d.ts.map +1 -1
  46. package/dist/types/src/events/events_block_comment_base.d.ts +2 -3
  47. package/dist/types/src/events/events_block_comment_base.d.ts.map +1 -1
  48. package/dist/types/src/events/events_block_comment_change.d.ts +0 -5
  49. package/dist/types/src/events/events_block_comment_change.d.ts.map +1 -1
  50. package/dist/types/src/events/events_block_comment_collapse.d.ts +0 -5
  51. package/dist/types/src/events/events_block_comment_collapse.d.ts.map +1 -1
  52. package/dist/types/src/events/events_block_comment_create.d.ts +0 -5
  53. package/dist/types/src/events/events_block_comment_create.d.ts.map +1 -1
  54. package/dist/types/src/events/events_block_comment_delete.d.ts +0 -5
  55. package/dist/types/src/events/events_block_comment_delete.d.ts.map +1 -1
  56. package/dist/types/src/events/events_block_comment_move.d.ts +0 -5
  57. package/dist/types/src/events/events_block_comment_move.d.ts.map +1 -1
  58. package/dist/types/src/events/events_block_comment_resize.d.ts +0 -5
  59. package/dist/types/src/events/events_block_comment_resize.d.ts.map +1 -1
  60. package/dist/types/src/events/events_block_drag_end.d.ts +1 -2
  61. package/dist/types/src/events/events_block_drag_end.d.ts.map +1 -1
  62. package/dist/types/src/events/events_block_drag_outside.d.ts +1 -2
  63. package/dist/types/src/events/events_block_drag_outside.d.ts.map +1 -1
  64. package/dist/types/src/events/events_scratch_variable_create.d.ts +0 -5
  65. package/dist/types/src/events/events_scratch_variable_create.d.ts.map +1 -1
  66. package/dist/types/src/fields/field_colour_slider.d.ts +3 -27
  67. package/dist/types/src/fields/field_colour_slider.d.ts.map +1 -1
  68. package/dist/types/src/fields/field_matrix.d.ts +0 -19
  69. package/dist/types/src/fields/field_matrix.d.ts.map +1 -1
  70. package/dist/types/src/fields/field_note.d.ts +8 -23
  71. package/dist/types/src/fields/field_note.d.ts.map +1 -1
  72. package/dist/types/src/fields/field_textinput_removable.d.ts +2 -4
  73. package/dist/types/src/fields/field_textinput_removable.d.ts.map +1 -1
  74. package/dist/types/src/fields/field_variable_getter.d.ts +0 -19
  75. package/dist/types/src/fields/field_variable_getter.d.ts.map +1 -1
  76. package/dist/types/src/fields/field_vertical_separator.d.ts +0 -19
  77. package/dist/types/src/fields/field_vertical_separator.d.ts.map +1 -1
  78. package/dist/types/src/fields/scratch_field_angle.d.ts +0 -19
  79. package/dist/types/src/fields/scratch_field_angle.d.ts.map +1 -1
  80. package/dist/types/src/fields/scratch_field_dropdown.d.ts +0 -5
  81. package/dist/types/src/fields/scratch_field_dropdown.d.ts.map +1 -1
  82. package/dist/types/src/fields/scratch_field_number.d.ts +0 -19
  83. package/dist/types/src/fields/scratch_field_number.d.ts.map +1 -1
  84. package/dist/types/src/fields/scratch_field_variable.d.ts +4 -7
  85. package/dist/types/src/fields/scratch_field_variable.d.ts.map +1 -1
  86. package/dist/types/src/flyout_checkbox_icon.d.ts +2 -3
  87. package/dist/types/src/flyout_checkbox_icon.d.ts.map +1 -1
  88. package/dist/types/src/glows.d.ts +1 -3
  89. package/dist/types/src/glows.d.ts.map +1 -1
  90. package/dist/types/src/index.d.ts +50 -51
  91. package/dist/types/src/index.d.ts.map +1 -1
  92. package/dist/types/src/procedures.d.ts +6 -8
  93. package/dist/types/src/procedures.d.ts.map +1 -1
  94. package/dist/types/src/recyclable_block_flyout_inflater.d.ts +3 -5
  95. package/dist/types/src/recyclable_block_flyout_inflater.d.ts.map +1 -1
  96. package/dist/types/src/renderer/bowler_hat.d.ts +2 -3
  97. package/dist/types/src/renderer/bowler_hat.d.ts.map +1 -1
  98. package/dist/types/src/renderer/cat/cat_face.d.ts +6 -5
  99. package/dist/types/src/renderer/cat/cat_face.d.ts.map +1 -1
  100. package/dist/types/src/renderer/cat/constants.d.ts +2 -2
  101. package/dist/types/src/renderer/cat/constants.d.ts.map +1 -1
  102. package/dist/types/src/renderer/cat/drawer.d.ts +3 -4
  103. package/dist/types/src/renderer/cat/drawer.d.ts.map +1 -1
  104. package/dist/types/src/renderer/cat/path_object.d.ts +2 -3
  105. package/dist/types/src/renderer/cat/path_object.d.ts.map +1 -1
  106. package/dist/types/src/renderer/cat/render_info.d.ts +3 -4
  107. package/dist/types/src/renderer/cat/render_info.d.ts.map +1 -1
  108. package/dist/types/src/renderer/cat/renderer.d.ts +6 -7
  109. package/dist/types/src/renderer/cat/renderer.d.ts.map +1 -1
  110. package/dist/types/src/renderer/constants.d.ts +4 -4
  111. package/dist/types/src/renderer/constants.d.ts.map +1 -1
  112. package/dist/types/src/renderer/drawer.d.ts +5 -4
  113. package/dist/types/src/renderer/drawer.d.ts.map +1 -1
  114. package/dist/types/src/renderer/path_object.d.ts +1 -3
  115. package/dist/types/src/renderer/path_object.d.ts.map +1 -1
  116. package/dist/types/src/renderer/render_info.d.ts +3 -4
  117. package/dist/types/src/renderer/render_info.d.ts.map +1 -1
  118. package/dist/types/src/renderer/renderer.d.ts +8 -15
  119. package/dist/types/src/renderer/renderer.d.ts.map +1 -1
  120. package/dist/types/src/scratch_block_paster.d.ts +0 -5
  121. package/dist/types/src/scratch_block_paster.d.ts.map +1 -1
  122. package/dist/types/src/scratch_blocks_utils.d.ts +0 -20
  123. package/dist/types/src/scratch_blocks_utils.d.ts.map +1 -1
  124. package/dist/types/src/scratch_comment_bubble.d.ts +1 -4
  125. package/dist/types/src/scratch_comment_bubble.d.ts.map +1 -1
  126. package/dist/types/src/scratch_comment_icon.d.ts +2 -3
  127. package/dist/types/src/scratch_comment_icon.d.ts.map +1 -1
  128. package/dist/types/src/scratch_connection_checker.d.ts +0 -5
  129. package/dist/types/src/scratch_connection_checker.d.ts.map +1 -1
  130. package/dist/types/src/scratch_continuous_category.d.ts +5 -5
  131. package/dist/types/src/scratch_continuous_category.d.ts.map +1 -1
  132. package/dist/types/src/scratch_continuous_toolbox.d.ts +3 -6
  133. package/dist/types/src/scratch_continuous_toolbox.d.ts.map +1 -1
  134. package/dist/types/src/scratch_dragger.d.ts +1 -10
  135. package/dist/types/src/scratch_dragger.d.ts.map +1 -1
  136. package/dist/types/src/scratch_insertion_marker_previewer.d.ts +0 -5
  137. package/dist/types/src/scratch_insertion_marker_previewer.d.ts.map +1 -1
  138. package/dist/types/src/scratch_variable_map.d.ts +0 -5
  139. package/dist/types/src/scratch_variable_map.d.ts.map +1 -1
  140. package/dist/types/src/scratch_variable_model.d.ts +1 -2
  141. package/dist/types/src/scratch_variable_model.d.ts.map +1 -1
  142. package/dist/types/src/scratch_zoom_controls.d.ts +4 -6
  143. package/dist/types/src/scratch_zoom_controls.d.ts.map +1 -1
  144. package/dist/types/src/shadows.d.ts +2 -2
  145. package/dist/types/src/shadows.d.ts.map +1 -1
  146. package/dist/types/src/status_indicator_label.d.ts +4 -6
  147. package/dist/types/src/status_indicator_label.d.ts.map +1 -1
  148. package/dist/types/src/status_indicator_label_flyout_inflater.d.ts +1 -6
  149. package/dist/types/src/status_indicator_label_flyout_inflater.d.ts.map +1 -1
  150. package/dist/types/src/variables.d.ts +4 -8
  151. package/dist/types/src/variables.d.ts.map +1 -1
  152. package/dist/types/src/xml.d.ts +2 -3
  153. package/dist/types/src/xml.d.ts.map +1 -1
  154. package/dist/types/tests/jsunit/block_test.d.ts.map +1 -1
  155. package/dist/types/tests/jsunit/connection_db_test.d.ts.map +1 -1
  156. package/dist/types/tests/jsunit/connection_test.d.ts.map +1 -1
  157. package/dist/types/tests/jsunit/event_test.d.ts.map +1 -1
  158. package/dist/types/tests/jsunit/extensions_test.d.ts.map +1 -1
  159. package/dist/types/tests/jsunit/field_number_test.d.ts.map +1 -1
  160. package/dist/types/tests/jsunit/field_test.d.ts.map +1 -1
  161. package/dist/types/tests/jsunit/field_variable_getter_test.d.ts.map +1 -1
  162. package/dist/types/tests/jsunit/field_variable_test.d.ts.map +1 -1
  163. package/dist/types/tests/jsunit/gesture_test.d.ts.map +1 -1
  164. package/dist/types/tests/jsunit/input_test.d.ts +1 -0
  165. package/dist/types/tests/jsunit/input_test.d.ts.map +1 -1
  166. package/dist/types/tests/jsunit/json_test.d.ts.map +1 -1
  167. package/dist/types/tests/jsunit/names_test.d.ts.map +1 -1
  168. package/dist/types/tests/jsunit/procedure_test.d.ts.map +1 -1
  169. package/dist/types/tests/jsunit/scratch_block_comment_test.d.ts.map +1 -1
  170. package/dist/types/tests/jsunit/svg_test.d.ts.map +1 -1
  171. package/dist/types/tests/jsunit/test_utilities.d.ts.map +1 -1
  172. package/dist/types/tests/jsunit/utils_test.d.ts.map +1 -1
  173. package/dist/types/tests/jsunit/variable_map_test.d.ts.map +1 -1
  174. package/dist/types/tests/jsunit/variable_model_test.d.ts.map +1 -1
  175. package/dist/types/tests/jsunit/widget_div_test.d.ts.map +1 -1
  176. package/dist/types/tests/jsunit/workspace_comment_test.d.ts.map +1 -1
  177. package/dist/types/tests/jsunit/workspace_test.d.ts.map +1 -1
  178. package/dist/types/tests/jsunit/workspace_undo_redo_test.d.ts.map +1 -1
  179. package/dist/types/tests/jsunit/xml_test.d.ts.map +1 -1
  180. package/dist/types/tests/workspace_svg/workspace_svg_test.d.ts.map +1 -1
  181. package/eslint.config.mjs +69 -0
  182. package/i18n/create_scratch_msgs.js +44 -45
  183. package/i18n/js_to_json.js +40 -32
  184. package/i18n/json_to_js.js +37 -37
  185. package/i18n/sync_tx_translations.js +64 -65
  186. package/i18n/test_scratch_msgs.js +66 -63
  187. package/msg/js/en.js +289 -287
  188. package/msg/json/en.json +284 -284
  189. package/msg/messages.js +289 -287
  190. package/msg/scratch_msgs.js +22959 -22970
  191. package/package.json +6 -3
  192. package/prettier.config.mjs +3 -0
  193. package/release.config.js +7 -7
  194. package/renovate.json5 +7 -9
  195. package/src/block_reporting.ts +15 -18
  196. package/src/blocks/colour.ts +12 -15
  197. package/src/blocks/control.ts +167 -177
  198. package/src/blocks/data.ts +225 -292
  199. package/src/blocks/event.ts +121 -123
  200. package/src/blocks/looks.ts +165 -167
  201. package/src/blocks/math.ts +44 -46
  202. package/src/blocks/matrix.ts +11 -13
  203. package/src/blocks/motion.ts +151 -153
  204. package/src/blocks/note.ts +11 -13
  205. package/src/blocks/operators.ts +158 -160
  206. package/src/blocks/procedures.ts +415 -523
  207. package/src/blocks/sensing.ts +163 -165
  208. package/src/blocks/sound.ts +58 -60
  209. package/src/blocks/text.ts +10 -12
  210. package/src/blocks/vertical_extensions.ts +86 -102
  211. package/src/checkable_continuous_flyout.ts +25 -42
  212. package/src/checkbox_bubble.ts +83 -100
  213. package/src/colours.ts +35 -37
  214. package/src/constants.ts +22 -29
  215. package/src/context_menu_items.ts +56 -81
  216. package/src/css.ts +3 -4
  217. package/src/data_category.ts +137 -251
  218. package/src/events/events_block_comment_base.ts +21 -31
  219. package/src/events/events_block_comment_change.ts +21 -42
  220. package/src/events/events_block_comment_collapse.ts +22 -43
  221. package/src/events/events_block_comment_create.ts +29 -46
  222. package/src/events/events_block_comment_delete.ts +10 -19
  223. package/src/events/events_block_comment_move.ts +27 -52
  224. package/src/events/events_block_comment_resize.ts +28 -55
  225. package/src/events/events_block_drag_end.ts +16 -26
  226. package/src/events/events_block_drag_outside.ts +12 -22
  227. package/src/events/events_scratch_variable_create.ts +33 -56
  228. package/src/fields/field_colour_slider.ts +173 -228
  229. package/src/fields/field_matrix.ts +200 -269
  230. package/src/fields/field_note.ts +272 -377
  231. package/src/fields/field_textinput_removable.ts +25 -40
  232. package/src/fields/field_variable_getter.ts +26 -31
  233. package/src/fields/field_vertical_separator.ts +19 -24
  234. package/src/fields/scratch_field_angle.ts +150 -186
  235. package/src/fields/scratch_field_dropdown.ts +15 -19
  236. package/src/fields/scratch_field_number.ts +123 -180
  237. package/src/fields/scratch_field_variable.ts +54 -75
  238. package/src/flyout_checkbox_icon.ts +18 -28
  239. package/src/glows.ts +51 -58
  240. package/src/index.ts +119 -133
  241. package/src/procedures.ts +146 -213
  242. package/src/recyclable_block_flyout_inflater.ts +14 -25
  243. package/src/renderer/bowler_hat.ts +6 -8
  244. package/src/renderer/cat/cat_face.ts +98 -99
  245. package/src/renderer/cat/constants.ts +67 -87
  246. package/src/renderer/cat/drawer.ts +21 -27
  247. package/src/renderer/cat/path_object.ts +3 -5
  248. package/src/renderer/cat/render_info.ts +5 -8
  249. package/src/renderer/cat/renderer.ts +11 -15
  250. package/src/renderer/constants.ts +34 -49
  251. package/src/renderer/drawer.ts +35 -51
  252. package/src/renderer/path_object.ts +4 -10
  253. package/src/renderer/render_info.ts +36 -56
  254. package/src/renderer/renderer.ts +16 -29
  255. package/src/scratch_block_paster.ts +12 -20
  256. package/src/scratch_blocks_utils.ts +4 -7
  257. package/src/scratch_comment_bubble.ts +70 -101
  258. package/src/scratch_comment_icon.ts +74 -123
  259. package/src/scratch_connection_checker.ts +7 -17
  260. package/src/scratch_continuous_category.ts +24 -28
  261. package/src/scratch_continuous_toolbox.ts +20 -27
  262. package/src/scratch_dragger.ts +42 -81
  263. package/src/scratch_insertion_marker_previewer.ts +6 -11
  264. package/src/scratch_variable_map.ts +5 -12
  265. package/src/scratch_variable_model.ts +4 -11
  266. package/src/scratch_zoom_controls.ts +101 -156
  267. package/src/shadows.ts +32 -37
  268. package/src/status_indicator_label.ts +54 -67
  269. package/src/status_indicator_label_flyout_inflater.ts +11 -21
  270. package/src/variables.ts +89 -138
  271. package/src/xml.ts +21 -35
  272. package/tsconfig.json +2 -6
  273. package/types/continuous-toolbox.d.ts +1 -1
  274. package/dist/main.mjs.LICENSE.txt +0 -163
@@ -1,18 +1,16 @@
1
1
  /**
2
- * @license
3
2
  * Copyright 2024 Google LLC
4
3
  * SPDX-License-Identifier: Apache-2.0
5
4
  */
6
-
7
- import * as Blockly from "blockly/core";
8
- import { ConstantProvider } from "./constants";
5
+ import * as Blockly from 'blockly/core'
6
+ import { ConstantProvider } from './constants'
9
7
 
10
8
  export class BowlerHat extends Blockly.blockRendering.Hat {
11
9
  constructor(constants: ConstantProvider) {
12
- super(constants);
10
+ super(constants)
13
11
  // Calculated dynamically by computeBounds_().
14
- this.width = 0;
15
- this.height = constants.BOWLER_HAT_HEIGHT;
16
- this.ascenderHeight = this.height;
12
+ this.width = 0
13
+ this.height = constants.BOWLER_HAT_HEIGHT
14
+ this.ascenderHeight = this.height
17
15
  }
18
16
  }
@@ -1,16 +1,13 @@
1
1
  /**
2
- * @license
3
2
  * Copyright 2026 Scratch Foundation
4
3
  * SPDX-License-Identifier: Apache-2.0
5
4
  */
5
+ import * as Blockly from 'blockly/core'
6
+ import { type ConstantProvider, type CatPathState, PathCapType, PathEarState } from './constants'
7
+ import { type RenderInfo } from './render_info'
8
+ import { type CatScratchRenderer } from './renderer'
6
9
 
7
- import * as Blockly from "blockly/core";
8
-
9
- import { type ConstantProvider, type CatPathState, PathCapType, PathEarState } from "./constants";
10
- import { type CatScratchRenderer } from "./renderer";
11
- import { type RenderInfo } from "./render_info";
12
-
13
- const Svg = Blockly.utils.Svg;
10
+ const Svg = Blockly.utils.Svg
14
11
 
15
12
  enum FacePart {
16
13
  MOUTH,
@@ -24,11 +21,11 @@ enum FacePart {
24
21
 
25
22
  const setVisibility = (element: SVGElement, visible: boolean) => {
26
23
  if (visible) {
27
- element.style.removeProperty("visibility");
24
+ element.style.removeProperty('visibility')
28
25
  } else {
29
- element.style.setProperty("visibility", "hidden");
26
+ element.style.setProperty('visibility', 'hidden')
30
27
  }
31
- };
28
+ }
32
29
 
33
30
  /**
34
31
  * Manages the SVG elements for the cat face.
@@ -36,65 +33,67 @@ const setVisibility = (element: SVGElement, visible: boolean) => {
36
33
  * Owned by the PathObject with similar lifetime.
37
34
  */
38
35
  export class CatFace {
39
- faceGroup_!: SVGElement;
40
- parts_ = {} as Record<FacePart, SVGElement>;
41
- pathEarState: CatPathState;
42
- constants_: ConstantProvider;
43
- renderer_: CatScratchRenderer;
44
- block_: Blockly.BlockSvg;
36
+ faceGroup_!: SVGElement
37
+ parts_ = {} as Record<FacePart, SVGElement>
38
+ pathEarState: CatPathState
39
+ constants_: ConstantProvider
40
+ renderer_: CatScratchRenderer
41
+ block_: Blockly.BlockSvg
45
42
 
46
43
  constructor(info: RenderInfo) {
47
- this.constants_ = info.constants_;
48
- this.renderer_ = info.renderer_;
49
- this.block_ = info.block_;
44
+ this.constants_ = info.constants_
45
+ this.renderer_ = info.renderer_
46
+ this.block_ = info.block_
50
47
  this.pathEarState = {
51
48
  capType: info.isBowlerHatBlock() ? PathCapType.BOWLER : PathCapType.CAP,
52
49
  ear1State: PathEarState.UP,
53
50
  ear2State: PathEarState.UP,
54
- };
51
+ }
55
52
  }
56
53
 
57
54
  /**
58
55
  * Initializes the face SVG elements if they haven't been created yet.
56
+ * @param parent The SVG element to attach the face geometry to.
59
57
  */
60
58
  init(parent: SVGElement) {
61
- if (this.faceGroup_) return;
62
- this.buildFaceGeometry_(parent);
63
- this.setupBlinking_();
64
- this.setupEarFlicks_();
59
+ if (this.faceGroup_) return
60
+ this.buildFaceGeometry_(parent)
61
+ this.setupBlinking_()
62
+ this.setupEarFlicks_()
65
63
  }
66
64
 
67
65
  /**
68
66
  * Updates the transform of the entire face group.
67
+ * @param transform The SVG transform attribute value to apply.
69
68
  */
70
69
  setTransform(transform: string) {
71
70
  if (this.faceGroup_) {
72
- this.faceGroup_.setAttribute("transform", transform);
71
+ this.faceGroup_.setAttribute('transform', transform)
73
72
  }
74
73
  }
75
74
 
76
75
  private setupBlinking_() {
77
- const blinkDuration = 100;
78
- let ignoreBlink = false;
76
+ const blinkDuration = 100
77
+ let ignoreBlink = false
79
78
 
80
79
  // TODO: Would it be better to use CSS for this?
81
- Blockly.browserEvents.bind(this.block_.pathObject.svgPath, "mouseenter", this, () => {
82
- if (ignoreBlink) return;
83
- ignoreBlink = true;
84
- setVisibility(this.parts_[FacePart.EYE_1_OPEN], false);
85
- setVisibility(this.parts_[FacePart.EYE_2_OPEN], false);
86
- setVisibility(this.parts_[FacePart.EYE_1_CLOSED], true);
87
- setVisibility(this.parts_[FacePart.EYE_2_CLOSED], true);
80
+ Blockly.browserEvents.bind(this.block_.pathObject.svgPath, 'mouseenter', this, () => {
81
+ if (ignoreBlink) return
82
+ ignoreBlink = true
83
+ setVisibility(this.parts_[FacePart.EYE_1_OPEN], false)
84
+ setVisibility(this.parts_[FacePart.EYE_2_OPEN], false)
85
+ setVisibility(this.parts_[FacePart.EYE_1_CLOSED], true)
86
+ setVisibility(this.parts_[FacePart.EYE_2_CLOSED], true)
88
87
  setTimeout(() => {
89
- setVisibility(this.parts_[FacePart.EYE_1_OPEN], true);
90
- setVisibility(this.parts_[FacePart.EYE_2_OPEN], true);
91
- setVisibility(this.parts_[FacePart.EYE_1_CLOSED], false);
92
- setVisibility(this.parts_[FacePart.EYE_2_CLOSED], false);
93
- }, blinkDuration);
88
+ setVisibility(this.parts_[FacePart.EYE_1_OPEN], true)
89
+ setVisibility(this.parts_[FacePart.EYE_2_OPEN], true)
90
+ setVisibility(this.parts_[FacePart.EYE_1_CLOSED], false)
91
+ setVisibility(this.parts_[FacePart.EYE_2_CLOSED], false)
92
+ }, blinkDuration)
94
93
  setTimeout(() => {
95
- ignoreBlink = false;
96
- }, 2 * blinkDuration);
97
- });
94
+ ignoreBlink = false
95
+ }, 2 * blinkDuration)
96
+ })
98
97
  }
99
98
 
100
99
  /**
@@ -103,65 +102,65 @@ export class CatFace {
103
102
  * Not necessary for face changes (blinking).
104
103
  */
105
104
  private triggerRedraw() {
106
- this.renderer_.render(this.block_);
105
+ this.renderer_.render(this.block_)
107
106
  }
108
107
 
109
108
  private setupEarFlicks_() {
110
- const flickDuration = 50;
111
- let ignoreFlick1 = false;
112
- let ignoreFlick2 = false;
113
-
114
- Blockly.browserEvents.bind(this.parts_[FacePart.EAR_1_INSIDE], "mouseenter", this, () => {
115
- if (ignoreFlick1) return;
116
- ignoreFlick1 = true;
117
- setVisibility(this.parts_[FacePart.EAR_1_INSIDE], false);
118
- this.pathEarState.ear1State = PathEarState.DOWN;
119
- this.triggerRedraw();
109
+ const flickDuration = 50
110
+ let ignoreFlick1 = false
111
+ let ignoreFlick2 = false
112
+
113
+ Blockly.browserEvents.bind(this.parts_[FacePart.EAR_1_INSIDE], 'mouseenter', this, () => {
114
+ if (ignoreFlick1) return
115
+ ignoreFlick1 = true
116
+ setVisibility(this.parts_[FacePart.EAR_1_INSIDE], false)
117
+ this.pathEarState.ear1State = PathEarState.DOWN
118
+ this.triggerRedraw()
120
119
  setTimeout(() => {
121
- setVisibility(this.parts_[FacePart.EAR_1_INSIDE], true);
122
- this.pathEarState.ear1State = PathEarState.UP;
123
- this.triggerRedraw();
124
- }, flickDuration);
120
+ setVisibility(this.parts_[FacePart.EAR_1_INSIDE], true)
121
+ this.pathEarState.ear1State = PathEarState.UP
122
+ this.triggerRedraw()
123
+ }, flickDuration)
125
124
  setTimeout(() => {
126
- ignoreFlick1 = false;
127
- }, 2 * flickDuration);
128
- });
129
- Blockly.browserEvents.bind(this.parts_[FacePart.EAR_2_INSIDE], "mouseenter", this, () => {
130
- if (ignoreFlick2) return;
131
- ignoreFlick2 = true;
132
- setVisibility(this.parts_[FacePart.EAR_2_INSIDE], false);
133
- this.pathEarState.ear2State = PathEarState.DOWN;
134
- this.triggerRedraw();
125
+ ignoreFlick1 = false
126
+ }, 2 * flickDuration)
127
+ })
128
+ Blockly.browserEvents.bind(this.parts_[FacePart.EAR_2_INSIDE], 'mouseenter', this, () => {
129
+ if (ignoreFlick2) return
130
+ ignoreFlick2 = true
131
+ setVisibility(this.parts_[FacePart.EAR_2_INSIDE], false)
132
+ this.pathEarState.ear2State = PathEarState.DOWN
133
+ this.triggerRedraw()
135
134
  setTimeout(() => {
136
- setVisibility(this.parts_[FacePart.EAR_2_INSIDE], true);
137
- this.pathEarState.ear2State = PathEarState.UP;
138
- this.triggerRedraw();
139
- }, flickDuration);
135
+ setVisibility(this.parts_[FacePart.EAR_2_INSIDE], true)
136
+ this.pathEarState.ear2State = PathEarState.UP
137
+ this.triggerRedraw()
138
+ }, flickDuration)
140
139
  setTimeout(() => {
141
- ignoreFlick2 = false;
142
- }, 2 * flickDuration);
143
- });
140
+ ignoreFlick2 = false
141
+ }, 2 * flickDuration)
142
+ })
144
143
  }
145
144
 
146
145
  private buildFaceGeometry_(parent: SVGElement) {
147
146
  const face = Blockly.utils.dom.createSvgElement(
148
147
  Svg.G,
149
148
  {
150
- fill: "#000000",
149
+ fill: '#000000',
151
150
  // transform set in setTransform()
152
151
  },
153
- parent
154
- );
155
- this.faceGroup_ = face;
152
+ parent,
153
+ )
154
+ this.faceGroup_ = face
156
155
 
157
156
  this.parts_[FacePart.MOUTH] = Blockly.utils.dom.createSvgElement(
158
157
  Svg.PATH,
159
158
  {
160
- "fill-opacity": this.constants_.FACE_OPACITY,
159
+ 'fill-opacity': this.constants_.FACE_OPACITY,
161
160
  d: this.constants_.MOUTH_PATH,
162
161
  },
163
- face
164
- );
162
+ face,
163
+ )
165
164
 
166
165
  this.parts_[FacePart.EAR_1_INSIDE] = Blockly.utils.dom.createSvgElement(
167
166
  Svg.PATH,
@@ -169,8 +168,8 @@ export class CatFace {
169
168
  fill: this.constants_.EAR_INSIDE_COLOR,
170
169
  d: this.constants_.EAR_1_INSIDE_PATH,
171
170
  },
172
- face
173
- );
171
+ face,
172
+ )
174
173
 
175
174
  this.parts_[FacePart.EAR_2_INSIDE] = Blockly.utils.dom.createSvgElement(
176
175
  Svg.PATH,
@@ -178,49 +177,49 @@ export class CatFace {
178
177
  fill: this.constants_.EAR_INSIDE_COLOR,
179
178
  d: this.constants_.EAR_2_INSIDE_PATH,
180
179
  },
181
- face
182
- );
180
+ face,
181
+ )
183
182
 
184
183
  this.parts_[FacePart.EYE_1_OPEN] = Blockly.utils.dom.createSvgElement(
185
184
  Svg.CIRCLE,
186
185
  {
187
- "fill-opacity": this.constants_.FACE_OPACITY,
186
+ 'fill-opacity': this.constants_.FACE_OPACITY,
188
187
  cx: this.constants_.EYE_1_X,
189
188
  cy: this.constants_.EYE_1_Y,
190
189
  r: this.constants_.OPEN_EYE_RADIUS,
191
190
  },
192
- face
193
- );
191
+ face,
192
+ )
194
193
 
195
194
  this.parts_[FacePart.EYE_1_CLOSED] = Blockly.utils.dom.createSvgElement(
196
195
  Svg.PATH,
197
196
  {
198
- "fill-opacity": this.constants_.FACE_OPACITY,
197
+ 'fill-opacity': this.constants_.FACE_OPACITY,
199
198
  d: this.constants_.CLOSED_EYE_1_PATH,
200
199
  },
201
- face
202
- );
203
- setVisibility(this.parts_[FacePart.EYE_1_CLOSED], false);
200
+ face,
201
+ )
202
+ setVisibility(this.parts_[FacePart.EYE_1_CLOSED], false)
204
203
 
205
204
  this.parts_[FacePart.EYE_2_OPEN] = Blockly.utils.dom.createSvgElement(
206
205
  Svg.CIRCLE,
207
206
  {
208
- "fill-opacity": this.constants_.FACE_OPACITY,
207
+ 'fill-opacity': this.constants_.FACE_OPACITY,
209
208
  cx: this.constants_.EYE_2_X,
210
209
  cy: this.constants_.EYE_2_Y,
211
210
  r: this.constants_.OPEN_EYE_RADIUS,
212
211
  },
213
- face
214
- );
212
+ face,
213
+ )
215
214
 
216
215
  this.parts_[FacePart.EYE_2_CLOSED] = Blockly.utils.dom.createSvgElement(
217
216
  Svg.PATH,
218
217
  {
219
- "fill-opacity": this.constants_.FACE_OPACITY,
218
+ 'fill-opacity': this.constants_.FACE_OPACITY,
220
219
  d: this.constants_.CLOSED_EYE_2_PATH,
221
220
  },
222
- face
223
- );
224
- setVisibility(this.parts_[FacePart.EYE_2_CLOSED], false);
221
+ face,
222
+ )
223
+ setVisibility(this.parts_[FacePart.EYE_2_CLOSED], false)
225
224
  }
226
225
  }
@@ -1,112 +1,95 @@
1
1
  /**
2
- * @license
3
2
  * Copyright 2026 Scratch Foundation
4
3
  * SPDX-License-Identifier: Apache-2.0
5
4
  */
6
-
7
- import { ConstantProvider as ClassicConstantProvider } from "../constants";
5
+ import { ConstantProvider as ClassicConstantProvider } from '../constants'
8
6
 
9
7
  export enum PathCapType {
10
- CAP = "CAP",
11
- BOWLER = "BOWLER",
8
+ CAP = 'CAP',
9
+ BOWLER = 'BOWLER',
12
10
  }
13
11
 
14
12
  export enum PathEarState {
15
- DOWN = "DOWN",
16
- UP = "UP",
13
+ DOWN = 'DOWN',
14
+ UP = 'UP',
17
15
  }
18
16
 
19
17
  export interface CatPathState {
20
- capType: PathCapType;
21
- ear1State: PathEarState; // Left ear in LTR, right in RTL
22
- ear2State: PathEarState; // Right ear in LTR, left in RTL
18
+ capType: PathCapType
19
+ ear1State: PathEarState // Left ear in LTR, right in RTL
20
+ ear2State: PathEarState // Right ear in LTR, left in RTL
23
21
  }
24
22
 
25
23
  export class ConstantProvider extends ClassicConstantProvider {
26
- START_HAT_HEIGHT = 31.5;
27
- START_HAT_WIDTH = 96;
24
+ START_HAT_HEIGHT = 31.5
25
+ START_HAT_WIDTH = 96
28
26
 
29
- BOWLER_HAT_HEIGHT = 35;
27
+ BOWLER_HAT_HEIGHT = 35
30
28
 
31
- FACE_OPACITY = 0.6;
29
+ FACE_OPACITY = 0.6
32
30
 
33
- EYE_1_X = 59.2;
34
- EYE_1_Y = -3.3;
35
- EYE_2_X = 29.1;
36
- EYE_2_Y = -3.3;
37
- OPEN_EYE_RADIUS = 3.4;
31
+ EYE_1_X = 59.2
32
+ EYE_1_Y = -3.3
33
+ EYE_2_X = 29.1
34
+ EYE_2_Y = -3.3
35
+ OPEN_EYE_RADIUS = 3.4
38
36
  CLOSED_EYE_1_PATH =
39
- "M25.2-1.1c0.1,0,0.2,0,0.2,0l8.3-2.1l-7-4.8" +
40
- "c-0.5-0.3-1.1-0.2-1.4,0.3s-0.2,1.1,0.3,1.4L29-4.1l-4,1" +
41
- "c-0.5,0.1-0.9,0.7-0.7,1.2C24.3-1.4,24.7-1.1,25.2-1.1z";
37
+ 'M25.2-1.1c0.1,0,0.2,0,0.2,0l8.3-2.1l-7-4.8' +
38
+ 'c-0.5-0.3-1.1-0.2-1.4,0.3s-0.2,1.1,0.3,1.4L29-4.1l-4,1' +
39
+ 'c-0.5,0.1-0.9,0.7-0.7,1.2C24.3-1.4,24.7-1.1,25.2-1.1z'
42
40
  CLOSED_EYE_2_PATH =
43
- "M62.4-1.1c-0.1,0-0.2,0-0.2,0l-8.3-2.1l7-4.8" +
44
- "c0.5-0.3,1.1-0.2,1.4,0.3s0.2,1.1-0.3,1.4l-3.4,2.3l4,1" +
45
- "c0.5,0.1,0.9,0.7,0.7,1.2C63.2-1.4,62.8-1.1,62.4-1.1z";
41
+ 'M62.4-1.1c-0.1,0-0.2,0-0.2,0l-8.3-2.1l7-4.8' +
42
+ 'c0.5-0.3,1.1-0.2,1.4,0.3s0.2,1.1-0.3,1.4l-3.4,2.3l4,1' +
43
+ 'c0.5,0.1,0.9,0.7,0.7,1.2C63.2-1.4,62.8-1.1,62.4-1.1z'
46
44
 
47
45
  MOUTH_PATH =
48
- "M45.6,0.1c-0.9,0-1.7-0.3-2.3-0.9" +
49
- "c-0.6,0.6-1.3,0.9-2.2,0.9c-0.9,0-1.8-0.3-2.3-0.9c-1-1.1-1.1-2.6-1.1-2.8" +
50
- "c0-0.5,0.5-1,1-1l0,0c0.6,0,1,0.5,1,1c0,0.4,0.1,1.7,1.4,1.7" +
51
- "c0.5,0,0.7-0.2,0.8-0.3c0.3-0.3,0.4-1,0.4-1.3c0-0.1,0-0.1,0-0.2" +
52
- "c0-0.5,0.5-1,1-1l0,0c0.5,0,1,0.4,1,1c0,0,0,0.1,0,0.2" +
53
- "c0,0.3,0.1,0.9,0.4,1.2C44.8-2.2,45-2,45.5-2s0.7-0.2,0.8-0.3" +
54
- "c0.3-0.4,0.4-1.1,0.3-1.3c0-0.5,0.4-1,0.9-1.1c0.5,0,1,0.4,1.1,0.9" +
55
- "c0,0.2,0.1,1.8-0.8,2.8C47.5-0.4,46.8,0.1,45.6,0.1z";
56
-
57
- EAR_INSIDE_COLOR = "#FFD5E6";
46
+ 'M45.6,0.1c-0.9,0-1.7-0.3-2.3-0.9' +
47
+ 'c-0.6,0.6-1.3,0.9-2.2,0.9c-0.9,0-1.8-0.3-2.3-0.9c-1-1.1-1.1-2.6-1.1-2.8' +
48
+ 'c0-0.5,0.5-1,1-1l0,0c0.6,0,1,0.5,1,1c0,0.4,0.1,1.7,1.4,1.7' +
49
+ 'c0.5,0,0.7-0.2,0.8-0.3c0.3-0.3,0.4-1,0.4-1.3c0-0.1,0-0.1,0-0.2' +
50
+ 'c0-0.5,0.5-1,1-1l0,0c0.5,0,1,0.4,1,1c0,0,0,0.1,0,0.2' +
51
+ 'c0,0.3,0.1,0.9,0.4,1.2C44.8-2.2,45-2,45.5-2s0.7-0.2,0.8-0.3' +
52
+ 'c0.3-0.4,0.4-1.1,0.3-1.3c0-0.5,0.4-1,0.9-1.1c0.5,0,1,0.4,1.1,0.9' +
53
+ 'c0,0.2,0.1,1.8-0.8,2.8C47.5-0.4,46.8,0.1,45.6,0.1z'
54
+
55
+ EAR_INSIDE_COLOR = '#FFD5E6'
58
56
  EAR_1_INSIDE_PATH =
59
- "M22.4-15.6c-1.7-4.2-4.5-9.1-5.8-8.5" +
60
- "c-1.6,0.8-5.4,7.9-5,15.4c0,0.6,0.7,0.7,1.1,0.5c3-1.6,6.4-2.8,8.6-3.6" +
61
- "C22.8-12.3,23.2-13.7,22.4-15.6z";
57
+ 'M22.4-15.6c-1.7-4.2-4.5-9.1-5.8-8.5' +
58
+ 'c-1.6,0.8-5.4,7.9-5,15.4c0,0.6,0.7,0.7,1.1,0.5c3-1.6,6.4-2.8,8.6-3.6' +
59
+ 'C22.8-12.3,23.2-13.7,22.4-15.6z'
62
60
  EAR_2_INSIDE_PATH =
63
- "M73.1-15.6c1.7-4.2,4.5-9.1,5.8-8.5" +
64
- "c1.6,0.8,5.4,7.9,5,15.4c0,0.6-0.7,0.7-1.1,0.5c-3-1.6-6.4-2.8-8.6-3.6" +
65
- "C72.8-12.3,72.4-13.7,73.1-15.6z";
66
-
67
- CAP_START_PATH = "c2.6,-2.3 5.5,-4.3 8.5,-6.2";
68
- CAP_MIDDLE_PATH = "c8.4,-1.3 17,-1.3 25.4,0";
69
- CAP_END_PATH = "c3,1.8 5.9,3.9 8.5,6.1";
70
-
71
- CAP_EAR_1_UP_PATH =
72
- "c-1,-12.5 5.3,-23.3 8.4,-24.8" + "c3.7,-1.8 16.5,13.1 18.4,15.4";
73
- CAP_EAR_2_UP_PATH =
74
- "c1.9,-2.3 14.7,-17.2 18.4,-15.4" + "c3.1,1.5 9.4,12.3 8.4,24.8";
75
- CAP_EAR_1_DOWN_PATH =
76
- "c-5.8,-4.8 -8,-18 -4.9,-19.5" + "c3.7,-1.8 24.5,11.1 31.7,10.1";
77
- CAP_EAR_2_DOWN_PATH =
78
- "c7.2,1 28,-11.9 31.7,-10.1" + "c3.1,1.5 0.9,14.7 -4.9,19.5";
79
-
80
- BOWLER_START_PATH = ""; // opening curve depends on whether ear 1 is up or down
81
- BOWLER_MIDDLE_PATH = "h33";
82
- BOWLER_END_PATH = "a 20,20 0 0,1 20,20";
83
- BOWLER_EAR_1_UP_PATH =
84
- "c0,-7.1 3.7,-13.3 9.3,-16.9" +
85
- "c1.7,-7.5 5.4,-13.2 7.6,-14.2" +
86
- "c2.6,-1.3 10,6 14.6,11.1";
87
- BOWLER_EAR_2_UP_PATH =
88
- "c4.6,-5.1 11.9,-12.4 14.6,-11.1" +
89
- "c1.9,0.9 4.9,5.2 6.8,11.1" +
90
- "h7.8";
61
+ 'M73.1-15.6c1.7-4.2,4.5-9.1,5.8-8.5' +
62
+ 'c1.6,0.8,5.4,7.9,5,15.4c0,0.6-0.7,0.7-1.1,0.5c-3-1.6-6.4-2.8-8.6-3.6' +
63
+ 'C72.8-12.3,72.4-13.7,73.1-15.6z'
64
+
65
+ CAP_START_PATH = 'c2.6,-2.3 5.5,-4.3 8.5,-6.2'
66
+ CAP_MIDDLE_PATH = 'c8.4,-1.3 17,-1.3 25.4,0'
67
+ CAP_END_PATH = 'c3,1.8 5.9,3.9 8.5,6.1'
68
+
69
+ CAP_EAR_1_UP_PATH = 'c-1,-12.5 5.3,-23.3 8.4,-24.8' + 'c3.7,-1.8 16.5,13.1 18.4,15.4'
70
+ CAP_EAR_2_UP_PATH = 'c1.9,-2.3 14.7,-17.2 18.4,-15.4' + 'c3.1,1.5 9.4,12.3 8.4,24.8'
71
+ CAP_EAR_1_DOWN_PATH = 'c-5.8,-4.8 -8,-18 -4.9,-19.5' + 'c3.7,-1.8 24.5,11.1 31.7,10.1'
72
+ CAP_EAR_2_DOWN_PATH = 'c7.2,1 28,-11.9 31.7,-10.1' + 'c3.1,1.5 0.9,14.7 -4.9,19.5'
73
+
74
+ BOWLER_START_PATH = '' // opening curve depends on whether ear 1 is up or down
75
+ BOWLER_MIDDLE_PATH = 'h33'
76
+ BOWLER_END_PATH = 'a 20,20 0 0,1 20,20'
77
+ BOWLER_EAR_1_UP_PATH = 'c0,-7.1 3.7,-13.3 9.3,-16.9' + 'c1.7,-7.5 5.4,-13.2 7.6,-14.2' + 'c2.6,-1.3 10,6 14.6,11.1'
78
+ BOWLER_EAR_2_UP_PATH = 'c4.6,-5.1 11.9,-12.4 14.6,-11.1' + 'c1.9,0.9 4.9,5.2 6.8,11.1' + 'h7.8'
91
79
  BOWLER_EAR_1_DOWN_PATH =
92
- "c0,-4.6 1.6,-8.9 4.3,-12.3" +
93
- "c-2.4,-5.6 -2.9,-12.4 -0.7,-13.4" +
94
- "c2.1,-1 9.6,2.6 17,5.8" +
95
- "h10.9";
96
- BOWLER_EAR_2_DOWN_PATH =
97
- "h11" +
98
- "c7.4,-3.2 14.8,-6.8 16.9,-5.8" +
99
- "c1.2,0.6 1.6,2.9 1.3,5.8";
80
+ 'c0,-4.6 1.6,-8.9 4.3,-12.3' + 'c-2.4,-5.6 -2.9,-12.4 -0.7,-13.4' + 'c2.1,-1 9.6,2.6 17,5.8' + 'h10.9'
81
+ BOWLER_EAR_2_DOWN_PATH = 'h11' + 'c7.4,-3.2 14.8,-6.8 16.9,-5.8' + 'c1.2,0.6 1.6,2.9 1.3,5.8'
100
82
 
101
83
  // This number was determined experimentally:
102
84
  // - The 17 came from zooming in on a "define" block and iterating to get a near-vertical edge.
103
85
  // - The .7 came from measuring the width of the other parts of the SVG path.
104
- BOWLER_WIDTH_MAGIC = 17.7;
86
+ BOWLER_WIDTH_MAGIC = 17.7
105
87
 
106
88
  /**
107
89
  * Make the starting portion of a block's hat.
108
90
  * The return value will be stored as START_HAT.
109
91
  * In the case of cat blocks, this is just a placeholder for sizing.
92
+ * @returns An object containing the hat's height and width dimensions.
110
93
  */
111
94
  override makeStartHat() {
112
95
  return {
@@ -117,20 +100,17 @@ export class ConstantProvider extends ClassicConstantProvider {
117
100
  ear1State: PathEarState.UP,
118
101
  ear2State: PathEarState.UP,
119
102
  }),
120
- };
103
+ }
121
104
  }
122
105
 
123
106
  makeCatPath(width: number, state: CatPathState) {
124
- const pathStart = this[`${state.capType}_START_PATH`];
125
- const pathEar1 =
126
- this[`${state.capType}_EAR_1_${state.ear1State}_PATH`];
127
- const pathMiddle = this[`${state.capType}_MIDDLE_PATH`];
128
- const pathEar2 =
129
- this[`${state.capType}_EAR_2_${state.ear2State}_PATH`];
130
- const spacer = (state.capType === PathCapType.BOWLER)
131
- ? `l ${width - this.START_HAT_WIDTH - this.BOWLER_WIDTH_MAGIC} 0`
132
- : ""; // caps don't need an internal spacer like bowlers do
133
- const pathEnd = this[`${state.capType}_END_PATH`];
134
- return `${pathStart}${pathEar1}${pathMiddle}${pathEar2}${spacer}${pathEnd}`;
107
+ const pathStart = this[`${state.capType}_START_PATH`]
108
+ const pathEar1 = this[`${state.capType}_EAR_1_${state.ear1State}_PATH`]
109
+ const pathMiddle = this[`${state.capType}_MIDDLE_PATH`]
110
+ const pathEar2 = this[`${state.capType}_EAR_2_${state.ear2State}_PATH`]
111
+ const spacer =
112
+ state.capType === PathCapType.BOWLER ? `l ${width - this.START_HAT_WIDTH - this.BOWLER_WIDTH_MAGIC} 0` : '' // caps don't need an internal spacer like bowlers do
113
+ const pathEnd = this[`${state.capType}_END_PATH`]
114
+ return `${pathStart}${pathEar1}${pathMiddle}${pathEar2}${spacer}${pathEnd}`
135
115
  }
136
116
  }
@@ -1,24 +1,21 @@
1
1
  /**
2
- * @license
3
2
  * Copyright 2026 Scratch Foundation
4
3
  * SPDX-License-Identifier: Apache-2.0
5
4
  */
6
-
7
- import { Drawer as ClassicDrawer } from "../drawer";
8
-
9
- import { type ConstantProvider } from "./constants";
10
- import { type PathObject } from "./path_object";
11
- import { type RenderInfo } from "./render_info";
12
- import { CatFace } from "./cat_face";
5
+ import { Drawer as ClassicDrawer } from '../drawer'
6
+ import { CatFace } from './cat_face'
7
+ import { type ConstantProvider } from './constants'
8
+ import { type PathObject } from './path_object'
9
+ import { type RenderInfo } from './render_info'
13
10
 
14
11
  export class Drawer extends ClassicDrawer {
15
- declare constants_: ConstantProvider;
16
- declare info_: RenderInfo;
12
+ declare constants_: ConstantProvider
13
+ declare info_: RenderInfo
17
14
 
18
15
  override draw() {
19
16
  // Make sure the face exists if we need it.
20
17
  if (this.block_.hat) {
21
- const pathObject = this.block_.pathObject as PathObject;
18
+ const pathObject = this.block_.pathObject as PathObject
22
19
 
23
20
  if (!pathObject.catFace) {
24
21
  // Initialize the persistent face view.
@@ -26,38 +23,35 @@ export class Drawer extends ClassicDrawer {
26
23
  // Drawer and RenderInfo only exist during `Renderer.render(block)`.
27
24
  // Block, PathObject, and CatFace last for the lifetime of the block.
28
25
  // ConstantsProvider and the Renderer last for the lifetime of the workspace.
29
- pathObject.catFace = new CatFace(this.info_);
30
- pathObject.catFace.init(this.block_.getSvgRoot());
26
+ pathObject.catFace = new CatFace(this.info_)
27
+ pathObject.catFace.init(this.block_.getSvgRoot())
31
28
  }
32
29
  }
33
30
 
34
- super.draw();
31
+ super.draw()
35
32
  }
36
33
 
37
34
  override drawInternals_() {
38
- super.drawInternals_();
35
+ super.drawInternals_()
39
36
 
40
- const pathObject = this.block_.pathObject as PathObject;
41
- const catFace = pathObject.catFace;
37
+ const pathObject = this.block_.pathObject as PathObject
38
+ const catFace = pathObject.catFace
42
39
  if (catFace) {
43
40
  // Update the transform for the whole group
44
- const transformParts: string[] = [];
41
+ const transformParts: string[] = []
45
42
  if (this.info_.RTL) {
46
- transformParts.push("scale(-1 1)");
43
+ transformParts.push('scale(-1 1)')
47
44
  }
48
- transformParts.push(`translate(0, ${this.info_.startY})`);
49
- catFace.setTransform(transformParts.join(" "));
45
+ transformParts.push(`translate(0, ${this.info_.startY})`)
46
+ catFace.setTransform(transformParts.join(' '))
50
47
  }
51
48
  }
52
49
 
53
50
  override makeReplacementTop_() {
54
51
  if (!this.block_.hat) {
55
- return super.makeReplacementTop_();
52
+ return super.makeReplacementTop_()
56
53
  }
57
- const pathObject = this.block_.pathObject as PathObject;
58
- return this.constants_.makeCatPath(
59
- this.info_.width,
60
- pathObject.catFace!.pathEarState
61
- );
54
+ const pathObject = this.block_.pathObject as PathObject
55
+ return this.constants_.makeCatPath(this.info_.width, pathObject.catFace!.pathEarState)
62
56
  }
63
57
  }
@@ -1,16 +1,14 @@
1
1
  /**
2
- * @license
3
2
  * Copyright 2026 Scratch Foundation
4
3
  * SPDX-License-Identifier: Apache-2.0
5
4
  */
6
-
7
- import { PathObject as ClassicPathObject } from "../path_object";
8
- import { type CatFace } from "./cat_face";
5
+ import { PathObject as ClassicPathObject } from '../path_object'
6
+ import { type CatFace } from './cat_face'
9
7
 
10
8
  export class PathObject extends ClassicPathObject {
11
9
  /**
12
10
  * The face view for this block.
13
11
  * Only valid if this block has a hat and therefore should have a face.
14
12
  */
15
- catFace?: CatFace;
13
+ catFace?: CatFace
16
14
  }