kingkont 0.7.98 → 0.7.99

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kingkont",
3
- "version": "0.7.98",
3
+ "version": "0.7.99",
4
4
  "description": "KingKont · Chatium — нод-редактор сцен с AI-генерацией (картинки/видео/голос/SFX/музыка/текст)",
5
5
  "main": "main.js",
6
6
  "bin": {
@@ -398,6 +398,20 @@ async function openGenModal(kind) {
398
398
  state.imageAspect = 'source';
399
399
  syncImageAspectActive();
400
400
  }
401
+ // Для video-из-картинки нет 'source' опции (ratios у video свои), но
402
+ // юзер всё равно ожидает сохранения пропорций. Считаем aspect картинки
403
+ // и выбираем ближайший из видео-списка. localStorage НЕ обновляем —
404
+ // это per-open default, не sticky (следующий open без source вернёт
405
+ // последний явный выбор юзера).
406
+ if (kind === 'video'
407
+ && state.sourceRef && state.sourceRef.type === 'image' && state.sourceRef.use) {
408
+ computeSourceMediaAspect(VIDEO_ASPECTS).then(asp => {
409
+ if (asp && state.genKind === 'video') {
410
+ state.videoAspect = asp;
411
+ if (typeof syncVideoOptionsActive === 'function') syncVideoOptionsActive();
412
+ }
413
+ });
414
+ }
401
415
  $('genModal').classList.remove('hidden');
402
416
  setTimeout(() => $('genPrompt').focus(), 50);
403
417
  }
@@ -825,9 +839,32 @@ document.querySelectorAll('#genModal [data-kind]').forEach(b => {
825
839
  });
826
840
  });
827
841
 
842
+ // Списки поддерживаемых aspect-ratio для image vs video — не идентичны,
843
+ // потому что у моделей разные ограничения (image поддерживает 3:2/2:3,
844
+ // video — 21:9 ultra-wide). При выводе video-из-image выбираем ближайший
845
+ // видео-aspect к natural-aspect'у картинки (см. computeSourceMediaAspect).
846
+ const IMAGE_ASPECTS = [
847
+ { name: '1:1', v: 1.0 },
848
+ { name: '16:9', v: 16/9 },
849
+ { name: '9:16', v: 9/16 },
850
+ { name: '3:2', v: 3/2 },
851
+ { name: '2:3', v: 2/3 },
852
+ { name: '4:3', v: 4/3 },
853
+ { name: '3:4', v: 3/4 },
854
+ ];
855
+ const VIDEO_ASPECTS = [
856
+ { name: '1:1', v: 1.0 },
857
+ { name: '16:9', v: 16/9 },
858
+ { name: '9:16', v: 9/16 },
859
+ { name: '4:3', v: 4/3 },
860
+ { name: '3:4', v: 3/4 },
861
+ { name: '21:9', v: 21/9 },
862
+ ];
863
+
828
864
  // Вычислить ближайший поддерживаемый aspect ratio из state.sourceRef.
865
+ // opts — список поддерживаемых семейством (image/video).
829
866
  // Возвращает строку '16:9' / '1:1' / etc, или null если не удалось.
830
- async function computeSourceImageAspect() {
867
+ async function computeSourceMediaAspect(opts = IMAGE_ASPECTS) {
831
868
  if (!state.sourceRef || state.sourceRef.type !== 'image' || !state.sourceRef.file) return null;
832
869
  const handle = state.sourceRef.boardHandle || state.currentBoard?.handle;
833
870
  if (!handle) return null;
@@ -843,24 +880,21 @@ async function computeSourceImageAspect() {
843
880
  img.src = url;
844
881
  });
845
882
  if (!dim.w || !dim.h) return null;
846
- return nearestSupportedAspect(dim.w / dim.h);
883
+ return nearestSupportedAspect(dim.w / dim.h, opts);
847
884
  } catch { return null; }
848
885
  finally { if (url) URL.revokeObjectURL(url); }
849
886
  }
850
887
 
851
- // Из произвольного ratio выбирает ближайший из поддерживаемых genModal'ом.
888
+ // Backward-compat: старое имя computeSourceImageAspect используется в
889
+ // submit-flow image'а. Для image-aspect списка по умолчанию.
890
+ async function computeSourceImageAspect() {
891
+ return computeSourceMediaAspect(IMAGE_ASPECTS);
892
+ }
893
+
894
+ // Из произвольного ratio выбирает ближайший из переданного списка.
852
895
  // Сравнение в логарифмической метрике — справедливо для пропорций
853
896
  // (1.5 ↔ 0.667 равноудалены от 1.0).
854
- function nearestSupportedAspect(ratio) {
855
- const opts = [
856
- { name: '1:1', v: 1.0 },
857
- { name: '16:9', v: 16/9 },
858
- { name: '9:16', v: 9/16 },
859
- { name: '3:2', v: 3/2 },
860
- { name: '2:3', v: 2/3 },
861
- { name: '4:3', v: 4/3 },
862
- { name: '3:4', v: 3/4 },
863
- ];
897
+ function nearestSupportedAspect(ratio, opts = IMAGE_ASPECTS) {
864
898
  let best = opts[0];
865
899
  let bestDiff = Math.abs(Math.log(ratio / best.v));
866
900
  for (const o of opts) {
@@ -678,6 +678,17 @@ async function openGenerateForRef(fromNode, clientX, clientY, forceKind) {
678
678
  state.imageAspect = 'source';
679
679
  syncImageAspectActive();
680
680
  }
681
+ // Video-из-картинки: подбираем ближайший видео-aspect к natural-aspect
682
+ // картинки (см. openGenModal для аналогичной логики).
683
+ if (forceKind === 'video'
684
+ && state.sourceRef && state.sourceRef.type === 'image' && state.sourceRef.use) {
685
+ computeSourceMediaAspect(VIDEO_ASPECTS).then(asp => {
686
+ if (asp && state.genKind === 'video') {
687
+ state.videoAspect = asp;
688
+ if (typeof syncVideoOptionsActive === 'function') syncVideoOptionsActive();
689
+ }
690
+ });
691
+ }
681
692
 
682
693
  closeMentionPopup();
683
694
  $('genModal').classList.remove('hidden');