kasaframe 0.1.4 → 0.1.5

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 (294) hide show
  1. package/NOTICE +298 -0
  2. package/README.md +16 -3
  3. package/docs/AGENTS.md +1 -1
  4. package/package.json +1 -1
  5. package/packages/cli/src/commands/doctor.ts +15 -2
  6. package/packages/cli/src/commands/fonts.ts +118 -0
  7. package/packages/cli/src/commands/update.ts +66 -0
  8. package/packages/cli/src/fonts.ts +405 -0
  9. package/packages/cli/src/kf.ts +5 -0
  10. package/packages/cli/src/update.ts +250 -0
  11. package/packages/plan/src/asks.ts +1 -1
  12. package/packages/plan/src/themes.ts +8 -2
  13. package/packages/themes/kit/THEME-MAKE.md +2 -2
  14. package/packages/themes/kit/fonts/display.json +3517 -0
  15. package/packages/themes/kit/fonts/sans.json +5155 -0
  16. package/packages/themes/kit/fonts/serif.json +5229 -0
  17. package/packages/themes/kit/fonts.json +243 -79
  18. package/packages/themes/package.json +3 -1
  19. package/packages/themes/src/fontfile.ts +183 -0
  20. package/packages/themes/src/fonts.ts +296 -0
  21. package/packages/themes/src/index.ts +10 -2
  22. package/packages/themes/src/look.ts +34 -8
  23. package/packages/themes/src/types.ts +5 -0
  24. package/packages/themes/src/vary.ts +35 -34
  25. package/presets/kawaii-pastel.json +2 -2
  26. package/skills/kasaframe/SKILL.md +1 -0
  27. package/themes/blueprint/sample/style.json +5 -5
  28. package/themes/blueprint/style.json +5 -5
  29. package/themes/blueprint/theme.json +3 -1
  30. package/themes/blueprint/variants/deep-rose-suit.json +1 -1
  31. package/themes/blueprint/variants/navy-coral-2.json +1 -1
  32. package/themes/blueprint/variants/navy-coral-suit.json +1 -1
  33. package/themes/blueprint/variants/navy-orange-2.json +1 -1
  34. package/themes/blueprint/variants/navy-orange-suit.json +1 -1
  35. package/themes/cartography/sample/style.json +2 -2
  36. package/themes/cartography/style.json +2 -2
  37. package/themes/cartography/theme.json +3 -1
  38. package/themes/cartography/variants/deep-plum.json +1 -1
  39. package/themes/cartography/variants/frost-teal.json +1 -1
  40. package/themes/cartography/variants/navy-green.json +1 -1
  41. package/themes/circuit-board/sample/style.json +2 -2
  42. package/themes/circuit-board/style.json +2 -2
  43. package/themes/circuit-board/theme.json +3 -1
  44. package/themes/circuit-board/variants/dusk-gold-pretendard.json +1 -1
  45. package/themes/circuit-board/variants/navy-gold-grain.json +1 -1
  46. package/themes/circuit-board/variants/wine-gold-pretendard.json +1 -1
  47. package/themes/clay-toy/sample/style.json +2 -2
  48. package/themes/clay-toy/style.json +2 -2
  49. package/themes/clay-toy/theme.json +3 -1
  50. package/themes/clay-toy/variants/blush-coral-grain.json +1 -1
  51. package/themes/clay-toy/variants/chalk-teal.json +1 -1
  52. package/themes/clay-toy/variants/frost-sky.json +1 -1
  53. package/themes/clay-toy/variants/frost-teal.json +1 -1
  54. package/themes/clay-toy/variants/lilac-plum-round.json +1 -1
  55. package/themes/clay-toy/variants/lilac-plum.json +1 -1
  56. package/themes/clay-toy/variants/sage-indigo.json +1 -1
  57. package/themes/conveyor-factory/sample/style.json +3 -3
  58. package/themes/conveyor-factory/style.json +3 -3
  59. package/themes/conveyor-factory/theme.json +3 -1
  60. package/themes/conveyor-factory/variants/cocoa-gold.json +1 -1
  61. package/themes/conveyor-factory/variants/navy-gold.json +1 -1
  62. package/themes/conveyor-factory/variants/slate-amber-2.json +1 -1
  63. package/themes/conveyor-factory/variants/slate-amber-suit.json +1 -1
  64. package/themes/conveyor-factory/variants/slate-gold-bold.json +1 -1
  65. package/themes/data-journal/theme.json +3 -1
  66. package/themes/data-journal/variants/deep-coral.json +1 -1
  67. package/themes/data-journal/variants/navy-lime.json +1 -1
  68. package/themes/data-journal/variants/wine-indigo.json +1 -1
  69. package/themes/debug-hud/sample/style.json +1 -1
  70. package/themes/debug-hud/style.json +1 -1
  71. package/themes/debug-hud/theme.json +2 -1
  72. package/themes/debug-hud/variants/cocoa-teal.json +2 -2
  73. package/themes/debug-hud/variants/deep-teal-scan.json +2 -2
  74. package/themes/debug-hud/variants/dusk-plum.json +2 -2
  75. package/themes/debug-hud/variants/forest-lime.json +2 -2
  76. package/themes/debug-hud/variants/slate-green.json +2 -2
  77. package/themes/debug-hud/variants/wine-gold.json +2 -2
  78. package/themes/depth-flight/sample/style.json +1 -1
  79. package/themes/depth-flight/style.json +1 -1
  80. package/themes/depth-flight/theme.json +3 -1
  81. package/themes/depth-flight/variants/cocoa-cyan.json +1 -1
  82. package/themes/depth-flight/variants/cocoa-violet.json +1 -1
  83. package/themes/depth-flight/variants/deep-sky.json +1 -1
  84. package/themes/depth-flight/variants/forest-blue.json +1 -1
  85. package/themes/depth-flight/variants/navy-sky-grain.json +1 -1
  86. package/themes/depth-flight/variants/navy-sky.json +1 -1
  87. package/themes/depth-flight/variants/night-teal.json +1 -1
  88. package/themes/depth-flight/variants/slate-indigo.json +1 -1
  89. package/themes/depth-flight/variants/slate-violet.json +1 -1
  90. package/themes/film-reel/sample/style.json +2 -2
  91. package/themes/film-reel/style.json +2 -2
  92. package/themes/film-reel/theme.json +3 -1
  93. package/themes/film-reel/variants/chalk-pink.json +1 -1
  94. package/themes/film-reel/variants/lilac-gold.json +1 -1
  95. package/themes/film-reel/variants/lilac-violet.json +1 -1
  96. package/themes/glass-light/sample/style.json +1 -1
  97. package/themes/glass-light/style.json +1 -1
  98. package/themes/glass-light/theme.json +3 -1
  99. package/themes/glass-light/variants/blush-pink.json +1 -1
  100. package/themes/glass-light/variants/blush-plum.json +1 -1
  101. package/themes/glass-light/variants/cream-violet.json +1 -1
  102. package/themes/glass-light/variants/frost-sky-suit.json +1 -1
  103. package/themes/glass-light/variants/frost-sky.json +1 -1
  104. package/themes/glass-light/variants/sage-green.json +1 -1
  105. package/themes/ink-wash/sample/style.json +3 -3
  106. package/themes/ink-wash/style.json +3 -3
  107. package/themes/ink-wash/theme.json +3 -1
  108. package/themes/iso-diorama/sample/style.json +1 -1
  109. package/themes/iso-diorama/style.json +1 -1
  110. package/themes/iso-diorama/theme.json +3 -1
  111. package/themes/iso-diorama/variants/chalk-plum.json +1 -1
  112. package/themes/iso-diorama/variants/cocoa-indigo.json +1 -1
  113. package/themes/iso-diorama/variants/dusk-blue.json +1 -1
  114. package/themes/iso-diorama/variants/dusk-coral.json +1 -1
  115. package/themes/iso-diorama/variants/dusk-jade.json +1 -1
  116. package/themes/iso-diorama/variants/forest-cyan.json +1 -1
  117. package/themes/iso-diorama/variants/frost-green.json +1 -1
  118. package/themes/iso-diorama/variants/frost-teal.json +1 -1
  119. package/themes/iso-diorama/variants/navy-amber.json +1 -1
  120. package/themes/isotype/sample/style.json +2 -2
  121. package/themes/isotype/style.json +2 -2
  122. package/themes/isotype/theme.json +2 -1
  123. package/themes/isotype/variants/blush-rose.json +1 -1
  124. package/themes/isotype/variants/chalk-coral.json +1 -1
  125. package/themes/isotype/variants/chalk-orange.json +1 -1
  126. package/themes/isotype/variants/frost-amber.json +1 -1
  127. package/themes/isotype/variants/frost-coral.json +1 -1
  128. package/themes/isotype/variants/frost-orange.json +1 -1
  129. package/themes/isotype/variants/sand-amber.json +1 -1
  130. package/themes/kawaii-sticker/sample/style.json +2 -2
  131. package/themes/kawaii-sticker/style.json +2 -2
  132. package/themes/kawaii-sticker/theme.json +3 -1
  133. package/themes/kawaii-sticker/variants/cream-gold.json +1 -1
  134. package/themes/kawaii-sticker/variants/dusk-green.json +1 -1
  135. package/themes/kawaii-sticker/variants/dusk-indigo.json +1 -1
  136. package/themes/kawaii-sticker/variants/dusk-sky.json +1 -1
  137. package/themes/kawaii-sticker/variants/dusk-teal.json +1 -1
  138. package/themes/kawaii-sticker/variants/frost-blue.json +1 -1
  139. package/themes/kawaii-sticker/variants/frost-plum.json +1 -1
  140. package/themes/kawaii-sticker/variants/lilac-violet.json +1 -1
  141. package/themes/kawaii-sticker/variants/navy-gold.json +1 -1
  142. package/themes/kawaii-sticker/variants/navy-plum.json +1 -1
  143. package/themes/lab-notebook/sample/style.json +3 -3
  144. package/themes/lab-notebook/style.json +3 -3
  145. package/themes/lab-notebook/theme.json +2 -1
  146. package/themes/lab-notebook/variants/blush-orange.json +1 -1
  147. package/themes/lab-notebook/variants/chalk-coral.json +1 -1
  148. package/themes/lab-notebook/variants/chalk-orange.json +1 -1
  149. package/themes/lab-notebook/variants/chalk-rose.json +1 -1
  150. package/themes/lab-notebook/variants/lilac-rose.json +1 -1
  151. package/themes/lab-notebook/variants/sage-rose.json +1 -1
  152. package/themes/lab-notebook/variants/sand-orange.json +1 -1
  153. package/themes/lab-notebook/variants/snow-orange.json +1 -1
  154. package/themes/lab-notebook/variants/snow-rose.json +1 -1
  155. package/themes/manga-panel/sample/style.json +3 -3
  156. package/themes/manga-panel/style.json +3 -3
  157. package/themes/manga-panel/theme.json +3 -1
  158. package/themes/manga-panel/variants/chalk-cyan-dots.json +1 -1
  159. package/themes/manga-panel/variants/chalk-rose.json +1 -1
  160. package/themes/manga-panel/variants/snow-cyan.json +1 -1
  161. package/themes/manga-panel/variants/snow-magenta-dots.json +1 -1
  162. package/themes/marble-run/sample/style.json +2 -2
  163. package/themes/marble-run/style.json +2 -2
  164. package/themes/marble-run/theme.json +3 -1
  165. package/themes/marble-run/variants/slate-orange.json +1 -1
  166. package/themes/neon-sign/sample/style.json +2 -2
  167. package/themes/neon-sign/style.json +2 -2
  168. package/themes/neon-sign/theme.json +2 -1
  169. package/themes/neon-sign/variants/dusk-plum.json +1 -1
  170. package/themes/neon-sign/variants/forest-magenta.json +1 -1
  171. package/themes/neon-sign/variants/night-pink.json +1 -1
  172. package/themes/neon-sign/variants/night-violet.json +1 -1
  173. package/themes/neon-sign/variants/slate-violet.json +1 -1
  174. package/themes/newspaper/sample/style.json +2 -2
  175. package/themes/newspaper/style.json +2 -2
  176. package/themes/newspaper/theme.json +2 -1
  177. package/themes/newspaper/variants/blush-amber.json +1 -1
  178. package/themes/newspaper/variants/chalk-magenta.json +1 -1
  179. package/themes/newspaper/variants/frost-sky.json +1 -1
  180. package/themes/newspaper/variants/lilac-green.json +1 -1
  181. package/themes/newspaper/variants/sage-lime.json +1 -1
  182. package/themes/og-measure/THEME.md +32 -6
  183. package/themes/og-measure/effects.ts +219 -115
  184. package/themes/og-measure/sample/assets/brand/og-logo.svg +11 -11
  185. package/themes/og-measure/sample/lib/data.ts +6 -0
  186. package/themes/og-measure/sample/scenes/end.ts +14 -10
  187. package/themes/og-measure/sample/scenes/gather.ts +12 -1
  188. package/themes/og-measure/sample/scenes/models.ts +13 -2
  189. package/themes/og-measure/sample/scenes/one.ts +8 -6
  190. package/themes/og-measure/sample/scenes/price.ts +20 -3
  191. package/themes/og-measure/sample/style.json +30 -35
  192. package/themes/og-measure/slots.ts +25 -30
  193. package/themes/og-measure/still.png +0 -0
  194. package/themes/og-measure/style.json +30 -35
  195. package/themes/og-measure/theme.json +64 -49
  196. package/themes/og-measure/variants/snow-blue.json +90 -0
  197. package/themes/orbit-system/sample/style.json +3 -3
  198. package/themes/orbit-system/style.json +3 -3
  199. package/themes/orbit-system/theme.json +3 -1
  200. package/themes/orbit-system/variants/cocoa-amber.json +1 -1
  201. package/themes/orbit-system/variants/cocoa-cyan.json +1 -1
  202. package/themes/orbit-system/variants/dusk-magenta.json +1 -1
  203. package/themes/orbit-system/variants/dusk-violet.json +1 -1
  204. package/themes/orbit-system/variants/forest-coral.json +1 -1
  205. package/themes/orbit-system/variants/wine-amber.json +1 -1
  206. package/themes/orbit-system/variants/wine-magenta.json +1 -1
  207. package/themes/origami-fold/sample/style.json +1 -1
  208. package/themes/origami-fold/style.json +1 -1
  209. package/themes/origami-fold/theme.json +3 -1
  210. package/themes/origami-fold/variants/deep-amber-sunflower.json +1 -1
  211. package/themes/origami-fold/variants/deep-orange.json +1 -1
  212. package/themes/origami-fold/variants/forest-coral.json +1 -1
  213. package/themes/origami-fold/variants/forest-pink.json +1 -1
  214. package/themes/origami-fold/variants/frost-amber-paper.json +1 -1
  215. package/themes/origami-fold/variants/sage-coral-sunflower.json +1 -1
  216. package/themes/origami-fold/variants/sage-coral.json +1 -1
  217. package/themes/origami-fold/variants/sage-pink-round.json +1 -1
  218. package/themes/origami-fold/variants/sage-pink.json +1 -1
  219. package/themes/paper-cutout/sample/style.json +2 -2
  220. package/themes/paper-cutout/style.json +2 -2
  221. package/themes/paper-cutout/theme.json +3 -1
  222. package/themes/paper-cutout/variants/blush-violet.json +1 -1
  223. package/themes/paper-cutout/variants/frost-lime.json +1 -1
  224. package/themes/paper-cutout/variants/lilac-gold.json +1 -1
  225. package/themes/paper-cutout/variants/sage-cyan.json +1 -1
  226. package/themes/paper-cutout/variants/sage-green.json +1 -1
  227. package/themes/paper-cutout/variants/sage-pink.json +1 -1
  228. package/themes/paper-cutout/variants/sand-blue.json +1 -1
  229. package/themes/pixel-quest/theme.json +2 -1
  230. package/themes/receipt/sample/style.json +2 -2
  231. package/themes/receipt/style.json +2 -2
  232. package/themes/riso-zine/sample/style.json +2 -2
  233. package/themes/riso-zine/style.json +2 -2
  234. package/themes/riso-zine/theme.json +3 -1
  235. package/themes/riso-zine/variants/chalk-lime.json +1 -1
  236. package/themes/riso-zine/variants/frost-green.json +1 -1
  237. package/themes/riso-zine/variants/lilac-plum.json +1 -1
  238. package/themes/riso-zine/variants/lilac-violet.json +1 -1
  239. package/themes/server-hall/sample/style.json +2 -2
  240. package/themes/server-hall/style.json +2 -2
  241. package/themes/server-hall/theme.json +3 -1
  242. package/themes/server-hall/variants/night-indigo.json +1 -1
  243. package/themes/server-hall/variants/wine-plum.json +1 -1
  244. package/themes/subway-map/sample/style.json +2 -2
  245. package/themes/subway-map/style.json +2 -2
  246. package/themes/subway-map/theme.json +3 -1
  247. package/themes/subway-map/variants/deep-green.json +1 -1
  248. package/themes/subway-map/variants/deep-teal.json +1 -1
  249. package/themes/subway-map/variants/frost-jade.json +1 -1
  250. package/themes/subway-map/variants/frost-teal.json +1 -1
  251. package/themes/subway-map/variants/slate-green.json +1 -1
  252. package/themes/subway-map/variants/snow-jade.json +1 -1
  253. package/themes/swiss-poster/sample/style.json +2 -2
  254. package/themes/swiss-poster/style.json +2 -2
  255. package/themes/swiss-poster/theme.json +3 -1
  256. package/themes/swiss-poster/variants/chalk-plum.json +1 -1
  257. package/themes/swiss-poster/variants/cocoa-cyan.json +1 -1
  258. package/themes/swiss-poster/variants/dusk-magenta.json +1 -1
  259. package/themes/swiss-poster/variants/frost-indigo.json +1 -1
  260. package/themes/swiss-poster/variants/slate-orange.json +1 -1
  261. package/themes/water-works/sample/style.json +1 -1
  262. package/themes/water-works/style.json +1 -1
  263. package/themes/water-works/theme.json +3 -1
  264. package/themes/water-works/variants/chalk-cyan.json +1 -1
  265. package/themes/water-works/variants/frost-indigo.json +1 -1
  266. package/themes/water-works/variants/sand-amber.json +1 -1
  267. package/themes/water-works/variants/sand-plum.json +1 -1
  268. package/themes/whiteboard/sample/style.json +2 -2
  269. package/themes/whiteboard/style.json +2 -2
  270. package/themes/whiteboard/theme.json +3 -1
  271. package/themes/whiteboard/variants/chalk-coral.json +1 -1
  272. package/themes/whiteboard/variants/cream-lime.json +1 -1
  273. package/themes/whiteboard/variants/frost-teal.json +1 -1
  274. package/themes/whiteboard/variants/lilac-indigo.json +1 -1
  275. package/themes/whiteboard/variants/sage-plum.json +1 -1
  276. package/themes/whiteboard/variants/snow-cyan.json +1 -1
  277. package/themes/whiteboard/variants/snow-green.json +1 -1
  278. package/themes/whiteboard/variants/snow-magenta.json +1 -1
  279. package/themes/og-measure/sample/assets/brand/og-logo-full.svg +0 -12
  280. package/themes/og-measure/variants/chalk-orange.json +0 -102
  281. package/themes/og-measure/variants/cocoa-amber.json +0 -138
  282. package/themes/og-measure/variants/cocoa-cyan.json +0 -138
  283. package/themes/og-measure/variants/cocoa-gold.json +0 -129
  284. package/themes/og-measure/variants/cream-lime.json +0 -137
  285. package/themes/og-measure/variants/deep-jade.json +0 -100
  286. package/themes/og-measure/variants/dusk-violet.json +0 -133
  287. package/themes/og-measure/variants/forest-cyan.json +0 -123
  288. package/themes/og-measure/variants/frost-amber.json +0 -129
  289. package/themes/og-measure/variants/frost-cyan.json +0 -133
  290. package/themes/og-measure/variants/lilac-plum.json +0 -127
  291. package/themes/og-measure/variants/lilac-violet.json +0 -139
  292. package/themes/og-measure/variants/sage-green.json +0 -137
  293. package/themes/og-measure/variants/wine-jade.json +0 -127
  294. package/themes/og-measure/variants/wine-plum.json +0 -127
@@ -1,34 +1,16 @@
1
1
  // 변주 — 세계 하나에서 겉모습만 바꾼 판을 데이터로 뽑는다(SPEC 9 변주). 코드는 세계 것을 그대로 쓰고, 여기서는 style 위에 덮을 판만 짓는다.
2
- import { readFileSync } from "node:fs";
3
- import { fileURLToPath } from "node:url";
4
2
  import { rand, randRange, type KfStyle } from "@kasaframe/core";
5
3
  import { hueDist, labOf, parseColor } from "./color.ts";
4
+ import { type FontPair, fontPairs, titleWeight } from "./fonts.ts";
6
5
  import { lchOf, NEUTRAL_C, transformPalette } from "./palette.ts";
7
6
  import type { TextureKind, ThemeManifest, ThemeTags, ThemeVary, VariantManifest, VariantParams } from "./types.ts";
8
7
 
9
- export interface FontPair {
10
- id: string;
11
- name: string;
12
- ko: string;
13
- tags: string[];
14
- sans: string;
15
- display: string;
16
- mono: string;
17
- faces: NonNullable<KfStyle["fonts"]["faces"]>;
18
- weightDisplay: number;
19
- weightBody: number;
20
- tracking: string;
21
- monoAll?: boolean;
22
- }
23
-
24
- let pairs: FontPair[] | null = null;
25
- export const fontPairs = (): FontPair[] => (pairs ??= JSON.parse(readFileSync(fileURLToPath(new URL("../kit/fonts.json", import.meta.url)), "utf8")));
26
-
27
8
  /** 세계가 허락한 글꼴 짝 — 「base」는 세계 글꼴 그대로 */
28
9
  export function allowedFonts(vary: ThemeVary): string[] {
29
10
  const all = fontPairs().filter((p) => !vary.monoAll || p.monoAll);
30
11
  const want = vary.fonts ?? ["base"];
31
- const ids = want.flatMap((w) => (w === "base" ? ["base"] : w.startsWith("tag:") ? all.filter((p) => p.tags.includes(w.slice(4))).map((p) => p.id) : all.some((p) => p.id === w) ? [w] : []));
12
+ // tag:sans+geometric 은 두 태그를 다 가진 짝 — 짝이 수백이라 태그 하나로는 결이 다른 무리까지 딸려 온다
13
+ const ids = want.flatMap((w) => (w === "base" ? ["base"] : w.startsWith("tag:") ? all.filter((p) => w.slice(4).split("+").every((t) => p.tags.includes(t))).map((p) => p.id) : all.some((p) => p.id === w) ? [w] : []));
32
14
  return [...new Set(ids)];
33
15
  }
34
16
 
@@ -71,28 +53,40 @@ function sampleHue(seed: string, i: number, ranges: [number, number][]): number
71
53
  return ranges[0][0];
72
54
  }
73
55
 
56
+ /** 그 밝기의 원점 색 — 세계가 밝기마다 한 벌을 정해 뒀으면(vary.palettes) 그 벌, 세계 자신의 밝기면 세계 색. 안 정한 세계는 null(세계 색을 옮긴다) */
57
+ export function paletteOf(style: KfStyle, vary: ThemeVary, scheme: "light" | "dark"): KfStyle["colors"] | null {
58
+ if (!vary.palettes) return null;
59
+ if (scheme === style.scheme) return style.colors;
60
+ return (vary.palettes[scheme] as KfStyle["colors"] | undefined) ?? null;
61
+ }
62
+
74
63
  /** 손잡이 값 하나 — 세계가 안 받는 축은 세계 값 */
75
64
  export function sampleParams(style: KfStyle, vary: ThemeVary, seed: string, n: number): VariantParams {
76
65
  const base = baseParams(style);
77
66
  const r = (k: number, lo: number, hi: number) => randRange(seed, n * 32 + k, lo, hi);
78
67
  const pickOf = <T>(k: number, items: readonly T[]): T => items[Math.min(items.length - 1, Math.floor(rand(seed, n * 32 + k) * items.length))];
79
68
  const scheme = pickOf(0, vary.scheme ?? [style.scheme]);
80
- const bgR = vary.bg?.[scheme] ?? BG_L[scheme];
81
- const hue = vary.hue ? sampleHue(seed, n * 32 + 1, vary.hue) : base.hue;
69
+ const own = paletteOf(style, vary, scheme);
70
+ const origin = own ? baseParams({ ...style, scheme, colors: own }) : null;
71
+ const bgR = vary.bg?.[scheme] ?? (origin ? [origin.bgL, origin.bgL] : BG_L[scheme]);
72
+ const hue = vary.hue ? sampleHue(seed, n * 32 + 1, vary.hue) : (origin ?? base).hue;
82
73
  // 무채색 빛깔은 반쯤은 강조색 쪽(한 집안), 반쯤은 아무 쪽
83
74
  const tintH = rand(seed, n * 32 + 2) < 0.5 ? (hue + r(3, -30, 30) + 360) % 360 : r(4, 0, 360);
84
75
  const tex = pickOf(5, vary.texture ?? [base.texture.kind]);
85
76
  const chroma = vary.chroma ? r(10, vary.chroma[0], vary.chroma[1]) : 1;
86
77
  // 바탕이 색 잉크인 세계는 바탕이 강조색과 같은 각도로 돌아야 모눈·선과 한 벌로 남는다 — tint 축은 무채색 바탕 세계 것
87
- const tint = base.tint.c >= NEUTRAL_C
88
- ? { h: (base.tint.h + hue - base.hue + 360) % 360, c: base.tint.c * chroma }
89
- : { h: tintH, c: vary.tint ? r(7, vary.tint[0], vary.tint[1]) * (scheme === "dark" ? DARK_TINT : 1) : base.tint.c };
78
+ // 정해 둔 벌이 있으면 바탕 빛깔·글 명도는 그 벌의 것 — 브랜드 무채색(푸른 회색)에 아무 빛깔이나 얹지 않는다
79
+ const tint = origin && !vary.tint
80
+ ? origin.tint
81
+ : base.tint.c >= NEUTRAL_C
82
+ ? { h: (base.tint.h + hue - base.hue + 360) % 360, c: base.tint.c * chroma }
83
+ : { h: tintH, c: vary.tint ? r(7, vary.tint[0], vary.tint[1]) * (scheme === "dark" ? DARK_TINT : 1) : base.tint.c };
90
84
  const q = (v: number) => +v.toFixed(4);
91
85
  return {
92
86
  scheme,
93
87
  bgL: q(r(6, bgR[0], bgR[1])),
94
88
  tint: { h: q(tint.h), c: q(tint.c) },
95
- inkL: q(scheme === style.scheme && rand(seed, n * 32 + 8) < 0.5 ? base.inkL : r(9, INK_L[scheme][0], INK_L[scheme][1])),
89
+ inkL: q(origin ? origin.inkL : scheme === style.scheme && rand(seed, n * 32 + 8) < 0.5 ? base.inkL : r(9, INK_L[scheme][0], INK_L[scheme][1])),
96
90
  hue: q(hue),
97
91
  chroma: q(chroma),
98
92
  fonts: pickOf(11, allowedFonts(vary)),
@@ -107,13 +101,15 @@ export function sampleParams(style: KfStyle, vary: ThemeVary, seed: string, n: n
107
101
  /** 손잡이 값 → 세계 style 위에 덮을 판. 색이 검사를 못 넘으면 bad 에 까닭 */
108
102
  export function overlayOf(style: KfStyle, manifest: Pick<ThemeManifest, "vary">, p: VariantParams): { style: VariantManifest["style"]; bad: string[]; measured: Record<string, number> } {
109
103
  const vary = manifest.vary ?? {};
110
- const pal = transformPalette(style.colors, p, { keep: vary.keep, fixedHue: vary.fixedHue });
104
+ const pal = transformPalette(paletteOf(style, vary, p.scheme) ?? style.colors, p, { keep: vary.keep, fixedHue: vary.fixedHue });
111
105
  const out: VariantManifest["style"] = { scheme: p.scheme, colors: pal.colors as KfStyle["colors"] };
112
106
  if (p.fonts !== "base") {
113
107
  const f = fontPairs().find((x) => x.id === p.fonts);
114
108
  if (!f) return { style: out, bad: [`글꼴 짝 ${p.fonts} 이 없다`], measured: pal.measured };
115
- out.fonts = vary.monoAll ? { sans: f.mono, display: f.mono, mono: f.mono, faces: f.faces } : { sans: f.sans, display: f.display, mono: f.mono, faces: f.faces };
116
- out.type = { weightDisplay: f.weightDisplay, weightBody: f.weightBody, tracking: f.tracking };
109
+ // 라이선스·출처는 짝 목록의 것 — style.json 의 face 는 core 계약(family·src·weight) 그대로
110
+ const faces = f.faces.map(({ license: _l, source: _s, ...face }) => face);
111
+ out.fonts = vary.monoAll ? { sans: f.mono, display: f.mono, mono: f.mono, faces } : { sans: f.sans, display: f.display, mono: f.mono, faces };
112
+ out.type = { weightDisplay: titleWeight(f, vary.monoAll), weightBody: f.weightBody, tracking: f.tracking };
117
113
  }
118
114
  if (p.radius !== null) {
119
115
  const md0 = style.radius.md || 12;
@@ -265,6 +261,14 @@ export function nameVariant(params: VariantParams, taken: Set<string>, colors?:
265
261
  return { id, name, desc };
266
262
  }
267
263
 
264
+ // 글꼴 짝 태그 → 변주 분위기 낱말. kf theme suggest 가 요청 낱말을 이 낱말과도 견준다
265
+ const FONT_MOOD: [string, string][] = [
266
+ ["serif", "고전적"], ["classic", "고전적"], ["elegant", "우아한"], ["traditional", "전통"], ["brush", "붓글씨"], ["newspaper", "신문"],
267
+ ["rounded", "귀여운"], ["playful", "발랄한"], ["comic", "만화"], ["hand", "손글씨"], ["pixel", "레트로"], ["retro", "레트로"],
268
+ ["mono", "기술적"], ["tech", "기술적"], ["futuristic", "미래적"], ["modern", "모던"], ["industrial", "산업"], ["signage", "안내판"],
269
+ ["calm", "차분한"], ["strong", "강한"], ["neon", "네온"],
270
+ ];
271
+
268
272
  /** 변주 태그 — 세계 태그에 색·질감·글꼴이 주는 분위기를 더한다 */
269
273
  export function variantTags(world: ThemeTags, params: VariantParams, colors?: Record<string, string>): ThemeTags {
270
274
  const p = seen(params, colors);
@@ -277,10 +281,7 @@ export function variantTags(world: ThemeTags, params: VariantParams, colors?: Re
277
281
  if (["paper", "grain", "halftone", "noise"].includes(p.texture.kind)) mood.add("아날로그");
278
282
  if (p.texture.kind === "scan") mood.add("레트로");
279
283
  const tags = fontPairs().find((x) => x.id === p.fonts)?.tags ?? [];
280
- if (tags.includes("serif")) mood.add("고전적");
281
- if (tags.includes("rounded")) mood.add("귀여운");
282
- if (tags.includes("pixel")) mood.add("레트로");
283
- if (tags.includes("mono")) mood.add("기술적");
284
+ for (const [tag, word] of FONT_MOOD) if (tags.includes(tag)) mood.add(word);
284
285
  return { ...world, mood: [...mood], light: p.scheme };
285
286
  }
286
287
 
@@ -35,12 +35,12 @@
35
35
  },
36
36
  {
37
37
  "family": "JetBrains Mono",
38
- "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5/files/jetbrains-mono-latin-wght-normal.woff2",
38
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/files/jetbrains-mono-latin-wght-normal.woff2",
39
39
  "weight": "100 800"
40
40
  },
41
41
  {
42
42
  "family": "Jua",
43
- "src": "https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/jua/Jua-Regular.ttf",
43
+ "src": "https://cdn.jsdelivr.net/gh/google/fonts@bd8f81ddb5c74d5c8897b36ad88b440266245103/ofl/jua/Jua-Regular.ttf",
44
44
  "weight": "400"
45
45
  }
46
46
  ]
@@ -9,6 +9,7 @@ argument-hint: "[만들 영상 한 줄]"
9
9
  # kasaframe — 말 한 줄로 영상까지
10
10
 
11
11
  명령은 `kf <명령>` — `npm i -g kasaframe` 로 깔았으면 어느 폴더에서나. `kf` 가 PATH 에 없고 이 스킬 폴더가 레포 안의 링크면(실제 경로의 두 단계 위가 레포 뿌리) 그 뿌리에서 `npx kf <명령>`. 둘 다 아니면 사람에게 `npm i -g kasaframe && kf setup` 을 알린다. 처음이면 `kf doctor` 로 ffmpeg·크롬·librosa·OG 키를 본다.
12
+ 표준 오류에 `[kasaframe] 새 판 <최신> (지금 <지금>) — kf update` 줄이 보이면 하던 일 사이에(렌더 도중이면 끝난 뒤) `kf update --yes` 로 올리고 이어 간다. 종료 코드가 0 이 아니면 찍힌 명령을 사람에게 알리고 지금 판으로 계속한다.
12
13
  규칙·장면 쓰는 법·고치는 법의 정본은 **`docs/AGENTS.md`**(이 스킬 폴더 `kf skill path` 의 두 단계 위) — 장면을 쓰기 전에 0절과 3절을 읽는다.
13
14
 
14
15
  ## 순서
@@ -27,27 +27,27 @@
27
27
  "faces": [
28
28
  {
29
29
  "family": "Barlow Condensed",
30
- "src": "https://cdn.jsdelivr.net/npm/@fontsource/barlow-condensed@5/files/barlow-condensed-latin-500-normal.woff2",
30
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource/barlow-condensed@5.3.0/files/barlow-condensed-latin-500-normal.woff2",
31
31
  "weight": "500"
32
32
  },
33
33
  {
34
34
  "family": "Barlow Condensed",
35
- "src": "https://cdn.jsdelivr.net/npm/@fontsource/barlow-condensed@5/files/barlow-condensed-latin-600-normal.woff2",
35
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource/barlow-condensed@5.3.0/files/barlow-condensed-latin-600-normal.woff2",
36
36
  "weight": "600"
37
37
  },
38
38
  {
39
39
  "family": "Barlow Condensed",
40
- "src": "https://cdn.jsdelivr.net/npm/@fontsource/barlow-condensed@5/files/barlow-condensed-latin-700-normal.woff2",
40
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource/barlow-condensed@5.3.0/files/barlow-condensed-latin-700-normal.woff2",
41
41
  "weight": "700"
42
42
  },
43
43
  {
44
44
  "family": "B612 Mono",
45
- "src": "https://cdn.jsdelivr.net/npm/@fontsource/b612-mono@5/files/b612-mono-latin-400-normal.woff2",
45
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource/b612-mono@5.3.0/files/b612-mono-latin-400-normal.woff2",
46
46
  "weight": "400"
47
47
  },
48
48
  {
49
49
  "family": "B612 Mono",
50
- "src": "https://cdn.jsdelivr.net/npm/@fontsource/b612-mono@5/files/b612-mono-latin-700-normal.woff2",
50
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource/b612-mono@5.3.0/files/b612-mono-latin-700-normal.woff2",
51
51
  "weight": "700"
52
52
  },
53
53
  {
@@ -27,27 +27,27 @@
27
27
  "faces": [
28
28
  {
29
29
  "family": "Barlow Condensed",
30
- "src": "https://cdn.jsdelivr.net/npm/@fontsource/barlow-condensed@5/files/barlow-condensed-latin-500-normal.woff2",
30
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource/barlow-condensed@5.3.0/files/barlow-condensed-latin-500-normal.woff2",
31
31
  "weight": "500"
32
32
  },
33
33
  {
34
34
  "family": "Barlow Condensed",
35
- "src": "https://cdn.jsdelivr.net/npm/@fontsource/barlow-condensed@5/files/barlow-condensed-latin-600-normal.woff2",
35
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource/barlow-condensed@5.3.0/files/barlow-condensed-latin-600-normal.woff2",
36
36
  "weight": "600"
37
37
  },
38
38
  {
39
39
  "family": "Barlow Condensed",
40
- "src": "https://cdn.jsdelivr.net/npm/@fontsource/barlow-condensed@5/files/barlow-condensed-latin-700-normal.woff2",
40
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource/barlow-condensed@5.3.0/files/barlow-condensed-latin-700-normal.woff2",
41
41
  "weight": "700"
42
42
  },
43
43
  {
44
44
  "family": "B612 Mono",
45
- "src": "https://cdn.jsdelivr.net/npm/@fontsource/b612-mono@5/files/b612-mono-latin-400-normal.woff2",
45
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource/b612-mono@5.3.0/files/b612-mono-latin-400-normal.woff2",
46
46
  "weight": "400"
47
47
  },
48
48
  {
49
49
  "family": "B612 Mono",
50
- "src": "https://cdn.jsdelivr.net/npm/@fontsource/b612-mono@5/files/b612-mono-latin-700-normal.woff2",
50
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource/b612-mono@5.3.0/files/b612-mono-latin-700-normal.woff2",
51
51
  "weight": "700"
52
52
  },
53
53
  {
@@ -41,7 +41,9 @@
41
41
  "plex-mono",
42
42
  "space-mono",
43
43
  "plex",
44
- "suit"
44
+ "suit",
45
+ "tag:sans+tech",
46
+ "tag:mono+tech"
45
47
  ],
46
48
  "texture": [
47
49
  "none"
@@ -60,7 +60,7 @@
60
60
  },
61
61
  {
62
62
  "family": "JetBrains Mono",
63
- "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5/files/jetbrains-mono-latin-wght-normal.woff2",
63
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/files/jetbrains-mono-latin-wght-normal.woff2",
64
64
  "weight": "100 800"
65
65
  }
66
66
  ]
@@ -60,7 +60,7 @@
60
60
  },
61
61
  {
62
62
  "family": "JetBrains Mono",
63
- "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5/files/jetbrains-mono-latin-wght-normal.woff2",
63
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/files/jetbrains-mono-latin-wght-normal.woff2",
64
64
  "weight": "100 800"
65
65
  }
66
66
  ]
@@ -60,7 +60,7 @@
60
60
  },
61
61
  {
62
62
  "family": "JetBrains Mono",
63
- "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5/files/jetbrains-mono-latin-wght-normal.woff2",
63
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/files/jetbrains-mono-latin-wght-normal.woff2",
64
64
  "weight": "100 800"
65
65
  }
66
66
  ]
@@ -60,7 +60,7 @@
60
60
  },
61
61
  {
62
62
  "family": "JetBrains Mono",
63
- "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5/files/jetbrains-mono-latin-wght-normal.woff2",
63
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/files/jetbrains-mono-latin-wght-normal.woff2",
64
64
  "weight": "100 800"
65
65
  }
66
66
  ]
@@ -60,7 +60,7 @@
60
60
  },
61
61
  {
62
62
  "family": "JetBrains Mono",
63
- "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5/files/jetbrains-mono-latin-wght-normal.woff2",
63
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/files/jetbrains-mono-latin-wght-normal.woff2",
64
64
  "weight": "100 800"
65
65
  }
66
66
  ]
@@ -31,7 +31,7 @@
31
31
  "faces": [
32
32
  {
33
33
  "family": "Gowun Batang",
34
- "src": "https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/gowunbatang/GowunBatang-Bold.ttf",
34
+ "src": "https://cdn.jsdelivr.net/gh/google/fonts@bd8f81ddb5c74d5c8897b36ad88b440266245103/ofl/gowunbatang/GowunBatang-Bold.ttf",
35
35
  "weight": "700"
36
36
  },
37
37
  {
@@ -41,7 +41,7 @@
41
41
  },
42
42
  {
43
43
  "family": "DM Mono",
44
- "src": "https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/dmmono/DMMono-Medium.ttf",
44
+ "src": "https://cdn.jsdelivr.net/gh/google/fonts@bd8f81ddb5c74d5c8897b36ad88b440266245103/ofl/dmmono/DMMono-Medium.ttf",
45
45
  "weight": "500"
46
46
  }
47
47
  ]
@@ -31,7 +31,7 @@
31
31
  "faces": [
32
32
  {
33
33
  "family": "Gowun Batang",
34
- "src": "https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/gowunbatang/GowunBatang-Bold.ttf",
34
+ "src": "https://cdn.jsdelivr.net/gh/google/fonts@bd8f81ddb5c74d5c8897b36ad88b440266245103/ofl/gowunbatang/GowunBatang-Bold.ttf",
35
35
  "weight": "700"
36
36
  },
37
37
  {
@@ -41,7 +41,7 @@
41
41
  },
42
42
  {
43
43
  "family": "DM Mono",
44
- "src": "https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/dmmono/DMMono-Medium.ttf",
44
+ "src": "https://cdn.jsdelivr.net/gh/google/fonts@bd8f81ddb5c74d5c8897b36ad88b440266245103/ofl/dmmono/DMMono-Medium.ttf",
45
45
  "weight": "500"
46
46
  }
47
47
  ]
@@ -121,7 +121,9 @@
121
121
  "myeongjo",
122
122
  "plex",
123
123
  "gothic-a1",
124
- "plex-mono"
124
+ "plex-mono",
125
+ "tag:serif+classic",
126
+ "tag:serif+editorial"
125
127
  ],
126
128
  "texture": [
127
129
  "none",
@@ -69,7 +69,7 @@
69
69
  },
70
70
  {
71
71
  "family": "JetBrains Mono",
72
- "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5/files/jetbrains-mono-latin-wght-normal.woff2",
72
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/files/jetbrains-mono-latin-wght-normal.woff2",
73
73
  "weight": "100 800"
74
74
  }
75
75
  ]
@@ -69,7 +69,7 @@
69
69
  },
70
70
  {
71
71
  "family": "JetBrains Mono",
72
- "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5/files/jetbrains-mono-latin-wght-normal.woff2",
72
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/files/jetbrains-mono-latin-wght-normal.woff2",
73
73
  "weight": "100 800"
74
74
  }
75
75
  ]
@@ -69,7 +69,7 @@
69
69
  },
70
70
  {
71
71
  "family": "JetBrains Mono",
72
- "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5/files/jetbrains-mono-latin-wght-normal.woff2",
72
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/files/jetbrains-mono-latin-wght-normal.woff2",
73
73
  "weight": "100 800"
74
74
  }
75
75
  ]
@@ -33,12 +33,12 @@
33
33
  "faces": [
34
34
  {
35
35
  "family": "Orbit",
36
- "src": "https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/orbit/Orbit-Regular.ttf",
36
+ "src": "https://cdn.jsdelivr.net/gh/google/fonts@bd8f81ddb5c74d5c8897b36ad88b440266245103/ofl/orbit/Orbit-Regular.ttf",
37
37
  "weight": "400"
38
38
  },
39
39
  {
40
40
  "family": "Share Tech Mono",
41
- "src": "https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/sharetechmono/ShareTechMono-Regular.ttf",
41
+ "src": "https://cdn.jsdelivr.net/gh/google/fonts@bd8f81ddb5c74d5c8897b36ad88b440266245103/ofl/sharetechmono/ShareTechMono-Regular.ttf",
42
42
  "weight": "400"
43
43
  },
44
44
  {
@@ -33,12 +33,12 @@
33
33
  "faces": [
34
34
  {
35
35
  "family": "Orbit",
36
- "src": "https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/orbit/Orbit-Regular.ttf",
36
+ "src": "https://cdn.jsdelivr.net/gh/google/fonts@bd8f81ddb5c74d5c8897b36ad88b440266245103/ofl/orbit/Orbit-Regular.ttf",
37
37
  "weight": "400"
38
38
  },
39
39
  {
40
40
  "family": "Share Tech Mono",
41
- "src": "https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/sharetechmono/ShareTechMono-Regular.ttf",
41
+ "src": "https://cdn.jsdelivr.net/gh/google/fonts@bd8f81ddb5c74d5c8897b36ad88b440266245103/ofl/sharetechmono/ShareTechMono-Regular.ttf",
42
42
  "weight": "400"
43
43
  },
44
44
  {
@@ -50,7 +50,9 @@
50
50
  "plex",
51
51
  "pretendard-jetbrains",
52
52
  "nanum-coding",
53
- "space-mono"
53
+ "space-mono",
54
+ "tag:tech+futuristic",
55
+ "tag:mono+tech"
54
56
  ],
55
57
  "texture": [
56
58
  "none",
@@ -61,7 +61,7 @@
61
61
  },
62
62
  {
63
63
  "family": "JetBrains Mono",
64
- "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5/files/jetbrains-mono-latin-wght-normal.woff2",
64
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/files/jetbrains-mono-latin-wght-normal.woff2",
65
65
  "weight": "100 800"
66
66
  }
67
67
  ]
@@ -61,7 +61,7 @@
61
61
  },
62
62
  {
63
63
  "family": "JetBrains Mono",
64
- "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5/files/jetbrains-mono-latin-wght-normal.woff2",
64
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/files/jetbrains-mono-latin-wght-normal.woff2",
65
65
  "weight": "100 800"
66
66
  }
67
67
  ]
@@ -61,7 +61,7 @@
61
61
  },
62
62
  {
63
63
  "family": "JetBrains Mono",
64
- "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5/files/jetbrains-mono-latin-wght-normal.woff2",
64
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/files/jetbrains-mono-latin-wght-normal.woff2",
65
65
  "weight": "100 800"
66
66
  }
67
67
  ]
@@ -30,7 +30,7 @@
30
30
  "faces": [
31
31
  {
32
32
  "family": "Jua",
33
- "src": "https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/jua/Jua-Regular.ttf",
33
+ "src": "https://cdn.jsdelivr.net/gh/google/fonts@bd8f81ddb5c74d5c8897b36ad88b440266245103/ofl/jua/Jua-Regular.ttf",
34
34
  "weight": "400"
35
35
  },
36
36
  {
@@ -40,7 +40,7 @@
40
40
  },
41
41
  {
42
42
  "family": "JetBrains Mono",
43
- "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5/files/jetbrains-mono-latin-wght-normal.woff2",
43
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/files/jetbrains-mono-latin-wght-normal.woff2",
44
44
  "weight": "100 800"
45
45
  }
46
46
  ]
@@ -30,7 +30,7 @@
30
30
  "faces": [
31
31
  {
32
32
  "family": "Jua",
33
- "src": "https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/jua/Jua-Regular.ttf",
33
+ "src": "https://cdn.jsdelivr.net/gh/google/fonts@bd8f81ddb5c74d5c8897b36ad88b440266245103/ofl/jua/Jua-Regular.ttf",
34
34
  "weight": "400"
35
35
  },
36
36
  {
@@ -40,7 +40,7 @@
40
40
  },
41
41
  {
42
42
  "family": "JetBrains Mono",
43
- "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5/files/jetbrains-mono-latin-wght-normal.woff2",
43
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/files/jetbrains-mono-latin-wght-normal.woff2",
44
44
  "weight": "100 800"
45
45
  }
46
46
  ]
@@ -47,7 +47,9 @@
47
47
  "dongle",
48
48
  "gowun-dodum",
49
49
  "do-hyeon",
50
- "sunflower"
50
+ "sunflower",
51
+ "tag:rounded+friendly",
52
+ "tag:rounded+playful"
51
53
  ],
52
54
  "texture": [
53
55
  "none",
@@ -63,7 +63,7 @@
63
63
  },
64
64
  {
65
65
  "family": "JetBrains Mono",
66
- "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5/files/jetbrains-mono-latin-wght-normal.woff2",
66
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/files/jetbrains-mono-latin-wght-normal.woff2",
67
67
  "weight": "100 800"
68
68
  }
69
69
  ]
@@ -63,7 +63,7 @@
63
63
  },
64
64
  {
65
65
  "family": "JetBrains Mono",
66
- "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5/files/jetbrains-mono-latin-wght-normal.woff2",
66
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/files/jetbrains-mono-latin-wght-normal.woff2",
67
67
  "weight": "100 800"
68
68
  }
69
69
  ]
@@ -63,7 +63,7 @@
63
63
  },
64
64
  {
65
65
  "family": "JetBrains Mono",
66
- "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5/files/jetbrains-mono-latin-wght-normal.woff2",
66
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/files/jetbrains-mono-latin-wght-normal.woff2",
67
67
  "weight": "100 800"
68
68
  }
69
69
  ]
@@ -63,7 +63,7 @@
63
63
  },
64
64
  {
65
65
  "family": "JetBrains Mono",
66
- "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5/files/jetbrains-mono-latin-wght-normal.woff2",
66
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/files/jetbrains-mono-latin-wght-normal.woff2",
67
67
  "weight": "100 800"
68
68
  }
69
69
  ]
@@ -63,7 +63,7 @@
63
63
  },
64
64
  {
65
65
  "family": "JetBrains Mono",
66
- "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5/files/jetbrains-mono-latin-wght-normal.woff2",
66
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/files/jetbrains-mono-latin-wght-normal.woff2",
67
67
  "weight": "100 800"
68
68
  }
69
69
  ]
@@ -63,7 +63,7 @@
63
63
  },
64
64
  {
65
65
  "family": "JetBrains Mono",
66
- "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5/files/jetbrains-mono-latin-wght-normal.woff2",
66
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/files/jetbrains-mono-latin-wght-normal.woff2",
67
67
  "weight": "100 800"
68
68
  }
69
69
  ]
@@ -63,7 +63,7 @@
63
63
  },
64
64
  {
65
65
  "family": "JetBrains Mono",
66
- "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5/files/jetbrains-mono-latin-wght-normal.woff2",
66
+ "src": "https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/files/jetbrains-mono-latin-wght-normal.woff2",
67
67
  "weight": "100 800"
68
68
  }
69
69
  ]
@@ -30,17 +30,17 @@
30
30
  "faces": [
31
31
  {
32
32
  "family": "Saira Stencil One",
33
- "src": "https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/sairastencilone/SairaStencilOne-Regular.ttf",
33
+ "src": "https://cdn.jsdelivr.net/gh/google/fonts@bd8f81ddb5c74d5c8897b36ad88b440266245103/ofl/sairastencilone/SairaStencilOne-Regular.ttf",
34
34
  "weight": "400"
35
35
  },
36
36
  {
37
37
  "family": "IBM Plex Sans KR",
38
- "src": "https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/ibmplexsanskr/IBMPlexSansKR-Bold.ttf",
38
+ "src": "https://cdn.jsdelivr.net/gh/google/fonts@bd8f81ddb5c74d5c8897b36ad88b440266245103/ofl/ibmplexsanskr/IBMPlexSansKR-Bold.ttf",
39
39
  "weight": "700"
40
40
  },
41
41
  {
42
42
  "family": "IBM Plex Mono",
43
- "src": "https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/ibmplexmono/IBMPlexMono-SemiBold.ttf",
43
+ "src": "https://cdn.jsdelivr.net/gh/google/fonts@bd8f81ddb5c74d5c8897b36ad88b440266245103/ofl/ibmplexmono/IBMPlexMono-SemiBold.ttf",
44
44
  "weight": "600"
45
45
  },
46
46
  {
@@ -30,17 +30,17 @@
30
30
  "faces": [
31
31
  {
32
32
  "family": "Saira Stencil One",
33
- "src": "https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/sairastencilone/SairaStencilOne-Regular.ttf",
33
+ "src": "https://cdn.jsdelivr.net/gh/google/fonts@bd8f81ddb5c74d5c8897b36ad88b440266245103/ofl/sairastencilone/SairaStencilOne-Regular.ttf",
34
34
  "weight": "400"
35
35
  },
36
36
  {
37
37
  "family": "IBM Plex Sans KR",
38
- "src": "https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/ibmplexsanskr/IBMPlexSansKR-Bold.ttf",
38
+ "src": "https://cdn.jsdelivr.net/gh/google/fonts@bd8f81ddb5c74d5c8897b36ad88b440266245103/ofl/ibmplexsanskr/IBMPlexSansKR-Bold.ttf",
39
39
  "weight": "700"
40
40
  },
41
41
  {
42
42
  "family": "IBM Plex Mono",
43
- "src": "https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/ibmplexmono/IBMPlexMono-SemiBold.ttf",
43
+ "src": "https://cdn.jsdelivr.net/gh/google/fonts@bd8f81ddb5c74d5c8897b36ad88b440266245103/ofl/ibmplexmono/IBMPlexMono-SemiBold.ttf",
44
44
  "weight": "600"
45
45
  },
46
46
  {