kasaframe 0.1.4 → 0.1.6

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 (374) hide show
  1. package/NOTICE +311 -0
  2. package/README.md +18 -5
  3. package/docs/AGENTS.md +2 -1
  4. package/package.json +1 -1
  5. package/packages/adapters/src/project.ts +2 -0
  6. package/packages/check/package.json +1 -0
  7. package/packages/check/src/check.ts +8 -2
  8. package/packages/check/src/rules/frames.ts +4 -5
  9. package/packages/cli/src/commands/doctor.ts +15 -2
  10. package/packages/cli/src/commands/fonts.ts +118 -0
  11. package/packages/cli/src/commands/make.ts +15 -5
  12. package/packages/cli/src/commands/render.ts +34 -7
  13. package/packages/cli/src/commands/update.ts +66 -0
  14. package/packages/cli/src/fonts.ts +405 -0
  15. package/packages/cli/src/kf.ts +5 -0
  16. package/packages/cli/src/mix.ts +66 -4
  17. package/packages/cli/src/segments.ts +1 -1
  18. package/packages/cli/src/sfx.ts +429 -0
  19. package/packages/cli/src/update.ts +250 -0
  20. package/packages/core/src/frame.ts +7 -4
  21. package/packages/core/src/index.ts +3 -1
  22. package/packages/core/src/project.ts +19 -0
  23. package/packages/core/src/sfx.ts +70 -0
  24. package/packages/director/src/assemble.ts +7 -4
  25. package/packages/director/src/index.ts +1 -1
  26. package/packages/director/src/pattern.ts +2 -0
  27. package/packages/director/src/scene.ts +14 -5
  28. package/packages/director/src/transitions.ts +21 -8
  29. package/packages/motion/src/enter.ts +7 -1
  30. package/packages/motion/src/impact.ts +5 -2
  31. package/packages/motion/src/moves/dress.ts +15 -2
  32. package/packages/motion/src/moves/menu.ts +11 -5
  33. package/packages/motion/src/transition.ts +3 -1
  34. package/packages/motion/src/transition3d/index.ts +3 -1
  35. package/packages/motion/src/transition3d/live.ts +5 -3
  36. package/packages/patterns/src/bars/rank.ts +6 -7
  37. package/packages/patterns/src/before-after/shrink.ts +3 -4
  38. package/packages/patterns/src/before-after/strike.ts +4 -5
  39. package/packages/patterns/src/code/terminal.ts +25 -16
  40. package/packages/patterns/src/end/lockup.ts +13 -10
  41. package/packages/patterns/src/end/slam.ts +7 -5
  42. package/packages/patterns/src/hook-number/counter.ts +15 -9
  43. package/packages/patterns/src/hook-number/slam.ts +6 -8
  44. package/packages/patterns/src/kit.ts +281 -58
  45. package/packages/patterns/src/limit/gauge.ts +16 -11
  46. package/packages/patterns/src/quote/karaoke.ts +17 -12
  47. package/packages/patterns/src/sfx.ts +80 -0
  48. package/packages/patterns/src/term-reveal/chips.ts +24 -10
  49. package/packages/patterns/src/term-reveal/expand.ts +17 -13
  50. package/packages/patterns/src/title/mask.ts +9 -8
  51. package/packages/patterns/src/title/slam.ts +1 -1
  52. package/packages/patterns/src/types.ts +1 -0
  53. package/packages/plan/src/asks.ts +1 -1
  54. package/packages/plan/src/brief.ts +5 -2
  55. package/packages/plan/src/themes.ts +8 -2
  56. package/packages/themes/kit/THEME-MAKE.md +2 -2
  57. package/packages/themes/kit/fonts/display.json +3517 -0
  58. package/packages/themes/kit/fonts/sans.json +5155 -0
  59. package/packages/themes/kit/fonts/serif.json +5229 -0
  60. package/packages/themes/kit/fonts.json +243 -79
  61. package/packages/themes/package.json +3 -1
  62. package/packages/themes/src/fontfile.ts +183 -0
  63. package/packages/themes/src/fonts.ts +296 -0
  64. package/packages/themes/src/index.ts +32 -2
  65. package/packages/themes/src/look.ts +34 -8
  66. package/packages/themes/src/slots.ts +32 -2
  67. package/packages/themes/src/types.ts +33 -0
  68. package/packages/themes/src/vary.ts +35 -34
  69. package/presets/kawaii-pastel.json +2 -2
  70. package/sfx/README.md +82 -0
  71. package/sfx/click/appear.wav +0 -0
  72. package/sfx/click/burst.wav +0 -0
  73. package/sfx/click/drop.wav +0 -0
  74. package/sfx/click/end.wav +0 -0
  75. package/sfx/click/hop.wav +0 -0
  76. package/sfx/click/land.wav +0 -0
  77. package/sfx/click/select.wav +0 -0
  78. package/sfx/click/stick.wav +0 -0
  79. package/sfx/click/tick.wav +0 -0
  80. package/sfx/click/type.wav +0 -0
  81. package/sfx/click/whoosh.wav +0 -0
  82. package/sfx/pop/appear.wav +0 -0
  83. package/sfx/pop/burst.wav +0 -0
  84. package/sfx/pop/drop.wav +0 -0
  85. package/sfx/pop/end.wav +0 -0
  86. package/sfx/pop/hop.wav +0 -0
  87. package/sfx/pop/land.wav +0 -0
  88. package/sfx/pop/select.wav +0 -0
  89. package/sfx/pop/stick.wav +0 -0
  90. package/sfx/pop/tick.wav +0 -0
  91. package/sfx/pop/type.wav +0 -0
  92. package/sfx/pop/whoosh.wav +0 -0
  93. package/sfx/tags.json +545 -0
  94. package/sfx/ui/appear.wav +0 -0
  95. package/sfx/ui/burst.wav +0 -0
  96. package/sfx/ui/drop.wav +0 -0
  97. package/sfx/ui/end.wav +0 -0
  98. package/sfx/ui/hop.wav +0 -0
  99. package/sfx/ui/land.wav +0 -0
  100. package/sfx/ui/select.wav +0 -0
  101. package/sfx/ui/stick.wav +0 -0
  102. package/sfx/ui/tick.wav +0 -0
  103. package/sfx/ui/type.wav +0 -0
  104. package/sfx/ui/whoosh.wav +0 -0
  105. package/skills/kasaframe/SKILL.md +1 -0
  106. package/themes/blueprint/sample/style.json +5 -5
  107. package/themes/blueprint/style.json +5 -5
  108. package/themes/blueprint/theme.json +3 -1
  109. package/themes/blueprint/variants/deep-rose-suit.json +1 -1
  110. package/themes/blueprint/variants/navy-coral-2.json +1 -1
  111. package/themes/blueprint/variants/navy-coral-suit.json +1 -1
  112. package/themes/blueprint/variants/navy-orange-2.json +1 -1
  113. package/themes/blueprint/variants/navy-orange-suit.json +1 -1
  114. package/themes/cartography/sample/style.json +2 -2
  115. package/themes/cartography/style.json +2 -2
  116. package/themes/cartography/theme.json +3 -1
  117. package/themes/cartography/variants/deep-plum.json +1 -1
  118. package/themes/cartography/variants/frost-teal.json +1 -1
  119. package/themes/cartography/variants/navy-green.json +1 -1
  120. package/themes/circuit-board/sample/style.json +2 -2
  121. package/themes/circuit-board/style.json +2 -2
  122. package/themes/circuit-board/theme.json +3 -1
  123. package/themes/circuit-board/variants/dusk-gold-pretendard.json +1 -1
  124. package/themes/circuit-board/variants/navy-gold-grain.json +1 -1
  125. package/themes/circuit-board/variants/wine-gold-pretendard.json +1 -1
  126. package/themes/clay-toy/sample/style.json +2 -2
  127. package/themes/clay-toy/style.json +2 -2
  128. package/themes/clay-toy/theme.json +3 -1
  129. package/themes/clay-toy/variants/blush-coral-grain.json +1 -1
  130. package/themes/clay-toy/variants/chalk-teal.json +1 -1
  131. package/themes/clay-toy/variants/frost-sky.json +1 -1
  132. package/themes/clay-toy/variants/frost-teal.json +1 -1
  133. package/themes/clay-toy/variants/lilac-plum-round.json +1 -1
  134. package/themes/clay-toy/variants/lilac-plum.json +1 -1
  135. package/themes/clay-toy/variants/sage-indigo.json +1 -1
  136. package/themes/conveyor-factory/sample/style.json +3 -3
  137. package/themes/conveyor-factory/style.json +3 -3
  138. package/themes/conveyor-factory/theme.json +3 -1
  139. package/themes/conveyor-factory/variants/cocoa-gold.json +1 -1
  140. package/themes/conveyor-factory/variants/navy-gold.json +1 -1
  141. package/themes/conveyor-factory/variants/slate-amber-2.json +1 -1
  142. package/themes/conveyor-factory/variants/slate-amber-suit.json +1 -1
  143. package/themes/conveyor-factory/variants/slate-gold-bold.json +1 -1
  144. package/themes/data-journal/theme.json +3 -1
  145. package/themes/data-journal/variants/deep-coral.json +1 -1
  146. package/themes/data-journal/variants/navy-lime.json +1 -1
  147. package/themes/data-journal/variants/wine-indigo.json +1 -1
  148. package/themes/debug-hud/sample/style.json +1 -1
  149. package/themes/debug-hud/style.json +1 -1
  150. package/themes/debug-hud/theme.json +2 -1
  151. package/themes/debug-hud/variants/cocoa-teal.json +2 -2
  152. package/themes/debug-hud/variants/deep-teal-scan.json +2 -2
  153. package/themes/debug-hud/variants/dusk-plum.json +2 -2
  154. package/themes/debug-hud/variants/forest-lime.json +2 -2
  155. package/themes/debug-hud/variants/slate-green.json +2 -2
  156. package/themes/debug-hud/variants/wine-gold.json +2 -2
  157. package/themes/depth-flight/sample/style.json +1 -1
  158. package/themes/depth-flight/style.json +1 -1
  159. package/themes/depth-flight/theme.json +3 -1
  160. package/themes/depth-flight/variants/cocoa-cyan.json +1 -1
  161. package/themes/depth-flight/variants/cocoa-violet.json +1 -1
  162. package/themes/depth-flight/variants/deep-sky.json +1 -1
  163. package/themes/depth-flight/variants/forest-blue.json +1 -1
  164. package/themes/depth-flight/variants/navy-sky-grain.json +1 -1
  165. package/themes/depth-flight/variants/navy-sky.json +1 -1
  166. package/themes/depth-flight/variants/night-teal.json +1 -1
  167. package/themes/depth-flight/variants/slate-indigo.json +1 -1
  168. package/themes/depth-flight/variants/slate-violet.json +1 -1
  169. package/themes/film-reel/sample/style.json +2 -2
  170. package/themes/film-reel/style.json +2 -2
  171. package/themes/film-reel/theme.json +3 -1
  172. package/themes/film-reel/variants/chalk-pink.json +1 -1
  173. package/themes/film-reel/variants/lilac-gold.json +1 -1
  174. package/themes/film-reel/variants/lilac-violet.json +1 -1
  175. package/themes/glass-light/sample/style.json +1 -1
  176. package/themes/glass-light/style.json +1 -1
  177. package/themes/glass-light/theme.json +3 -1
  178. package/themes/glass-light/variants/blush-pink.json +1 -1
  179. package/themes/glass-light/variants/blush-plum.json +1 -1
  180. package/themes/glass-light/variants/cream-violet.json +1 -1
  181. package/themes/glass-light/variants/frost-sky-suit.json +1 -1
  182. package/themes/glass-light/variants/frost-sky.json +1 -1
  183. package/themes/glass-light/variants/sage-green.json +1 -1
  184. package/themes/ink-wash/sample/style.json +3 -3
  185. package/themes/ink-wash/style.json +3 -3
  186. package/themes/ink-wash/theme.json +3 -1
  187. package/themes/iso-diorama/sample/style.json +1 -1
  188. package/themes/iso-diorama/style.json +1 -1
  189. package/themes/iso-diorama/theme.json +3 -1
  190. package/themes/iso-diorama/variants/chalk-plum.json +1 -1
  191. package/themes/iso-diorama/variants/cocoa-indigo.json +1 -1
  192. package/themes/iso-diorama/variants/dusk-blue.json +1 -1
  193. package/themes/iso-diorama/variants/dusk-coral.json +1 -1
  194. package/themes/iso-diorama/variants/dusk-jade.json +1 -1
  195. package/themes/iso-diorama/variants/forest-cyan.json +1 -1
  196. package/themes/iso-diorama/variants/frost-green.json +1 -1
  197. package/themes/iso-diorama/variants/frost-teal.json +1 -1
  198. package/themes/iso-diorama/variants/navy-amber.json +1 -1
  199. package/themes/isotype/sample/style.json +2 -2
  200. package/themes/isotype/style.json +2 -2
  201. package/themes/isotype/theme.json +2 -1
  202. package/themes/isotype/variants/blush-rose.json +1 -1
  203. package/themes/isotype/variants/chalk-coral.json +1 -1
  204. package/themes/isotype/variants/chalk-orange.json +1 -1
  205. package/themes/isotype/variants/frost-amber.json +1 -1
  206. package/themes/isotype/variants/frost-coral.json +1 -1
  207. package/themes/isotype/variants/frost-orange.json +1 -1
  208. package/themes/isotype/variants/sand-amber.json +1 -1
  209. package/themes/kawaii-sticker/effects.ts +15 -3
  210. package/themes/kawaii-sticker/sample/style.json +2 -2
  211. package/themes/kawaii-sticker/style.json +2 -2
  212. package/themes/kawaii-sticker/theme.json +4 -1
  213. package/themes/kawaii-sticker/variants/cream-gold.json +1 -1
  214. package/themes/kawaii-sticker/variants/dusk-green.json +1 -1
  215. package/themes/kawaii-sticker/variants/dusk-indigo.json +1 -1
  216. package/themes/kawaii-sticker/variants/dusk-sky.json +1 -1
  217. package/themes/kawaii-sticker/variants/dusk-teal.json +1 -1
  218. package/themes/kawaii-sticker/variants/frost-blue.json +1 -1
  219. package/themes/kawaii-sticker/variants/frost-plum.json +1 -1
  220. package/themes/kawaii-sticker/variants/lilac-violet.json +1 -1
  221. package/themes/kawaii-sticker/variants/navy-gold.json +1 -1
  222. package/themes/kawaii-sticker/variants/navy-plum.json +1 -1
  223. package/themes/lab-notebook/sample/style.json +3 -3
  224. package/themes/lab-notebook/style.json +3 -3
  225. package/themes/lab-notebook/theme.json +2 -1
  226. package/themes/lab-notebook/variants/blush-orange.json +1 -1
  227. package/themes/lab-notebook/variants/chalk-coral.json +1 -1
  228. package/themes/lab-notebook/variants/chalk-orange.json +1 -1
  229. package/themes/lab-notebook/variants/chalk-rose.json +1 -1
  230. package/themes/lab-notebook/variants/lilac-rose.json +1 -1
  231. package/themes/lab-notebook/variants/sage-rose.json +1 -1
  232. package/themes/lab-notebook/variants/sand-orange.json +1 -1
  233. package/themes/lab-notebook/variants/snow-orange.json +1 -1
  234. package/themes/lab-notebook/variants/snow-rose.json +1 -1
  235. package/themes/manga-panel/sample/style.json +3 -3
  236. package/themes/manga-panel/style.json +3 -3
  237. package/themes/manga-panel/theme.json +3 -1
  238. package/themes/manga-panel/variants/chalk-cyan-dots.json +1 -1
  239. package/themes/manga-panel/variants/chalk-rose.json +1 -1
  240. package/themes/manga-panel/variants/snow-cyan.json +1 -1
  241. package/themes/manga-panel/variants/snow-magenta-dots.json +1 -1
  242. package/themes/marble-run/sample/style.json +2 -2
  243. package/themes/marble-run/style.json +2 -2
  244. package/themes/marble-run/theme.json +3 -1
  245. package/themes/marble-run/variants/slate-orange.json +1 -1
  246. package/themes/neon-sign/sample/style.json +2 -2
  247. package/themes/neon-sign/style.json +2 -2
  248. package/themes/neon-sign/theme.json +2 -1
  249. package/themes/neon-sign/variants/dusk-plum.json +1 -1
  250. package/themes/neon-sign/variants/forest-magenta.json +1 -1
  251. package/themes/neon-sign/variants/night-pink.json +1 -1
  252. package/themes/neon-sign/variants/night-violet.json +1 -1
  253. package/themes/neon-sign/variants/slate-violet.json +1 -1
  254. package/themes/newspaper/sample/style.json +2 -2
  255. package/themes/newspaper/style.json +2 -2
  256. package/themes/newspaper/theme.json +2 -1
  257. package/themes/newspaper/variants/blush-amber.json +1 -1
  258. package/themes/newspaper/variants/chalk-magenta.json +1 -1
  259. package/themes/newspaper/variants/frost-sky.json +1 -1
  260. package/themes/newspaper/variants/lilac-green.json +1 -1
  261. package/themes/newspaper/variants/sage-lime.json +1 -1
  262. package/themes/og-measure/THEME.md +41 -6
  263. package/themes/og-measure/effects.ts +236 -115
  264. package/themes/og-measure/sample/assets/brand/og-logo.svg +11 -11
  265. package/themes/og-measure/sample/lib/data.ts +6 -0
  266. package/themes/og-measure/sample/scenes/end.ts +14 -10
  267. package/themes/og-measure/sample/scenes/gather.ts +4 -1
  268. package/themes/og-measure/sample/scenes/models.ts +5 -2
  269. package/themes/og-measure/sample/scenes/one.ts +9 -6
  270. package/themes/og-measure/sample/scenes/price.ts +8 -3
  271. package/themes/og-measure/sample/style.json +30 -35
  272. package/themes/og-measure/slots.ts +54 -30
  273. package/themes/og-measure/still.png +0 -0
  274. package/themes/og-measure/style.json +30 -35
  275. package/themes/og-measure/theme.json +72 -49
  276. package/themes/og-measure/variants/snow-blue.json +90 -0
  277. package/themes/orbit-system/sample/style.json +3 -3
  278. package/themes/orbit-system/style.json +3 -3
  279. package/themes/orbit-system/theme.json +3 -1
  280. package/themes/orbit-system/variants/cocoa-amber.json +1 -1
  281. package/themes/orbit-system/variants/cocoa-cyan.json +1 -1
  282. package/themes/orbit-system/variants/dusk-magenta.json +1 -1
  283. package/themes/orbit-system/variants/dusk-violet.json +1 -1
  284. package/themes/orbit-system/variants/forest-coral.json +1 -1
  285. package/themes/orbit-system/variants/wine-amber.json +1 -1
  286. package/themes/orbit-system/variants/wine-magenta.json +1 -1
  287. package/themes/origami-fold/sample/style.json +1 -1
  288. package/themes/origami-fold/style.json +1 -1
  289. package/themes/origami-fold/theme.json +3 -1
  290. package/themes/origami-fold/variants/deep-amber-sunflower.json +1 -1
  291. package/themes/origami-fold/variants/deep-orange.json +1 -1
  292. package/themes/origami-fold/variants/forest-coral.json +1 -1
  293. package/themes/origami-fold/variants/forest-pink.json +1 -1
  294. package/themes/origami-fold/variants/frost-amber-paper.json +1 -1
  295. package/themes/origami-fold/variants/sage-coral-sunflower.json +1 -1
  296. package/themes/origami-fold/variants/sage-coral.json +1 -1
  297. package/themes/origami-fold/variants/sage-pink-round.json +1 -1
  298. package/themes/origami-fold/variants/sage-pink.json +1 -1
  299. package/themes/paper-cutout/sample/style.json +2 -2
  300. package/themes/paper-cutout/style.json +2 -2
  301. package/themes/paper-cutout/theme.json +3 -1
  302. package/themes/paper-cutout/variants/blush-violet.json +1 -1
  303. package/themes/paper-cutout/variants/frost-lime.json +1 -1
  304. package/themes/paper-cutout/variants/lilac-gold.json +1 -1
  305. package/themes/paper-cutout/variants/sage-cyan.json +1 -1
  306. package/themes/paper-cutout/variants/sage-green.json +1 -1
  307. package/themes/paper-cutout/variants/sage-pink.json +1 -1
  308. package/themes/paper-cutout/variants/sand-blue.json +1 -1
  309. package/themes/pixel-quest/theme.json +2 -1
  310. package/themes/receipt/sample/style.json +2 -2
  311. package/themes/receipt/style.json +2 -2
  312. package/themes/riso-zine/sample/style.json +2 -2
  313. package/themes/riso-zine/style.json +2 -2
  314. package/themes/riso-zine/theme.json +3 -1
  315. package/themes/riso-zine/variants/chalk-lime.json +1 -1
  316. package/themes/riso-zine/variants/frost-green.json +1 -1
  317. package/themes/riso-zine/variants/lilac-plum.json +1 -1
  318. package/themes/riso-zine/variants/lilac-violet.json +1 -1
  319. package/themes/server-hall/sample/style.json +2 -2
  320. package/themes/server-hall/style.json +2 -2
  321. package/themes/server-hall/theme.json +3 -1
  322. package/themes/server-hall/variants/night-indigo.json +1 -1
  323. package/themes/server-hall/variants/wine-plum.json +1 -1
  324. package/themes/subway-map/sample/style.json +2 -2
  325. package/themes/subway-map/style.json +2 -2
  326. package/themes/subway-map/theme.json +3 -1
  327. package/themes/subway-map/variants/deep-green.json +1 -1
  328. package/themes/subway-map/variants/deep-teal.json +1 -1
  329. package/themes/subway-map/variants/frost-jade.json +1 -1
  330. package/themes/subway-map/variants/frost-teal.json +1 -1
  331. package/themes/subway-map/variants/slate-green.json +1 -1
  332. package/themes/subway-map/variants/snow-jade.json +1 -1
  333. package/themes/swiss-poster/sample/style.json +2 -2
  334. package/themes/swiss-poster/style.json +2 -2
  335. package/themes/swiss-poster/theme.json +3 -1
  336. package/themes/swiss-poster/variants/chalk-plum.json +1 -1
  337. package/themes/swiss-poster/variants/cocoa-cyan.json +1 -1
  338. package/themes/swiss-poster/variants/dusk-magenta.json +1 -1
  339. package/themes/swiss-poster/variants/frost-indigo.json +1 -1
  340. package/themes/swiss-poster/variants/slate-orange.json +1 -1
  341. package/themes/water-works/sample/style.json +1 -1
  342. package/themes/water-works/style.json +1 -1
  343. package/themes/water-works/theme.json +3 -1
  344. package/themes/water-works/variants/chalk-cyan.json +1 -1
  345. package/themes/water-works/variants/frost-indigo.json +1 -1
  346. package/themes/water-works/variants/sand-amber.json +1 -1
  347. package/themes/water-works/variants/sand-plum.json +1 -1
  348. package/themes/whiteboard/sample/style.json +2 -2
  349. package/themes/whiteboard/style.json +2 -2
  350. package/themes/whiteboard/theme.json +3 -1
  351. package/themes/whiteboard/variants/chalk-coral.json +1 -1
  352. package/themes/whiteboard/variants/cream-lime.json +1 -1
  353. package/themes/whiteboard/variants/frost-teal.json +1 -1
  354. package/themes/whiteboard/variants/lilac-indigo.json +1 -1
  355. package/themes/whiteboard/variants/sage-plum.json +1 -1
  356. package/themes/whiteboard/variants/snow-cyan.json +1 -1
  357. package/themes/whiteboard/variants/snow-green.json +1 -1
  358. package/themes/whiteboard/variants/snow-magenta.json +1 -1
  359. package/themes/og-measure/sample/assets/brand/og-logo-full.svg +0 -12
  360. package/themes/og-measure/variants/chalk-orange.json +0 -102
  361. package/themes/og-measure/variants/cocoa-amber.json +0 -138
  362. package/themes/og-measure/variants/cocoa-cyan.json +0 -138
  363. package/themes/og-measure/variants/cocoa-gold.json +0 -129
  364. package/themes/og-measure/variants/cream-lime.json +0 -137
  365. package/themes/og-measure/variants/deep-jade.json +0 -100
  366. package/themes/og-measure/variants/dusk-violet.json +0 -133
  367. package/themes/og-measure/variants/forest-cyan.json +0 -123
  368. package/themes/og-measure/variants/frost-amber.json +0 -129
  369. package/themes/og-measure/variants/frost-cyan.json +0 -133
  370. package/themes/og-measure/variants/lilac-plum.json +0 -127
  371. package/themes/og-measure/variants/lilac-violet.json +0 -139
  372. package/themes/og-measure/variants/sage-green.json +0 -137
  373. package/themes/og-measure/variants/wine-jade.json +0 -127
  374. package/themes/og-measure/variants/wine-plum.json +0 -127
@@ -1,6 +1,6 @@
1
1
  import { clamp, spring, applyStyle } from "@kasaframe/core";
2
2
  import { typeText } from "@kasaframe/motion";
3
- import { area, beatStops, glider, moving, node, slotsOf } from "../kit.ts";
3
+ import { area, beatStops, dwells, glider, markOf, moving, node, readOver, reread, slotsOf } from "../kit.ts";
4
4
  import type { Pattern } from "../types.ts";
5
5
 
6
6
  export interface CodeContent {
@@ -22,13 +22,13 @@ const rowsOf = (c: CodeContent): Row[] => {
22
22
  };
23
23
 
24
24
  /**
25
- * 명령·코드 — 창 판 안에서 명령은 자모 단위로 쳐지고(블록 커서가 끝을 따라간다), 출력·코드 줄은 흘러 찍힌다. 지금 줄 뒤엔 강조색 칸이 글과 함께 늘어난다.
26
- * 다 서면 짚개가 마지막 줄(결과)과 다른 줄을 박마다 번갈아 짚는다. 치는 빠르기는 박아 둔다(명령 초당 36타·출력 90자) — 장면이 길다고 느리게 치지 않는다.
25
+ * 명령·코드 — 창 판 안에서 명령은 자모 단위로 쳐지고(블록 커서가 끝을 따라간다), 출력·코드 줄은 흘러 찍힌다. 지금 줄 뒤엔 짚는 칸이 글과 함께 늘어난다.
26
+ * 다 서면 줄이 둘 넘을 때 짚개가 마지막 줄(결과)부터 짚는다(머무는 테마는 목소리가 다른 줄을 말할 때만 그리로). 치는 빠르기는 박아 둔다(명령 초당 36타·출력 90자) — 장면이 길다고 느리게 치지 않는다.
27
27
  */
28
28
  const pattern: Pattern<CodeContent> = {
29
29
  id: "code.terminal",
30
30
  type: "code",
31
- does: "창 판 안에서 명령이 쳐지고 출력이 흘러 찍히며 지금 줄이 짚이고, 다 서면 짚개가 결과 줄과 다른 줄을 번갈아 짚는다",
31
+ does: "창 판 안에서 명령이 쳐지고 출력이 흘러 찍히며 지금 줄이 짚이고, 다 서면 짚개가 결과 줄부터 짚는다",
32
32
  energy: ["mid"],
33
33
  family: "type",
34
34
  camera: ["none"],
@@ -72,7 +72,9 @@ const pattern: Pattern<CodeContent> = {
72
72
  const text = node(line, "display:inline");
73
73
  return { r, line, prompt, text };
74
74
  });
75
- const cursor = node(body, `position:absolute;left:0;top:0;width:0.6em;height:1.2em;background:var(--kf-on-accent);visibility:hidden`);
75
+ const mark = markOf(kit, ctx);
76
+ // 블록 커서는 지금 줄 칸 위에 선다 — 테마 짚음 칸이 옅으면 칸 위 글색(onAccent)이 바탕에 묻혀 강조색으로
77
+ const cursor = node(body, `position:absolute;left:0;top:0;width:0.6em;height:1.2em;background:${mark ? "var(--kf-accent)" : "var(--kf-on-accent)"};visibility:hidden`);
76
78
 
77
79
  // 시각 — 명령은 초당 36타로 쳐지고, 출력·코드 줄은 초당 90자로 흘러 찍힌다. 줄 사이는 0.04초 — 박을 기다리면 그 사이가 멈춘 화면이다
78
80
  const cps = (r: Row) => (r.typed ? 36 : 90);
@@ -84,11 +86,16 @@ const pattern: Pattern<CodeContent> = {
84
86
  }
85
87
  const doneAt = at;
86
88
  const result = lines[lines.length - 1];
87
- const point = glider(body, [result.line, ...lines.slice(0, -1).map((l) => l.line)], { hub: true, pad: 0.15 });
88
- // 지금 줄 — 치거나 찍히는 줄 뒤에 강조색 칸이 붙어 글과 함께 늘어난다(작은 글 치기만으로는 화면이 바뀐 것으로 안 읽힌다)
89
- const nowBar = node(body, "position:absolute;left:0;top:0;background:var(--kf-accent);z-index:-1;visibility:hidden");
89
+ const point = glider(body, [result, ...lines.slice(0, -1)].map((l) => ({ el: l.line, text: l.r.text })), { kit, ctx, from: doneAt, pad: 0.15 });
90
+ // 한 줄뿐이고 훑는 테마면 짚개 대신 다 친 그 줄을 박마다 다시 짚는다
91
+ const again = lines.length < 2 && !dwells(kit, ctx) ? readOver(result.line, `${result.r.typed ? "$ " : ""}${result.r.text}`, ctx) : null;
92
+ const againStops = again ? beatStops(kit.hits, doneAt, ctx.dur) : [];
93
+ // 지금 줄 — 치거나 찍히는 줄 뒤에 짚는 칸이 붙어 글과 함께 늘어난다(작은 글 치기만으로는 화면이 바뀐 것으로 안 읽힌다). 칸 모양·줄 옮김은 테마 짚음
94
+ const nowBar = node(body, `position:absolute;left:0;top:0;z-index:-1;visibility:hidden${mark ? "" : ";background:var(--kf-accent)"}`);
95
+ const nowMark = mark?.(nowBar) ?? null;
96
+ const nowInk = nowMark ? nowMark.ink : "var(--kf-on-accent)";
97
+ const lineBox = (l: HTMLElement, extra = 0) => ({ x: -px * 0.25, y: l.offsetTop - px * 0.1, w: l.offsetWidth + px * 0.5 + extra, h: l.offsetHeight + px * 0.2 });
90
98
  body.style.isolation = "isolate";
91
- const stops = beatStops(kit.hits, doneAt, ctx.dur);
92
99
  const lands = lines.map((l, i) => slots.land(l.line, { ctx, at: starts[i], seed: `${kit.seed}:l${i}` }));
93
100
 
94
101
  return (t: number) => {
@@ -111,21 +118,23 @@ const pattern: Pattern<CodeContent> = {
111
118
  nowBar.style.visibility = live ? "visible" : "hidden";
112
119
  lines.forEach((l) => {
113
120
  const on = l === live;
114
- l.text.style.color = on ? "var(--kf-on-accent)" : "";
115
- if (l.prompt) l.prompt.style.color = on ? "var(--kf-on-accent)" : "var(--kf-accent-text, var(--kf-accent))";
121
+ l.text.style.color = on && nowInk ? nowInk : "";
122
+ if (l.prompt) l.prompt.style.color = on && nowInk ? nowInk : "var(--kf-accent-text, var(--kf-accent))";
116
123
  });
117
124
  if (live) {
118
- const extra = live.r.typed && cur ? px * 0.7 : 0;
119
- nowBar.style.transform = `translate(${(-px * 0.25).toFixed(1)}px, ${(live.line.offsetTop - px * 0.1).toFixed(1)}px)`;
120
- nowBar.style.width = `${(live.line.offsetWidth + px * 0.5 + extra).toFixed(1)}px`;
121
- nowBar.style.height = `${(live.line.offsetHeight + px * 0.2).toFixed(1)}px`;
125
+ const box = lineBox(live.line, live.r.typed && cur ? px * 0.7 : 0);
126
+ const b = nowMark ? nowMark.at(k > 0 ? lineBox(lines[k - 1].line) : null, box, clamp((t - starts[k]) / 0.3)) : box;
127
+ nowBar.style.transform = `translate(${b.x.toFixed(1)}px, ${b.y.toFixed(1)}px)`;
128
+ nowBar.style.width = `${b.w.toFixed(1)}px`;
129
+ nowBar.style.height = `${b.h.toFixed(1)}px`;
122
130
  }
123
131
  // 블록 커서는 치는 줄의 끝을 따라간다 — 다 치면 결과 줄 끝에서 짚개에 자리를 내준다
124
132
  const c2 = cur as { line: HTMLElement; chars: number } | null;
125
133
  cursor.style.visibility = c2 && t < doneAt ? "visible" : "hidden";
126
134
  // 접힌 줄은 몇째 줄 몇째 칸인지로 센다(고정폭이라 한 줄 = wrap 칸)
127
135
  if (c2) cursor.style.transform = `translate(${((c2.chars % wrap) * 0.6).toFixed(2)}em, ${(c2.line.offsetTop / px + Math.floor(c2.chars / wrap) * 1.45 + 0.12).toFixed(3)}em)`;
128
- point(t, stops);
136
+ point(t);
137
+ again?.(reread(t, againStops));
129
138
  };
130
139
  },
131
140
  };
@@ -1,6 +1,6 @@
1
1
  import { applyStyle, clamp, combine, spring } from "@kasaframe/core";
2
2
  import { fitSize, textEm } from "@kasaframe/motion/moves";
3
- import { area, beatStops, fitOnce, glider, moving, node, riseName, slotsOf } from "../kit.ts";
3
+ import { area, beatStops, dwells, fitOnce, followSpoken, glider, moving, node, reread, riseName, sayTimes, slotsOf } from "../kit.ts";
4
4
  import type { Pattern } from "../types.ts";
5
5
 
6
6
  export interface EndContent {
@@ -12,12 +12,12 @@ export interface EndContent {
12
12
  }
13
13
 
14
14
  /**
15
- * 끝 카드 — 로고가 앉고 이름이 글자마다 서고, 한 줄·주소가 찍히는 동안 짚개가 이름 → 한 줄 → 주소를 박마다 옮겨 다닌다.
15
+ * 끝 카드 — 로고가 앉고 이름이 글자마다 서고 한 줄·주소가 찍힌다. 한 줄·주소가 있으면 짚개가 이름부터 짚는다(머무는 테마는 목소리가 한 줄·주소를 말할 때만 그리로).
16
16
  */
17
17
  const pattern: Pattern<EndContent> = {
18
18
  id: "end.lockup",
19
19
  type: "end",
20
- does: "로고가 앉고 이름이 서고 한 줄·주소가 찍히는 동안, 짚개가 이름·한 줄·주소를 박마다 옮겨 다닌다",
20
+ does: "로고가 앉고 이름이 서고 한 줄·주소가 찍히면, 짚개가 이름부터 짚는다",
21
21
  energy: ["low", "mid"],
22
22
  family: "mask",
23
23
  camera: ["none"],
@@ -57,14 +57,17 @@ const pattern: Pattern<EndContent> = {
57
57
  const logoAt = 0;
58
58
  const nameAt = logo ? 0.15 : kit.first ? -0.2 : 0;
59
59
  const nameEnd = nameAt + each * (count - 1) + 0.3;
60
- const lineAt = nameEnd;
60
+ // 머무는 짚개 테마는 한 줄·주소를 목소리가 그것을 말할 때 찍는다(못 들으면 이름이 선 뒤부터 장면 끝 무렵까지 고르게). 찍힐 때마다(없으면
61
+ // 이름이 서면) 카메라가 그쪽으로 다가간다 — 끝 카드가 일찍 다 서고 남은 시간이 비지 않게. 훑는 테마는 이름이 서자마자 잇달아 찍는다
61
62
  const lineDur = line ? clamp([...c.line!].length * 0.03, 0.25, 0.6) : 0;
62
- const urlAt = lineAt + lineDur;
63
63
  const urlDur = url ? clamp([...c.url!].length * 0.03, 0.25, 0.6) : 0;
64
- // 짚개는 이름이 서자마자 이름 → 한 줄 → 주소를 박마다 옮겨 다닌다 — 장면이 길어도 빠르기는 박이 정해 화면이 서지 않는다
65
- const point = glider(host, [name, line, url].filter((e): e is HTMLDivElement => !!e), { hub: true });
64
+ const [lineAt, urlWant] = dwells(kit, ctx) ? sayTimes(kit, [c.line, c.url], nameEnd, Math.max(nameEnd + 0.3, ctx.dur - 0.9)) : [nameEnd, nameEnd + lineDur];
65
+ const urlAt = Math.max(urlWant, lineAt + lineDur);
66
+ followSpoken(kit, ctx, line || url ? [...(line ? [{ at: lineAt, el: line }] : []), ...(url ? [{ at: urlAt, el: url }] : [])] : [{ at: nameEnd, el: name }]);
67
+ // 짚개는 이름이 서면 이름·한 줄·주소를 짚는다(짚기 방식은 테마 짚음). 한 줄·주소가 없고 훑는 테마면 이름 글자를 박마다 다시 짚는다
68
+ const point = glider(host, [{ el: name, text: c.title }, ...(line ? [{ el: line, text: c.line }] : []), ...(url ? [{ el: url, text: c.url }] : [])], { kit, ctx, from: nameEnd - 0.15 });
69
+ const again = !line && !url && !dwells(kit, ctx) ? beatStops(kit.hits, nameEnd - 0.15, ctx.dur) : null;
66
70
  const fit = fitOnce(name, w * 0.86, h * (vertical ? 0.18 : 0.3), c.title);
67
- const stops = beatStops(kit.hits, nameEnd - 0.15, ctx.dur);
68
71
 
69
72
  const writeLine = line ? slots.write(line, { ctx, text: c.line!, at: lineAt, dur: lineDur, seed: `${kit.seed}:line` }) : null;
70
73
  const writeUrl = url ? slots.write(url, { ctx, text: c.url!, at: urlAt, dur: urlDur, seed: `${kit.seed}:url` }) : null;
@@ -74,8 +77,8 @@ const pattern: Pattern<EndContent> = {
74
77
  moving("end.lockup", ctx);
75
78
  if (logo && logoLand) applyStyle(logo, combine({ scale: spring(t - logoAt, { from: 0.6, to: 1, stiffness: 280, damping: 16 }) }, logoLand(t)));
76
79
  fit();
77
- paintName(t, { riseAt: nameAt, each, fill: 0 });
78
- point(t, stops);
80
+ paintName(t, { riseAt: nameAt, each, fill: 0, up: again ? reread(t, again) : undefined });
81
+ point(t);
79
82
  writeLine?.(t);
80
83
  writeUrl?.(t);
81
84
  };
@@ -1,6 +1,6 @@
1
1
  import { applyStyle, clamp, combine, spring } from "@kasaframe/core";
2
2
  import { fitSize, textEm } from "@kasaframe/motion/moves";
3
- import { area, beatStops, cameraOk, fitOnce, glider, moving, node, sceneDrop, slam, slotsOf } from "../kit.ts";
3
+ import { area, beatStops, cameraOk, dwells, fitOnce, glider, moving, node, readOver, reread, sceneDrop, slam, slotsOf } from "../kit.ts";
4
4
  import type { EndContent } from "./lockup.ts";
5
5
  import type { Pattern } from "../types.ts";
6
6
 
@@ -65,9 +65,10 @@ const pattern: Pattern<EndContent> = {
65
65
  const writeLine = lineEl ? slots.write(lineEl, { ctx, text: c.line!, at: lineAt, dur: 0.35, seed: `${kit.seed}:line` }) : null;
66
66
  const writeUrl = urlEl ? slots.write(urlEl, { ctx, text: c.url!, at: urlAt, dur: 0.3, seed: `${kit.seed}:url` }) : null;
67
67
  const landed = slots.land(name, { ctx, at, seed: `${kit.seed}:land` });
68
- // 앉은 뒤엔 짚개가 이름 ↔ 한 줄·주소를 박마다 번갈아 짚는다
69
- const point = glider(host, [stage, ...(lineEl ? [lineEl] : []), ...(urlEl ? [urlEl] : [])], { hub: true });
70
- const stops = beatStops(kit.hits, at + 0.2, ctx.dur);
68
+ // 앉으면 짚개가 이름·한 줄·주소를 짚는다(짚기 방식은 테마 짚음). 한 줄·주소가 없고 훑는 테마면 이름 글을 박마다 다시 짚는다
69
+ const point = glider(host, [{ el: stage, text: c.title }, ...(lineEl ? [{ el: lineEl, text: c.line }] : []), ...(urlEl ? [{ el: urlEl, text: c.url }] : [])], { kit, ctx, from: at + 0.2 });
70
+ const again = line || dwells(kit, ctx) ? null : readOver(name, c.title, ctx);
71
+ const againStops = again ? beatStops(kit.hits, at + 0.2, ctx.dur) : [];
71
72
 
72
73
  return (t: number) => {
73
74
  moving("end.slam", ctx);
@@ -78,7 +79,8 @@ const pattern: Pattern<EndContent> = {
78
79
  // 쾅 전엔 외곽선 이름을 왼쪽부터 짚어 자리를 알린다 — 앉은 뒤엔 꽉 찬 이름을 마지막 프레임까지 짚는다
79
80
  ghost.style.opacity = t < at ? "0.16" : "0";
80
81
  ghost.style.clipPath = t < at ? `inset(0 ${((1 - clamp(t / Math.max(0.1, at - 0.16))) * 100).toFixed(2)}% 0 0)` : "";
81
- point(t, stops);
82
+ point(t);
83
+ again?.(reread(t, againStops));
82
84
  if (line) line.style.visibility = t >= lineAt ? "visible" : "hidden";
83
85
  writeLine?.(t);
84
86
  writeUrl?.(t);
@@ -1,17 +1,18 @@
1
1
  import { applyStyle, clamp } from "@kasaframe/core";
2
2
  import { textEm } from "@kasaframe/motion/moves";
3
- import { area, beatStops, decimalsOf, fitOnce, glider, moving, node, odometer, slotsOf, timesSign } from "../kit.ts";
3
+ import { area, decimalsOf, dwells, fitOnce, followSpoken, glider, moving, node, odometer, sayTimes, slotsOf, timesSign } from "../kit.ts";
4
4
  import type { HookNumber } from "./roll.ts";
5
+ import { rollCues } from "../sfx.ts";
5
6
  import type { Pattern } from "../types.ts";
6
7
 
7
8
  /**
8
- * 계수기 — 숫자 자리마다 판이 서고 주행계 띠가 굴러 값에 앉는다(끝자리 띠가 연속으로 구르고 윗자리는 올림 때만). 굴림 2.2초로 박아 둔다.
9
- * 앉은 뒤엔 짚개가 숫자와 라벨을 박마다 번갈아 짚는다. 롤(roll)이 「값이 바뀐다」라면 이쪽은 「센다」.
9
+ * 계수기 — 숫자 자리마다 판이 서고 주행계 띠가 굴러 값에 앉는다(끝자리 띠가 연속으로 구르고 윗자리는 올림 때만). 목소리가 그 값을 말할 때(못 들으면 장면 끝 무렵) 앉는다.
10
+ * 앉으면 짚개가 숫자부터 짚는다(머무는 테마는 목소리가 라벨·단위를 말할 때만 그리로). 롤(roll)이 「값이 바뀐다」라면 이쪽은 「센다」.
10
11
  */
11
12
  const pattern: Pattern<HookNumber> = {
12
13
  id: "hook-number.counter",
13
14
  type: "hook-number",
14
- does: "숫자 자리마다 판이 서고 주행계 띠가 굴러 값에 앉은 뒤, 짚개가 숫자와 라벨을 번갈아 짚는다",
15
+ does: "숫자 자리마다 판이 서고 주행계 띠가 굴러 값에 앉으면, 짚개가 숫자부터 짚는다",
15
16
  energy: ["low", "mid"],
16
17
  family: "flap",
17
18
  camera: ["none"],
@@ -69,11 +70,15 @@ const pattern: Pattern<HookNumber> = {
69
70
  // 라벨 폭은 글꼴마다 다르다(고정폭 테마는 빈칸까지 한 칸) — 글자 수 어림 대신 그 글꼴로 재서 안전 영역 폭 92% 안에
70
71
  const fitLabel = fitOnce(label, w * 0.92, labelPx, c.label);
71
72
 
72
- const land = Math.min(2.4, ctx.dur - 0.6);
73
+ // 머무는 짚개 테마는 라벨을 목소리가 그것을 말할 때 세우고, 숫자는 그 값을 말할 때까지(못 들으면 장면 끝 무렵까지) 고른 빠르기로 센다 —
74
+ // 처음 2초에 다 서고 남은 시간이 비지 않게. 앉으면 카메라가 숫자 쪽으로 다가간다. 훑는 테마는 2.4초 안에 앉고 남은 시간을 짚개가 진다
75
+ const spread = dwells(kit, ctx);
76
+ const [labelAt, valueAt] = spread ? sayTimes(kit, [c.label, c.value.toFixed(dec)], 0, Math.max(1.2, ctx.dur - 0.9)) : [0, Math.min(2.4, ctx.dur - 0.6)];
77
+ const land = clamp(valueAt, Math.min(1.2, ctx.dur - 0.6), ctx.dur - 0.6);
78
+ followSpoken(kit, ctx, [{ at: land, el: board }]);
73
79
  // 배수 기호 하나를 칸으로 짚으면 색 네모 안 × — 닫기 단추로 읽힌다
74
- const point = glider(host, [board, label, ...(unitEl && !times ? [unitEl] : [])], { hub: true });
75
- const stops = beatStops(kit.hits, land + 0.15, ctx.dur);
76
- const writeLabel = slots.write(label, { ctx, text: c.label, at: 0, dur: 0.35, seed: `${kit.seed}:l` });
80
+ const point = glider(host, [{ el: board, text: c.value.toFixed(dec) }, { el: label, text: c.label }, ...(unitEl && !times ? [{ el: unitEl, text: unit }] : [])], { kit, ctx, from: land + 0.15 });
81
+ const writeLabel = slots.write(label, { ctx, text: c.label, at: Math.min(labelAt, land - 0.2), dur: 0.35, seed: `${kit.seed}:l` });
77
82
  const landed = slots.land(board, { ctx, at: land, seed: `${kit.seed}:land` });
78
83
  // 출처는 앉은 뒤에 찍고 장면 끝 0.35초 전에 다 찍는다 — 테마 글 찍기가 마지막 글자를 앉힐 틈(끝 프레임에 덜 찍힌 글자가 안 남게)
79
84
  const srcDur = clamp([...srcText].length * 0.035, 0.3, 0.9);
@@ -87,13 +92,14 @@ const pattern: Pattern<HookNumber> = {
87
92
  writeSource?.(t);
88
93
  // 고른 빠르기로 센다 — 감속하면 끝자리 띠가 서서 그 사이가 멈춘 화면이 된다
89
94
  const p = clamp((t - 0.1) / (land - 0.1));
95
+ rollCues(t, { at: 0.1, dur: land - 0.1, p: (u) => u });
90
96
  const v = from + (c.value - from) * p;
91
97
  if (odo) odo(p >= 1 ? c.value : v);
92
98
  num.style.visibility = odo && t < land ? "visible" : "hidden";
93
99
  plain.style.visibility = !odo || t >= land ? "visible" : "hidden";
94
100
  if (!odo) plain.textContent = (p >= 1 ? c.value : v).toFixed(dec).padStart(template.length, " ");
95
101
  applyStyle(board, landed(t));
96
- point(t, stops);
102
+ point(t);
97
103
  };
98
104
  },
99
105
  };
@@ -1,6 +1,6 @@
1
1
  import { applyStyle, clamp, combine } from "@kasaframe/core";
2
2
  import { textEm } from "@kasaframe/motion/moves";
3
- import { area, beatStops, cameraOk, decimalsOf, factRoll, fitOnce, glider, moving, node, sceneDrop, slam, slotsOf } from "../kit.ts";
3
+ import { area, cameraOk, decimalsOf, factRoll, fitOnce, glider, moving, node, sceneDrop, slam, slotsOf } from "../kit.ts";
4
4
  import type { HookNumber } from "./roll.ts";
5
5
  import type { Pattern } from "../types.ts";
6
6
 
@@ -61,13 +61,11 @@ const pattern: Pattern<HookNumber> = {
61
61
  if (di === null && kit.stage && cameraOk(ctx)) kit.stage.camera.impact(at, { amount: 0.04 });
62
62
  const writeLabel = slots.write(label, { ctx, text: c.label, at: 0, dur: labelDur, seed: `${kit.seed}:l` });
63
63
  const landed = slots.land(row, { ctx, at, seed: `${kit.seed}:land` });
64
- // 짚개 — 쾅 전엔 라벨 ↔ 외곽선 자리(무엇의 숫자가 어디 오나), 쾅 뒤엔 숫자 ↔ 라벨을 박마다 번갈아 짚는다
65
- const before = glider(host, [labelBox, ghostRow], { hub: true });
66
- const after = glider(host, [numBox, labelBox], { hub: true });
67
- const preStops = beatStops(kit.hits, labelDur, at - 0.2);
64
+ // 짚개 — 쾅 전엔 라벨(무엇의 숫자인가)과 외곽선 자리, 쾅 뒤엔 숫자와 라벨. 짚기 방식(박마다 훑기·요점에 머묾)은 테마 짚음이 고른다
65
+ const before = glider(host, [{ el: labelBox, text: c.label }, { el: ghostRow }], { kit, ctx, from: labelDur, to: at - 0.2, until: at - 0.16 });
66
+ const after = glider(host, [{ el: numBox, text }, { el: labelBox, text: c.label }], { kit, ctx, from: at + 0.25 });
68
67
  // 라벨은 그 글꼴로 재서 안전 영역 폭 92% 안에
69
68
  const fitLabel = fitOnce(labelBox, w * 0.92, labelPx, c.label);
70
- const postStops = beatStops(kit.hits, at + 0.25, ctx.dur);
71
69
 
72
70
  return (t: number) => {
73
71
  moving("hook-number.slam", ctx);
@@ -81,8 +79,8 @@ const pattern: Pattern<HookNumber> = {
81
79
  ghostRow.style.left = `${row.offsetLeft}px`;
82
80
  ghostRow.style.top = `${row.offsetTop}px`;
83
81
  }
84
- before(t, preStops, at - 0.16);
85
- after(t, postStops);
82
+ before(t);
83
+ after(t);
86
84
  if (s) applyStyle(host, s.shake);
87
85
  };
88
86
  },