kingkont 0.7.82 → 0.7.84

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.
@@ -0,0 +1,19 @@
1
+ # Bundled fonts
2
+
3
+ All fonts in this directory are licensed under the SIL Open Font License v1.1
4
+ (<https://openfontlicense.org/>) and bundled here so KingKont can render
5
+ beautiful Cyrillic-aware label nodes without needing a network connection.
6
+
7
+ | Font | Author / Foundry | Source |
8
+ |---------------|----------------------------------------|--------------------------------------------------|
9
+ | Caveat | Pablo Impallari | <https://fonts.google.com/specimen/Caveat> |
10
+ | Bad Script | Roman Shchyukin (Gaslight) | <https://fonts.google.com/specimen/Bad+Script> |
11
+ | Pacifico | Vernon Adams | <https://fonts.google.com/specimen/Pacifico> |
12
+ | Lobster | Pablo Impallari | <https://fonts.google.com/specimen/Lobster> |
13
+ | Yeseva One | Jovanny Lemonad | <https://fonts.google.com/specimen/Yeseva+One> |
14
+ | Comfortaa | Johan Aakerlund | <https://fonts.google.com/specimen/Comfortaa> |
15
+ | PT Serif | ParaType | <https://fonts.google.com/specimen/PT+Serif> |
16
+ | PT Mono | ParaType | <https://fonts.google.com/specimen/PT+Mono> |
17
+
18
+ Files were downloaded from the @fontsource jsDelivr mirror in the
19
+ `cyrillic-400-normal` and `latin-400-normal` subsets.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kingkont",
3
- "version": "0.7.82",
3
+ "version": "0.7.84",
4
4
  "description": "KingKont · Chatium — нод-редактор сцен с AI-генерацией (картинки/видео/голос/SFX/музыка/текст)",
5
5
  "main": "main.js",
6
6
  "bin": {
package/renderer/board.js CHANGED
@@ -1638,8 +1638,14 @@ async function createNodeEl(node) {
1638
1638
  el.dataset.id = node.id;
1639
1639
  el.style.left = node.x + 'px';
1640
1640
  el.style.top = node.y + 'px';
1641
- if (node.width) el.style.width = node.width + 'px';
1642
- if (node.height) el.style.height = node.height + 'px';
1641
+ // Label-ноды всегда auto-размер (по тексту) фиксированный width/height
1642
+ // создавал «невидимые боксы» вокруг текста, что ломало hit-testing когда
1643
+ // несколько label оказывались рядом (клик попадал в перекрывающий, а не
1644
+ // в видимый текст). Игнорируем сохранённые width/height для label-нод.
1645
+ if (node.type !== 'label') {
1646
+ if (node.width) el.style.width = node.width + 'px';
1647
+ if (node.height) el.style.height = node.height + 'px';
1648
+ }
1643
1649
 
1644
1650
  const header = document.createElement('div');
1645
1651
  header.className = 'node-header';
@@ -213,7 +213,8 @@ async function addLabelAt(pos) {
213
213
  text: '',
214
214
  textStyle: { fontSize: 32, italic: false, fontFamily: 'handwritten' },
215
215
  x, y,
216
- width: 260, height: 90,
216
+ // width/height не задаём — label всегда auto-размер по тексту
217
+ // (см. createNodeEl: для type='label' inline-style не применяется).
217
218
  };
218
219
  state.currentBoard.metadata.nodes.push(node);
219
220
  const el = await createNodeEl(node);
@@ -61,12 +61,19 @@ $('settingsRegen').addEventListener('click', () => {
61
61
  // Шрифты — system-only, без Google Fonts CDN (приложение офлайновое).
62
62
  // На macOS все варианты выглядят естественно; на Win/Linux fallback'и
63
63
  // (cursive/fantasy/serif/monospace) сохраняют смысл.
64
+ // id хранится в node.textStyle.fontFamily, поэтому переименовывать существующие
65
+ // id (`handwritten` / `marker` / `serif` / `mono`) нельзя — это сломает
66
+ // сохранённые сцены. Новые красивые шрифты добавляем под новыми id.
64
67
  const LABEL_FONTS = [
65
68
  { id: 'default', label: 'Обычный' },
66
- { id: 'handwritten', label: 'Карандашом' },
67
- { id: 'marker', label: 'Краской' },
68
- { id: 'serif', label: 'С засечками' },
69
- { id: 'mono', label: 'Моноширинный' },
69
+ { id: 'handwritten', label: 'Карандашом' }, // Caveat
70
+ { id: 'brush', label: 'Скорописью' }, // Bad Script
71
+ { id: 'marker', label: 'Кистью' }, // Pacifico
72
+ { id: 'display', label: 'Декор' }, // Lobster
73
+ { id: 'elegant', label: 'Элегант' }, // Yeseva One
74
+ { id: 'rounded', label: 'Округлый' }, // Comfortaa
75
+ { id: 'serif', label: 'С засечками' }, // PT Serif
76
+ { id: 'mono', label: 'Моноширинный' }, // PT Mono
70
77
  ];
71
78
  const LABEL_FONT_SIZES = [12, 14, 18, 24, 32, 48, 64, 96];
72
79
  const LABEL_DEFAULT_STYLE = { fontSize: 32, italic: false, fontFamily: 'handwritten' };
@@ -1,3 +1,88 @@
1
+ /* === Bundled fonts (для label-нод, поддерживают кириллицу) ===
2
+ Все шрифты — OFL, лежат в assets/fonts/, см. NOTICE.md.
3
+ Для каждого семейства подключены два subset-файла (Latin + Cyrillic)
4
+ с unicode-range — браузер скачивает только тот блок, который нужен. */
5
+ @font-face {
6
+ font-family: 'KK Caveat'; font-style: normal; font-weight: 400; font-display: block;
7
+ src: url('../assets/fonts/caveat-cyrillic-400.woff2') format('woff2');
8
+ unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
9
+ }
10
+ @font-face {
11
+ font-family: 'KK Caveat'; font-style: normal; font-weight: 400; font-display: block;
12
+ src: url('../assets/fonts/caveat-latin-400.woff2') format('woff2');
13
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
14
+ }
15
+ @font-face {
16
+ font-family: 'KK BadScript'; font-style: normal; font-weight: 400; font-display: block;
17
+ src: url('../assets/fonts/bad-script-cyrillic-400.woff2') format('woff2');
18
+ unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
19
+ }
20
+ @font-face {
21
+ font-family: 'KK BadScript'; font-style: normal; font-weight: 400; font-display: block;
22
+ src: url('../assets/fonts/bad-script-latin-400.woff2') format('woff2');
23
+ unicode-range: U+0000-00FF;
24
+ }
25
+ @font-face {
26
+ font-family: 'KK Pacifico'; font-style: normal; font-weight: 400; font-display: block;
27
+ src: url('../assets/fonts/pacifico-cyrillic-400.woff2') format('woff2');
28
+ unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
29
+ }
30
+ @font-face {
31
+ font-family: 'KK Pacifico'; font-style: normal; font-weight: 400; font-display: block;
32
+ src: url('../assets/fonts/pacifico-latin-400.woff2') format('woff2');
33
+ unicode-range: U+0000-00FF;
34
+ }
35
+ @font-face {
36
+ font-family: 'KK Lobster'; font-style: normal; font-weight: 400; font-display: block;
37
+ src: url('../assets/fonts/lobster-cyrillic-400.woff2') format('woff2');
38
+ unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
39
+ }
40
+ @font-face {
41
+ font-family: 'KK Lobster'; font-style: normal; font-weight: 400; font-display: block;
42
+ src: url('../assets/fonts/lobster-latin-400.woff2') format('woff2');
43
+ unicode-range: U+0000-00FF;
44
+ }
45
+ @font-face {
46
+ font-family: 'KK YesevaOne'; font-style: normal; font-weight: 400; font-display: block;
47
+ src: url('../assets/fonts/yeseva-one-cyrillic-400.woff2') format('woff2');
48
+ unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
49
+ }
50
+ @font-face {
51
+ font-family: 'KK YesevaOne'; font-style: normal; font-weight: 400; font-display: block;
52
+ src: url('../assets/fonts/yeseva-one-latin-400.woff2') format('woff2');
53
+ unicode-range: U+0000-00FF;
54
+ }
55
+ @font-face {
56
+ font-family: 'KK Comfortaa'; font-style: normal; font-weight: 400; font-display: block;
57
+ src: url('../assets/fonts/comfortaa-cyrillic-400.woff2') format('woff2');
58
+ unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
59
+ }
60
+ @font-face {
61
+ font-family: 'KK Comfortaa'; font-style: normal; font-weight: 400; font-display: block;
62
+ src: url('../assets/fonts/comfortaa-latin-400.woff2') format('woff2');
63
+ unicode-range: U+0000-00FF;
64
+ }
65
+ @font-face {
66
+ font-family: 'KK PTSerif'; font-style: normal; font-weight: 400; font-display: block;
67
+ src: url('../assets/fonts/pt-serif-cyrillic-400.woff2') format('woff2');
68
+ unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
69
+ }
70
+ @font-face {
71
+ font-family: 'KK PTSerif'; font-style: normal; font-weight: 400; font-display: block;
72
+ src: url('../assets/fonts/pt-serif-latin-400.woff2') format('woff2');
73
+ unicode-range: U+0000-00FF;
74
+ }
75
+ @font-face {
76
+ font-family: 'KK PTMono'; font-style: normal; font-weight: 400; font-display: block;
77
+ src: url('../assets/fonts/pt-mono-cyrillic-400.woff2') format('woff2');
78
+ unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
79
+ }
80
+ @font-face {
81
+ font-family: 'KK PTMono'; font-style: normal; font-weight: 400; font-display: block;
82
+ src: url('../assets/fonts/pt-mono-latin-400.woff2') format('woff2');
83
+ unicode-range: U+0000-00FF;
84
+ }
85
+
1
86
  * { box-sizing: border-box; margin: 0; padding: 0; }
2
87
  html, body { height: 100%; }
3
88
  body {
@@ -330,48 +415,72 @@
330
415
  }
331
416
 
332
417
  /* === Label-node — плавающая текст-аннотация поверх холста ===
333
- Без фона / рамки / тени выглядит как «написанный» прямо на сцене текст.
334
- Header / footer / resize / anchor скрыты по умолчанию, появляются на
335
- hover чтобы можно было перетаскивать, удалять, ресайзить. */
418
+ Auto-размер по тексту: .node автоматически сжимается до контента,
419
+ никаких «невидимых боксов» вокруг текста. Header / toolbar /
420
+ resize / anchor вынесены за пределы видимой области (absolute) и
421
+ показываются на hover. */
336
422
  .node.label-node {
337
423
  background: transparent;
338
424
  border: none; box-shadow: none;
339
425
  padding: 0;
426
+ overflow: visible; /* absolute-дети могут выйти за рамки */
427
+ width: auto !important; /* override любого inline-width из старых сцен */
428
+ height: auto !important;
429
+ min-width: 30px;
430
+ max-width: 800px; /* лимит чтобы не получить однострочного монстра */
431
+ display: block; /* отключаем flex-column — нам не нужно */
432
+ contain: none; /* отменяем content-visibility-оптимизацию */
433
+ contain-intrinsic-size: auto;
340
434
  }
341
435
  .node.label-node.selected {
342
436
  outline: 1px dashed rgba(90,168,255,0.8);
343
437
  outline-offset: 2px;
344
438
  }
345
- .node.label-node .node-header,
346
- .node.label-node .node-footer,
347
- .node.label-node .resize-handle,
348
- .node.label-node .anchor,
349
- .node.label-node .label-toolbar {
350
- opacity: 0; transition: opacity 0.15s;
351
- }
352
- .node.label-node:hover .node-header,
353
- .node.label-node:hover .node-footer,
354
- .node.label-node:hover .resize-handle,
355
- .node.label-node:hover .anchor,
356
- .node.label-node:hover .label-toolbar,
357
- .node.label-node:focus-within .label-toolbar { opacity: 1; }
439
+
440
+ /* Header (drag-handle + имя + ×) — absolute над текстом, hover-only. */
358
441
  .node.label-node .node-header {
359
- background: rgba(20,20,20,0.85);
360
- border-radius: 6px 6px 0 0;
442
+ position: absolute;
443
+ bottom: 100%; /* над label, без занятия layout */
444
+ left: 0; right: 0;
445
+ background: rgba(20,20,20,0.92);
446
+ border-radius: 4px 4px 0 0;
447
+ margin-bottom: 2px;
448
+ opacity: 0; transition: opacity 0.15s;
449
+ pointer-events: none; /* hover-only включаем ниже */
361
450
  }
451
+ /* Footer для label не используется (нет сгенерированной информации) — скрываем. */
452
+ .node.label-node .node-footer { display: none; }
453
+ /* Resize и anchor для label не нужны — текст auto-размером, ссылок нет. */
454
+ .node.label-node .resize-handle,
455
+ .node.label-node .anchor { display: none; }
456
+
457
+ /* Body — wrapper без визуального вклада. */
362
458
  .node.label-node .node-body {
363
459
  padding: 0; background: transparent;
364
- display: flex; flex-direction: column; min-height: 0;
460
+ display: block; min-height: 0;
461
+ position: relative;
365
462
  }
366
463
 
367
- /* Тулбар форматирования label поверх текста, на hover. */
464
+ /* Тулбар форматирования — absolute под текстом, hover-only. */
368
465
  .node.label-node .label-toolbar {
466
+ position: absolute;
467
+ top: 100%; /* под label */
468
+ left: 0;
469
+ margin-top: 4px;
369
470
  display: flex; align-items: center; gap: 4px;
370
471
  padding: 3px 6px; background: rgba(20,20,20,0.92);
371
- border-radius: 4px; margin: 4px;
472
+ border-radius: 4px;
372
473
  font-size: 11px; flex-shrink: 0;
373
- align-self: flex-start;
374
- pointer-events: auto;
474
+ opacity: 0; transition: opacity 0.15s;
475
+ pointer-events: none;
476
+ white-space: nowrap;
477
+ z-index: 10;
478
+ }
479
+ .node.label-node:hover .node-header,
480
+ .node.label-node:hover .label-toolbar,
481
+ .node.label-node:focus-within .node-header,
482
+ .node.label-node:focus-within .label-toolbar {
483
+ opacity: 1; pointer-events: auto;
375
484
  }
376
485
  .node.label-node .label-toolbar select,
377
486
  .node.label-node .label-toolbar button {
@@ -386,32 +495,57 @@
386
495
  }
387
496
  .node.label-node .label-toolbar .tt-italic { font-style: italic; min-width: 22px; }
388
497
 
389
- /* Сам текст. flex:1 занимает оставшееся тело, поэтому drag-area
390
- совпадает с визуальной областью. */
498
+ /* Сам текстauto-ширина по контенту, до max-width. */
391
499
  .node.label-node .label-text {
392
- flex: 1; padding: 8px 12px;
500
+ display: inline-block;
501
+ padding: 4px 8px;
393
502
  color: #eaeaea; line-height: 1.2;
394
503
  word-break: break-word; white-space: pre-wrap;
395
504
  outline: none; cursor: text;
396
505
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
397
506
  text-shadow: 0 1px 2px rgba(0,0,0,0.6);
507
+ min-width: 30px;
508
+ max-width: 100%;
398
509
  }
399
510
  .node.label-node .label-text:empty::before {
400
511
  content: attr(data-placeholder);
401
512
  color: rgba(200,200,200,0.35);
402
513
  }
514
+ /* === Label-шрифты ===
515
+ Все варианты — bundled woff2 (см. assets/fonts/), кириллица поддержана. */
403
516
  .node.label-node .label-text[data-font="handwritten"] {
404
- font-family: 'Caveat', 'Marker Felt', 'Bradley Hand', 'Snell Roundhand', cursive;
517
+ /* Карандашом мягкий рукописный (Caveat). */
518
+ font-family: 'KK Caveat', 'Caveat', 'Marker Felt', cursive;
519
+ line-height: 1.1;
520
+ }
521
+ .node.label-node .label-text[data-font="brush"] {
522
+ /* Скорописью — каллиграфия в русском стиле (Bad Script). */
523
+ font-family: 'KK BadScript', 'Bad Script', 'Snell Roundhand', cursive;
405
524
  }
406
525
  .node.label-node .label-text[data-font="marker"] {
407
- font-family: 'Permanent Marker', 'Chalkduster', 'Marker Felt', 'Comic Sans MS', fantasy;
408
- letter-spacing: 0.02em;
526
+ /* Кистью закруглённый плакатный шрифт (Pacifico). */
527
+ font-family: 'KK Pacifico', 'Pacifico', 'Marker Felt', cursive;
528
+ letter-spacing: 0.01em;
529
+ }
530
+ .node.label-node .label-text[data-font="display"] {
531
+ /* Декор — крупная декоративная подпись (Lobster). */
532
+ font-family: 'KK Lobster', 'Lobster', Georgia, serif;
533
+ }
534
+ .node.label-node .label-text[data-font="elegant"] {
535
+ /* Элегант — выразительный заголовочный serif (Yeseva One). */
536
+ font-family: 'KK YesevaOne', 'Yeseva One', Georgia, serif;
537
+ }
538
+ .node.label-node .label-text[data-font="rounded"] {
539
+ /* Округлый — мягкий sans (Comfortaa). */
540
+ font-family: 'KK Comfortaa', 'Comfortaa', -apple-system, sans-serif;
409
541
  }
410
542
  .node.label-node .label-text[data-font="serif"] {
411
- font-family: Georgia, 'Times New Roman', serif;
543
+ /* С засечками академический serif (PT Serif). */
544
+ font-family: 'KK PTSerif', 'PT Serif', Georgia, serif;
412
545
  }
413
546
  .node.label-node .label-text[data-font="mono"] {
414
- font-family: ui-monospace, 'SF Mono', Menlo, 'Courier New', monospace;
547
+ /* Моноширинный (PT Mono). */
548
+ font-family: 'KK PTMono', 'PT Mono', ui-monospace, Menlo, monospace;
415
549
  }
416
550
  .node.video-node .node-body { padding: 0; overflow: hidden; border-radius: 0 0 8px 8px; }
417
551
  .node.video-node .node-body video { width: 100%; height: auto; max-height: none; background: transparent; border-radius: 0; display: block; }